Merge pull request #10147 from osmandapp/master

update test branch
This commit is contained in:
Hardy 2020-11-07 09:53:06 +01:00 committed by GitHub
commit eb56c19cf1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
124 changed files with 3486 additions and 1802 deletions

View file

@ -77,4 +77,6 @@ public class IndexConstants {
public static final String TEMP_DIR = "temp/";
public static final String ROUTING_PROFILES_DIR = "routing/";
public static final String PLUGINS_DIR = "plugins/";
public static final String VOICE_PROVIDER_SUFFIX = "-tts";
}

View file

@ -106,9 +106,11 @@ public class TspAnt {
// Allocates all memory.
// Adds 1 to edge lengths to ensure no zero length edges.
public TspAnt readGraph(List<LatLon> intermediates, LatLon start, LatLon end) {
boolean keepEndPoint = end != null;
List<LatLon> l = new ArrayList<LatLon>();
l.add(start);
boolean keepEndPoint = end != null;
List<LatLon> l = new ArrayList<LatLon>();
if (start != null) {
l.add(start);
}
l.addAll(intermediates);
if (keepEndPoint) {
l.add(end);

View file

@ -267,4 +267,8 @@
<string name="location_sharing_status">مشاركة: %1$s</string>
<string name="shared_string_enabled">مفعل</string>
<string name="duration_ago">%1$s منذ</string>
<string name="shared_string_export">تصدير</string>
<string name="logcat_buffer">لوجكات العازلة</string>
<string name="logcat_buffer_descr">تحقق من السجلات التفصيلية للتطبيق وشاركها</string>
<string name="send_report">إرسال تقرير</string>
</resources>

View file

@ -78,4 +78,8 @@
<string name="last_response_date">آخرین پاسخ: %1$s</string>
<string name="last_update_from_telegram_date">آخرین به‌روزرسانی تلگرام: %1$s</string>
<string name="shared_string_error_short">خطا</string>
<string name="send_report">ارسال گزارش</string>
<string name="shared_string_export">برون‌برد</string>
<string name="logcat_buffer">بافر لاگ‌کت</string>
<string name="logcat_buffer_descr">لاگ‌های جزئی برنامه را بررسی و هم‌رسانی کنید</string>
</resources>

View file

@ -1,2 +1,211 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>
<resources>
<string name="units_and_formats">Einingar og snið þeirra</string>
<string name="install_osmand">Setja upp OsmAnd</string>
<string name="proxy_password">Lykilorð</string>
<string name="average_altitude">Meðalhæð</string>
<string name="shared_string_hide">Fela</string>
<string name="gps_points_in_buffer">sendi (%1$d í biðminni)</string>
<string name="re_send_location">Endursenda staðsetningu</string>
<string name="searching_for_gps">Staðsetning…</string>
<string name="average_speed">Meðalhraði</string>
<string name="logcat_buffer_descr">Athugaðu og deildu nákvæmum atvikaskrám úr forritinu</string>
<string name="si_mi_meters">Mílur/metrar</string>
<string name="password_descr">Lykilorð í Telegram</string>
<string name="share_location_as">Deila staðsetningu sem</string>
<string name="share_location">Deila staðsetningu</string>
<string name="min_logging_distance_descr">Sía: Stilltu lágmarksfjarlægð frá síðustu staðsetningu þar sem punktur er tekinn í skráningu</string>
<string name="shared_string_back">Til baka</string>
<string name="shared_string_off">Slökkt</string>
<string name="no_internet_connection">Engin internettenging</string>
<string name="set_time">Stilla tíma</string>
<string name="shared_string_accept">Samþykkja</string>
<string name="shared_string_second_short">sek</string>
<string name="minutes_format">%1$d mín</string>
<string name="si_mi_feet">Mílur/fet</string>
<string name="shared_string_bot">Vélmenni</string>
<string name="osmand_privacy_policy">Meðferð persónuupplýsinga í OsmAnd</string>
<string name="sending_location_messages">Sendi staðsetningu</string>
<string name="proxy_type">Tegund milliþjóns (proxy)</string>
<string name="unit_of_length_descr">Breyta einingum sem notaðar eru við lengdarmælingar.</string>
<string name="location_history">Staðsetningaferill</string>
<string name="osmand_logo">Merki OsmAnd</string>
<string name="error_adding_new_device">Gat ekki bætt við nýju tæki</string>
<string name="gps_and_location">Staða</string>
<string name="proxy_settings">Stillingar milliþjóns (proxy)</string>
<string name="proxy_port">Gátt</string>
<string name="by_name">Eftir nafni</string>
<string name="time_zone">Tímabelti</string>
<string name="min_km">mín/km</string>
<string name="m">m</string>
<string name="location_recording_enabled">Skráning staðsetningar virk</string>
<string name="shared_string_connection">Tenging</string>
<string name="si_km_m">Kílómetrar/metrar</string>
<string name="last_update_from_telegram_duration">Síðasta uppfærsla frá Telegram: Fyrir %1$s síðan</string>
<string name="monitoring_is_disabled">Vöktun er óvirk</string>
<string name="status_widget_title">Staða OsmAnd-rekjara</string>
<string name="app_name_short">OsmAnd rekjari</string>
<string name="shared_string_group">Hópur</string>
<string name="min_mile">mín/ml</string>
<string name="proxy_server">Netþjónn</string>
<string name="turn_off_all">Slökkva á öllu</string>
<string name="back_to_osmand">Til baka í OsmAnd</string>
<string name="device_name_is_too_long">Heiti tækis er of langt</string>
<string name="closing">Loka</string>
<string name="hours_and_minutes_format">%1$d klst %2$d mín</string>
<string name="si_min_m">Mínútur á mílu</string>
<string name="shared_string_minute_short">mín</string>
<string name="shared_string_start">Byrja</string>
<string name="shared_string_save">Vista</string>
<string name="map_and_text">Landakort og texti</string>
<string name="shared_string_password">Lykilorð</string>
<string name="device_added_successfully">%1$s bætt við.</string>
<string name="open_in_osmand">Birta í OsmAnd</string>
<string name="last_available_location">Síðasta tiltæka staðsetning</string>
<string name="shared_string_sent">Sent</string>
<string name="authentication_code">Auðkenningarkóði</string>
<string name="search_contacts">Leita í tengiliðum</string>
<string name="open_osmand">Opna OsmAnd</string>
<string name="shared_string_end">Endar</string>
<string name="enter_authentication_code">Settu inn auðkenningarkóða</string>
<string name="my_location">Staðsetning mín</string>
<string name="shared_string_logout">Skrá út</string>
<string name="show_on_map">Birta á korti</string>
<string name="sharing_status">Staða deilingar</string>
<string name="shared_string_cancel">Hætta við</string>
<string name="waiting_for_response_from_telegram">Bíð eftir svari frá Telegram</string>
<string name="successfully_sent_and_updated">Tókst að senda og uppfæra</string>
<string name="shared_string_select">Velja</string>
<string name="si_m_s">Metrar á sekúndu</string>
<string name="device_name">Heiti tækis</string>
<string name="shared_string_welcome">Velkomin</string>
<string name="how_it_works">Hvernig það virkar</string>
<string name="direction">Stefna</string>
<string name="proxy">Milliþjónn</string>
<string name="no_gps_connection">Engin GPS-tenging</string>
<string name="send_location_as">Senda staðsetningu sem</string>
<string name="points_size">%1$d punktar</string>
<string name="yard">yd</string>
<string name="shared_string_disable">Gera óvirkt</string>
<string name="time_on_the_move">Tími á ferðinni</string>
<string name="si_nm_h">Sjómílur á klukkustund (hnútar)</string>
<string name="hours_format">%1$d klst</string>
<string name="proxy_key">Lykill</string>
<string name="background_work">Bakgrunnsvinna</string>
<string name="shared_string_install">Setja upp</string>
<string name="shared_string_add">Bæta við</string>
<string name="shared_string_sort_by">Raða eftir</string>
<string name="last_response_date">Síðasta svar: %1$s</string>
<string name="shared_string_all">Allt</string>
<string name="altitude">Hæð</string>
<string name="show_gps_points">Birta GPS-punkta</string>
<string name="device_name_cannot_be_empty">Heiti tækis getur ekki verið tómt</string>
<string name="shared_string_search">Leita</string>
<string name="by_distance">Eftir vegalengd</string>
<string name="si_nm">Sjómílur</string>
<string name="m_s">m/sek</string>
<string name="not_logged_in">Þú ert ekki skráð/ur inn</string>
<string name="initializing">Ræsing</string>
<string name="min_logging_accuracy">Lágmarksnákvæmni skráningar</string>
<string name="shared_string_close">Loka</string>
<string name="min_logging_speed">Lágmarkshraði skráninga</string>
<string name="process_service">OsmAnd rakningarþjónusta</string>
<string name="shared_string_telegram">Telegram</string>
<string name="gps_network_not_enabled">Kveikja á \"Staðsetning\"\?</string>
<string name="connected_account">Tengdur aðgangur</string>
<string name="mile">mi</string>
<string name="proxy_username">Notandanafn</string>
<string name="shared_string_authorization">Heimild</string>
<string name="unit_of_length">Lengdareiningar</string>
<string name="gpx_settings">GPX-stillingar</string>
<string name="get_telegram_title">Nýskráning í Telegram</string>
<string name="shared_string_distance">Vegalengd</string>
<string name="shared_string_hour_short">klst</string>
<string name="km_h">km/klst</string>
<string name="shared_string_login">Skrá inn</string>
<string name="last_response">Síðasta svar</string>
<string name="start_location_sharing">Deila staðsetningu</string>
<string name="foot">ft</string>
<string name="shared_string_name">Nafn</string>
<string name="duration_ago">%1$s síðan</string>
<string name="location_sharing_description">Veldu notendur eða hópa til að deila með staðsetningu þinni.</string>
<string name="do_not_have_telegram">Ég er ekki með Telegram-aðgang</string>
<string name="monitoring_is_enabled">Vöktun er virk</string>
<string name="expire_at">Rennur út</string>
<string name="privacy">Gagnaleynd</string>
<string name="shared_string_account">Notandaaðgangur</string>
<string name="shared_string_enabled">Virkt</string>
<string name="precision">Nákvæmni</string>
<string name="shared_string_error_short">VILL</string>
<string name="stale_location">Ekki á ferð</string>
<string name="shared_string_continue">Halda áfram</string>
<string name="shared_string_status">Staða</string>
<string name="start_end_date">Upphafs — Endadagsetning</string>
<string name="proxy_disconnected">Aftengt</string>
<string name="nm">sml</string>
<string name="shared_string_update">Uppfæra</string>
<string name="enter_password">Settu inn lykilorð</string>
<string name="shared_string_share">Deila</string>
<string name="logcat_buffer">Logcat biðminni</string>
<string name="enter_phone_number">Settu inn símanúmer</string>
<string name="si_min_km">Mínútur á kílómetra</string>
<string name="shared_string_exit">Hætta</string>
<string name="shared_string_appearance">Útlit</string>
<string name="shared_string_date">Dagsetning</string>
<string name="shared_string_later">Síðar</string>
<string name="bearing">Stefna</string>
<string name="unit_of_speed_system">Hraðaeining</string>
<string name="shared_string_map">Landakort</string>
<string name="min_logging_speed_descr">Sía: Engin skráning punkta fyrir neðan þennan hraða</string>
<string name="in_time">í %1$s</string>
<string name="my_location_search_hint">Leit: Hópur eða tengiliður</string>
<string name="nm_h">hnútar</string>
<string name="km">km</string>
<string name="timeline">Tímalína</string>
<string name="saved_messages">Vistuð skilaboð</string>
<string name="gps_points">GPS-punktar</string>
<string name="shared_string_apply">Virkja</string>
<string name="min_logging_distance">Lágmarksfjarlægð skráninga</string>
<string name="last_update_from_telegram">Síðasta uppfærsla frá Telegram</string>
<string name="shared_string_collected">Safnað</string>
<string name="logging_out">Skrái út</string>
<string name="si_mi_yard">Mílur/yardar</string>
<string name="set_time_timeline_descr">Veldu tíma sem á að birta</string>
<string name="proxy_credentials">Auðkenni</string>
<string name="si_kmh">Kílómetrar á klukkustund</string>
<string name="last_response_duration">Síðasta svar: Fyrir %1$s síðan</string>
<string name="connecting_to_the_internet">Tengist internetinu</string>
<string name="send_report">Senda skýrslu</string>
<string name="shared_string_export">Flytja út</string>
<string name="si_mph">Mílur á klukkustund</string>
<string name="shared_string_ok">Í lagi</string>
<string name="shared_string_enable">Virkja</string>
<string name="telegram_privacy_policy">Persónuverndarstefna Telegram</string>
<string name="active_chats">Virkt spjall</string>
<string name="send_my_location">Senda staðsetningu mína</string>
<string name="shared_string_suggested">Stungið upp á</string>
<string name="go_to_settings">Fara í stillingar</string>
<string name="mile_per_hour">mi/klst</string>
<string name="sharing_in_background">Deiling í bakgrunni</string>
<string name="location_sharing_status">Deiling: %1$s</string>
<string name="last_update_from_telegram_date">Síðasta uppfærsla frá Telegram: %1$s</string>
<string name="initialization">Byrja</string>
<string name="shared_string_sort">Raða</string>
<string name="timeline_no_data">Engin gögn</string>
<string name="by_group">Eftir hópi</string>
<string name="add_device">Bæta við tæki</string>
<string name="shared_string_text">Texti</string>
<string name="shared_string_settings">Stillingar</string>
<string name="show_users_on_map">Birta notendur á kortinu</string>
<string name="proxy_connected">Tengt</string>
<string name="phone_number_title">Símanúmer</string>
<string name="start_date">Upphafsdagsetning</string>
<string name="unit_of_speed_system_descr">Skilgreindu einingu fyrir hraða.</string>
<string name="time_ago">síðan</string>
<string name="enter_code">Settu inn kóða</string>
<string name="disable_monitoring">Gera vöktun óvirka</string>
<string name="no_location_permission">Forritið hefur ekki heimildir til að nota staðsetningargögn.</string>
<string name="end_date">Lokadagsetning</string>
<string name="osmand_service">Bakgrunnshamur</string>
<string name="osmand_service_descr">OsmAnd-rakning keyrir í bakgrunni á meðan slökkt er á skjá.</string>
</resources>

View file

@ -266,4 +266,5 @@
<string name="last_update_from_telegram_date">Ultimo aggiornamento da Telegram: %1$s</string>
<string name="shared_string_error_short">ERR</string>
<string name="logcat_buffer_descr">Controlla e condividi i log dettagliati dell\'applicazione</string>
<string name="logcat_buffer">Logcat buffer</string>
</resources>

View file

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="shared_string_back">Aɣul</string>
<string name="shared_string_share">Bḍu</string>
<string name="enter_phone_number">Ssekcem uṭṭun n utilifun</string>
<string name="shared_string_all">Akk</string>
<string name="shared_string_bot">Abut</string>
<string name="shared_string_live">Usrid</string>
<string name="in_time">g %1$s</string>
<string name="shared_string_account">Amiḍan</string>
<string name="shared_string_close">Rgel</string>
<string name="shared_string_group">Tarabbut</string>
<string name="time_ago">aya</string>
<string name="shared_string_exit">Ffeɣ</string>
<string name="shared_string_sort_by">Fren s</string>
<string name="shared_string_sort">Fren</string>
<string name="by_group">S trabbut</string>
<string name="by_name">S isem</string>
<string name="shared_string_name">Isem</string>
<string name="share_location_as">Bḍu adɣar am</string>
<string name="add_device">Rnu allal</string>
<string name="shared_string_save">Ḥḍu</string>
<string name="shared_string_status">Addad</string>
<string name="go_to_settings">Ddu ɣer tesɣal</string>
<string name="sending_location_messages">Azan n udɣar</string>
<string name="shared_string_hide">Ssentel</string>
<string name="shared_string_add">Rnu</string>
<string name="last_update_from_telegram">Taleqqemt tameggarut seg Tiligṛam</string>
<string name="map_and_text">Takaṛḍa d uḍṛiṣ</string>
<string name="shared_string_text">Aḍṛiṣ</string>
<string name="shared_string_map">Takaṛḍa</string>
<string name="send_location_as">Azen adɣar am</string>
<string name="start_date">Asakud n usenti</string>
<string name="shared_string_date">Asakud</string>
<string name="shared_string_update">Ssedɣi</string>
<string name="shared_string_telegram">Tiligṛam</string>
<string name="shared_string_ok">WAX</string>
<string name="shared_string_search">Rzu</string>
<string name="direction">Tanila</string>
<string name="privacy">Tinnutla</string>
<string name="proxy">Apṛuksi</string>
<string name="proxy_settings">Tisɣal n Upṛuksi</string>
<string name="proxy_connected">Izdey</string>
<string name="proxy_type">Anaw n upṛuksi</string>
<string name="proxy_password">Taguri n uzray</string>
<string name="proxy_key">Tasarut</string>
<string name="gpx_settings">Tisɣal n GPX</string>
<string name="shared_string_select">Stey</string>
<string name="shared_string_start">Ssenti</string>
<string name="back_to_osmand">Aɣul ɣer OsmAnd</string>
<string name="duration_ago">%1$s aya</string>
</resources>

View file

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:icon="@mipmap/icon_free"
android:label="@string/app_name_free"
tools:replace="android:icon">
<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="fb131313131043971"/>
<activity
android:name="net.osmand.plus.activities.MapActivity"
android:theme="@style/FirstSplashScreenCustom"
tools:replace="android:theme"/>
<service
android:name="net.osmand.plus.NavigationService"
android:process="net.osmand.freecustom"
tools:replace="android:process"/>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="net.osmand.freecustom.fileprovider"
tools:replace="android:authorities"/>
</application>
</manifest>

View file

@ -12,6 +12,7 @@
<asset source="voice/cs/cs_tts.js" destination="voice/cs-tts/cs_tts.js" mode="overwriteOnlyIfExists" />
<asset source="voice/da/da_tts.js" destination="voice/da-tts/da_tts.js" mode="overwriteOnlyIfExists" />
<asset source="voice/de/de_tts.js" destination="voice/de-tts/de_tts.js" mode="alwaysOverwriteOrCopy" />
<asset source="voice/de-casual/de-casual_tts.js" destination="voice/de-casual-tts/de-casual_tts.js" mode="overwriteOnlyIfExists" />
<asset source="voice/el/el_tts.js" destination="voice/el-tts/el_tts.js" mode="overwriteOnlyIfExists" />
<asset source="voice/en/en_tts.js" destination="voice/en-tts/en_tts.js" mode="alwaysOverwriteOrCopy" />
<asset source="voice/en-gb/en-gb_tts.js" destination="voice/en-gb-tts/en-gb_tts.js" mode="overwriteOnlyIfExists" />

View file

@ -119,9 +119,6 @@ android {
full {
java.srcDirs = ["src-google"]
}
fulldev {
java.srcDirs = ["src-google"]
}
free {
java.srcDirs = ["src-google"]
manifest.srcFile "AndroidManifest-free.xml"
@ -130,10 +127,6 @@ android {
java.srcDirs = ["src-google"]
manifest.srcFile "AndroidManifest-freedev.xml"
}
freecustom {
java.srcDirs = ["src-google"]
manifest.srcFile "AndroidManifest-freecustom.xml"
}
freehuawei {
java.srcDirs = ["src-huawei"]
manifest.srcFile "AndroidManifest-freehuawei.xml"
@ -188,38 +181,24 @@ android {
dimension "version"
applicationId "net.osmand"
}
freeres {
dimension "version"
applicationId "net.osmand"
resConfig "en"
}
freecustom {
dimension "version"
applicationId "net.osmand.freecustom"
}
full {
dimension "version"
applicationId "net.osmand.plus"
}
fulldev {
dimension "version"
applicationId "net.osmand.plus"
resConfig "en"
// resConfigs "xxhdpi", "nodpi"
}
freehuawei {
dimension "version"
applicationId "net.osmand.huawei"
}
// CoreVersion
// Build that doesn't include 3D OpenGL
legacy {
dimension "coreversion"
}
// Build that includes 3D OpenGL release
qtcore {
dimension "coreversion"
}
// Build that includes 3D OpenGL debug
qtcoredebug {
dimension "coreversion"
}

View file

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M8,9.95C8,13.0979 9.799,16.5395 11.3078,18.9347C11.535,19.2955 11.7687,19.6502 12.0081,20H5V4H10.6499C9.0278,5.4317 8,7.5291 8,9.95Z"
android:strokeAlpha="0.3"
android:fillColor="#727272"
android:fillAlpha="0.3"/>
<path
android:pathData="M10.6499,4H5L5,20H12.0081C12.4759,20.6835 12.9654,21.3479 13.4706,22H5C3.8954,22 3,21.1046 3,20V4C3,2.8954 3.8954,2 5,2H15C15.112,2 15.2218,2.0092 15.3288,2.0269C13.5444,2.1705 11.9161,2.8824 10.6499,4Z"
android:strokeAlpha="0.7"
android:fillColor="#727272"
android:fillAlpha="0.7"/>
<path
android:pathData="M9.6612,16H8C7.4477,16 7,16.4477 7,17C7,17.5523 7.4477,18 8,18H10.7383C10.3718,17.3767 10.0035,16.7041 9.6612,16Z"
android:strokeAlpha="0.7"
android:fillColor="#727272"
android:fillAlpha="0.7"/>
<path
android:pathData="M6,6C6,5.4477 6.4477,5 7,5C7.5523,5 8,5.4477 8,6C8,6.5523 7.5523,7 7,7C6.4477,7 6,6.5523 6,6Z"
android:strokeAlpha="0.5"
android:fillColor="#727272"
android:fillAlpha="0.5"/>
<path
android:pathData="M16,22C16,22 22,15 22,9.95C22,6.55 19.3137,4 16,4C12.6863,4 10,6.55 10,9.95C10,15 16,22 16,22ZM16,12C17.1046,12 18,11.1046 18,10C18,8.8954 17.1046,8 16,8C14.8954,8 14,8.8954 14,10C14,11.1046 14.8954,12 16,12Z"
android:fillColor="#727272"
android:fillType="evenOdd"/>
</vector>

View file

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M5,4H15V20H5V4Z"
android:fillColor="#237BFF"/>
<path
android:pathData="M15,4H5L5,20H15V4ZM5,2C3.8954,2 3,2.8954 3,4V20C3,21.1046 3.8954,22 5,22H15C16.1046,22 17,21.1046 17,20V4C17,2.8954 16.1046,2 15,2H5Z"
android:fillColor="#264573"
android:fillType="evenOdd"/>
<path
android:pathData="M7,18C7,17.4477 7.4477,17 8,17H12C12.5523,17 13,17.4477 13,18C13,18.5523 12.5523,19 12,19H8C7.4477,19 7,18.5523 7,18Z"
android:fillColor="#66A3FF"/>
<path
android:pathData="M6,6C6,5.4477 6.4477,5 7,5C7.5523,5 8,5.4477 8,6C8,6.5523 7.5523,7 7,7C6.4477,7 6,6.5523 6,6Z"
android:fillColor="#002357"/>
<path
android:pathData="M17,5.3265C16.3744,5.1142 15.7013,5 15,5C11.6863,5 9,7.55 9,10.95C9,14.8397 12.441,19.8863 14.0222,22H15C15.4484,22 15.8623,21.8525 16.1958,21.6033C16.4203,21.2762 16.672,20.9017 16.9394,20.4904C16.979,20.3335 17,20.1692 17,20V5.3265Z"
android:strokeAlpha="0.1"
android:fillColor="#000000"
android:fillAlpha="0.1"/>
<path
android:pathData="M22,9.95C22,13.9575 17.1491,20.7132 16.3199,21.8388C16.243,21.9431 16.1239,22 15.9943,22V22C15.8712,22 15.7575,21.9487 15.6805,21.8526C14.8522,20.8194 10,14.569 10,9.95C10,6.55 12.6863,4 16,4C19.3137,4 22,6.55 22,9.95Z"
android:fillColor="#FF8800"/>
<path
android:pathData="M16,10m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"
android:fillColor="#B35F00"/>
</vector>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.material.internal.FlowLayout
android:id="@+id/select_color"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding_small"
android:layout_marginLeft="@dimen/content_padding_small"
android:layout_marginTop="@dimen/context_menu_padding_margin_tiny"
android:layout_marginBottom="@dimen/content_padding_half" />
</LinearLayout>

View file

@ -26,9 +26,9 @@
android:id="@+id/common_graphs_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible"
android:orientation="vertical">
tools:visibility="visible">
<com.github.mikephil.charting.charts.LineChart
android:id="@+id/line_chart"
@ -42,17 +42,22 @@
android:id="@+id/custom_graphs_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible"
android:orientation="vertical">
tools:visibility="visible">
<com.github.mikephil.charting.charts.HorizontalBarChart
android:id="@+id/horizontal_chart"
android:layout_width="match_parent"
android:layout_height="@dimen/route_info_chart_height" />
<LinearLayout
android:id="@+id/route_items"
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/list_divider" />
<FrameLayout
android:id="@+id/route_legend"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
@ -65,48 +70,106 @@
android:id="@+id/message_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding_small"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginBottom="@dimen/content_padding_small"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible"
android:orientation="horizontal">
tools:visibility="visible">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/message_icon"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_gravity="center"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:tint="?attr/default_icon_color"
tools:src="@drawable/ic_action_info_dark" />
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="@dimen/card_button_progress_size"
android:layout_height="@dimen/card_button_progress_size"
android:layout_gravity="center"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:indeterminate="true"
android:visibility="gone" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/message_text"
android:layout_width="0dp"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_weight="1"
android:letterSpacing="@dimen/description_letter_spacing"
android:lineSpacingMultiplier="@dimen/bottom_sheet_text_spacing_multiplier"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_regular"
tools:text="Altitude data available only on the roads, you need to calculate a route using “Route between points” to get it." />
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding_small"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/message_icon"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:tint="?attr/default_icon_color"
tools:src="@drawable/ic_action_info_dark" />
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="@dimen/card_button_progress_size"
android:layout_height="@dimen/card_button_progress_size"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:indeterminate="true"
android:visibility="gone" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/message_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:letterSpacing="@dimen/description_letter_spacing"
android:lineSpacingMultiplier="@dimen/bottom_sheet_text_spacing_multiplier"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_regular"
tools:text="Altitude data available only on the roads, you need to calculate a route using “Route between points” to get it." />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/btn_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/content_padding"
android:background="?attr/selectableItemBackground"
android:orientation="horizontal">
<View
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:visibility="invisible"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:minHeight="@dimen/bottom_sheet_list_item_height"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/divider_color_basic" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/btn_text"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="start|center_vertical"
android:layout_weight="1"
android:gravity="start|center_vertical"
android:lineSpacingMultiplier="@dimen/bottom_sheet_text_spacing_multiplier"
android:textColor="@color/preference_category_title"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="@string/route_between_points" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View file

@ -84,26 +84,11 @@
</ScrollView>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/inapp_descr"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/list_content_padding_large"
android:layout_marginRight="@dimen/list_content_padding_large"
android:layout_marginTop="@dimen/title_padding"
android:gravity="center"
android:text="@string/osm_live_payment_desc"
android:textColor="?attr/card_description_text_color"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_regular"
android:layout_marginStart="@dimen/list_content_padding_large"
android:layout_marginEnd="@dimen/list_content_padding_large" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/card_padding"
android:layout_marginTop="@dimen/card_padding">
android:layout_marginTop="@dimen/title_padding">
<include layout="@layout/purchase_dialog_card_shadow_button"/>

View file

@ -444,9 +444,9 @@
osmand:typeface="@string/font_roboto_medium" />
</LinearLayout>
<net.osmand.plus.widgets.FlowLayout
<LinearLayout
android:id="@+id/select_color"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding_small"
android:layout_marginLeft="@dimen/content_padding_small"

View file

@ -3931,4 +3931,7 @@
<string name="icon_group_sport">رياضة</string>
<string name="icon_group_emergency">الطوارئ</string>
<string name="icon_group_travel">سفر</string>
<string name="navigate_point_mgrs">النظام المرجعي للشبكة العسكرية</string>
<string name="navigate_point_format_mgrs">النظام المرجعي للشبكة العسكرية</string>
<string name="mgrs_format_descr">OsmAnd يستخدم MGRS، وهو مشابه لتنسيق UTM NATO .</string>
</resources>

View file

@ -1710,7 +1710,7 @@
<string name="poi_deleted_localy">POI ще бъдат изтрити, след като качите Вашите промени</string>
<string name="user_hates_app_get_feedback_long">Моля, кажете ни какви промени искате в това приложение.</string>
<string name="we_really_care_about_your_opinion">Вашето мнение е важно за нас.</string>
<string name="use_fast_recalculation_desc">Преизчисляване само началната част от дълги маршрути</string>
<string name="use_fast_recalculation_desc">Преизчисляване само на началото на маршрута. Може да се ползва за дълги маршрути.</string>
<string name="create_poi_link_to_osm_doc"><u>Онлайн OSM</u> класификация на картите с изображения</string>
<string name="free_downloads_used_description">Показва използваните безплатни файлове за изтегляне</string>
<string name="save_track_to_gpx_globally_descr">Записването в GPX може да бъде включвано и изключвано от основния екран</string>
@ -2186,4 +2186,42 @@
<string name="icon_group_sport">Спорт</string>
<string name="icon_group_emergency">Аварийни служби</string>
<string name="icon_group_travel">Пътуване</string>
<string name="clear_osm_token">Изчистете маркера OAuth на OpenStreetMap</string>
<string name="all_previous_segments_will_be_recalc">Всички предишни сегменти ще бъдат преизчислени спрямо избрания профил.</string>
<string name="open_saved_track">Отваряне на записан трак</string>
<string name="shared_string_is_saved">е записан</string>
<string name="one_point_error">Моля, добавете поне две точки.</string>
<string name="shared_string_redo">Повтаряне</string>
<string name="sort_last_modified">Последна промяна</string>
<string name="sort_name_descending">Име: Я - А</string>
<string name="sort_name_ascending">Име: А - Я</string>
<string name="start_finish_icons">Икони за начало/край</string>
<string name="contour_lines_thanks">Благодарим ви, че закупихте \"Контурни линии\"</string>
<string name="osm_live_payment_desc_hw">Абонаментът се таксува за избрания период. Можете да го отмените в AppGallery по всяко време.</string>
<string name="osm_live_payment_subscription_management_hw">Заплащането ще ви бъде приспаднато от вашия акаунт в AppGallery при потвърждаване на покупката.
\n
\nАбонаментът се удължава автоматично, ако не бъде отменен преди датата на подновяване. От вашата сметка се удържат пари само в датата на подновяване.
\n
\nМожете да управлявате или да прекъснете абонаментите си в настройките на AppGallery.</string>
<string name="routing_attr_avoid_footways_description">Избягване на пътеки</string>
<string name="routing_attr_avoid_footways_name">Избягване на пътеки</string>
<string name="development">Разработка</string>
<string name="use_live_public_transport">Данни на OsmAnd Live</string>
<string name="use_live_routing">Данни на OsmAnd Live</string>
<string name="complex_routing_descr">Двустъпково изчисляване на маршрута за автомобилна навигация.</string>
<string name="use_native_pt_desc">Превключете на Java (безопасен режим) изчисляването на маршрути за обществения транспорт</string>
<string name="perform_oauth_authorization_description">Влезте с OAuth, за да ползвате всички функции на osmedit</string>
<string name="perform_oauth_authorization">Вход с OAuth</string>
<string name="system_default_theme">Системна настройка</string>
<string name="all_next_segments">Всички следващи сегменти</string>
<string name="previous_segment">Предишен сегмент</string>
<string name="all_previous_segments">Всички предишни сегменти</string>
<string name="only_selected_segment_recalc">Само избраният сегмент ще бъде преизчислен съобразно избрания профил.</string>
<string name="all_next_segments_will_be_recalc">Всички следващи сегменти ще бъдат преизчислени с помощта на избрания профил.</string>
<string name="plan_route_change_route_type_after">Промяна типа на маршрута след</string>
<string name="simplified_track">Опростена пътека</string>
<string name="simplified_track_description">Само линията на маршрута ще бъде запазена, точките ще бъдат изтрити.</string>
<string name="shared_string_file_name">Име на файл</string>
<string name="number_of_gpx_files_selected_pattern">Избрани файлове за проследяване: %s</string>
<string name="monitoring_control_start">REC</string>
</resources>

View file

@ -184,7 +184,7 @@
<string name="play_commands_of_currently_selected_voice">Seleccioneu una veu i comproveu les seves indicacions:</string>
<string name="zoom_by_trackball_descr">Canvia el zoom del mapa seguint el desplaçament horitzontal del ratolí de bola.</string>
<string name="zoom_by_trackball">Utilitza el ratolí de bola per controlar el zoom</string>
<string name="local_openstreetmap_were_uploaded">Es van pujar {0} PDI/notes</string>
<string name="local_openstreetmap_were_uploaded">S\'han pujat {0} PDI/notes</string>
<string name="local_openstreetmap_settings">PDIs/notes d\'OSM desades al dispositiu</string>
<string name="local_openstreetmap_settings_descr">Mostra i gestiona els PDI/notes d\'OSM de la vostra base de dades local.</string>
<string name="day_night_info">Informació de dia/nit</string>
@ -3859,4 +3859,26 @@ Abasta l\'àrea: %1$s x %2$s</string>
<string name="screen_control">Control de pantalla</string>
<string name="development">Desenvolupament</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="use_native_pt_desc">Canvieu el càlcul de rutes de Transport Public a Java (segur)</string>
<string name="start_finish_icons">Icones d\'Inici/Final</string>
<string name="contour_lines_thanks">Gràcies per comprar \'Corbes de nivell\'</string>
<string name="routing_attr_avoid_footways_description">Evita els camins per a vianants</string>
<string name="routing_attr_avoid_footways_name">Evita els camins per a vianants</string>
<string name="use_live_public_transport">Dades d\'OsmAnd Live</string>
<string name="use_live_routing">Dades d\'OsmAnd Live</string>
<string name="complex_routing_descr">Enrutament en dues fases per navegació amb cotxe.</string>
<string name="perform_oauth_authorization_description">Inicieu la sessió mitjançant OAuth per fer servir les funcionalitats osmedit</string>
<string name="perform_oauth_authorization">Inicieu la sessió via OAuth</string>
<string name="clear_osm_token">Neteja el testimoni OAuth d\'OpenStreetMap</string>
<string name="osm_edit_logout_success">La sessió s\'ha tancat correctament</string>
<string name="file_already_imported">El fitxer ja s\'ha importat a OsmAnd</string>
<string name="shared_string_local_maps">Mapes locals</string>
<string name="icon_group_special">Especial</string>
<string name="icon_group_transport">Transport</string>
<string name="icon_group_service">Servei</string>
<string name="icon_group_symbols">Símbols</string>
<string name="icon_group_sport">Esport</string>
<string name="icon_group_emergency">Emergència</string>
<string name="use_native_pt">Desenvolupament local de Transport Public</string>
<string name="app_mode_gap">Discontinu</string>
</resources>

View file

@ -3849,4 +3849,5 @@
<string name="poi_parking_sheds">Přístřešky</string>
<string name="poi_parking_rooftop">Střešní</string>
<string name="poi_gpx_point">Bod GPX</string>
<string name="poi_radar_tower">Radarová věž</string>
</resources>

View file

@ -3589,4 +3589,69 @@ Zobrazená oblast: %1$s x %2$s</string>
<string name="message_graph_will_be_available_after_recalculation">Počkejte na přepočet trasy.
\nGraf bude dostupný po přepočtu.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="pseudo_mercator_projection">Pseudo-Mercatorovo zobrazení</string>
<string name="one_image_per_tile">Jeden obrazový soubor pro každou dlaždici</string>
<string name="sqlite_db_file">Soubor SQLiteDB</string>
<string name="online_map_name_helper_text">Zadejte název online zdroje.</string>
<string name="online_map_url_helper_text">Zadejte nebo vložte URL online zdroje.</string>
<string name="delete_all_actions_message_q">Opravdu chcete odstranit %d rychlých akcí\?</string>
<string name="screen_timeout">Časový limit obrazovky</string>
<string name="uninstall_speed_cameras">Odinstalovat rychlostní radary</string>
<string name="shared_string_legal">Právní informace</string>
<string name="speed_camera_pois">Body rychlostních radarů</string>
<string name="speed_cameras_legal_descr">V některých zemích nebo regionech je zákonem zakázáno používat aplikace varující před rychlostními radary.
\n
\nMusíte se rozhodnout podle zákonů vaší země.
\n
\nZvolíte-li %1$s, budete dostávat varování před rychlostními radary.
\n
\nZvolíte-li %2$s, všechna data o rychlostních radarech budou odstraněna do té doby, než OsmAnd kompletně přeinstalujete.</string>
<string name="keep_active">Ponechat aktivní</string>
<string name="shared_string_uninstall">Odinstalovat</string>
<string name="speed_cameras_alert">V některých zemích je varování před rychlostními radary zákonem zakázané.</string>
<string name="screen_timeout_descr">Je-li \"%1$s\" zapnuto, čas aktivity bude na tom záviset.</string>
<string name="default_screen_timeout">Výchozí časový limit obrazovky</string>
<string name="shared_string_tones">tuny</string>
<string name="shared_string_meters">metry</string>
<string name="details_dialog_decr">Zobrazit nebo skrýt další detaily na mapě</string>
<string name="shared_string_night_map">Noční mapa</string>
<string name="add_online_source">Přidat online zdroj</string>
<string name="clear_tiles_warning">Použitím těchto změn se vymažou uložené dlaždice pro tento zdroj</string>
<string name="vessel_height_warning_link">Nastavit výšku plavidla</string>
<string name="vessel_height_warning">Můžete nastavit výšku plavidla, aby bylo možné se vyhnout nízkým mostům. Mějte na paměti, že pro pohyblivé mosty se zohledňuje výška v otevřeném stavu.</string>
<string name="track_coloring_solid">Plné</string>
<string name="overwrite_track">Přepsat stopu</string>
<string name="save_as_new_track">Uložit jako novou stopu</string>
<string name="reverse_route">Otočit trasu</string>
<string name="route_between_points_whole_track_button_desc">Celá stopa bude přepočítána pomocí zvoleného profilu.</string>
<string name="route_between_points_next_segment_button_desc">Pouze následující úsek bude přepočítaný pomocí zvoleného profilu.</string>
<string name="route_between_points_desc">Zvolte, jakým způsobem spojit body přímou čarou, nebo výpočtem trasy mezi nimi, viz níže.</string>
<string name="whole_track">Celá stopa</string>
<string name="next_segment">Další úsek</string>
<string name="osm_live_payment_desc_hw">Předplatné bude účtováno za zvolené období. Můžete jej kdykoliv zrušit na AppGallery.</string>
<string name="osm_live_payment_subscription_management_hw">Platba se strhne z vašeho účtu AppGallery po potvrzení nákupu.
\n
\nPředplatné bude automaticky obnoveno, pokud jej před datem obnovení nezrušíte. Platba za další období (měsíc/čtvrtletí/rok) bude stržena pouze v den obnovení.
\n
\nPředplatné můžete spravovat a zrušit v nastavení AppGallery.</string>
<string name="routing_attr_avoid_footways_description">Vyhnout se chodníkům</string>
<string name="routing_attr_avoid_footways_name">Vyhnout se chodníkům</string>
<string name="development">Vývoj</string>
<string name="use_live_public_transport">Údaje OsmAnd Live</string>
<string name="use_live_routing">Údaje OsmAnd Live</string>
<string name="complex_routing_descr">Dvoufázový výpočet trasy pro navigaci auta.</string>
<string name="use_native_pt">Nativní hromadná doprava (ve vývoji)</string>
<string name="use_native_pt_desc">Přepnout na výpočet trasy hromadné dopravy v Javě (bezpečné)</string>
<string name="shared_string_local_maps">Lokální mapy</string>
<string name="icon_group_amenity">Občanská vybavenost</string>
<string name="icon_group_special">Speciální</string>
<string name="icon_group_transport">Doprava</string>
<string name="icon_group_service">Služby</string>
<string name="icon_group_symbols">Symboly</string>
<string name="icon_group_sport">Sport</string>
<string name="icon_group_emergency">Nouzová situace</string>
<string name="icon_group_travel">Cestování</string>
<string name="keep_screen_on">Nechat obrazovku zapnutou</string>
<string name="keep_screen_off">Nechat obrazovku vypnutou</string>
<string name="route_between_points_warning_desc">Dále, pro použití této možnosti připojte vaši stopu k nejbližší povolené cestě s některým z vašich navigačních profilů.</string>
</resources>

View file

@ -3852,4 +3852,5 @@
<string name="poi_parking_sheds">Überdachter Parkplatz</string>
<string name="poi_parking_rooftop">Dachparkplätze</string>
<string name="poi_gpx_point">GPX-Wegpunkt</string>
<string name="poi_radar_tower">Radarturm</string>
</resources>

View file

@ -3937,4 +3937,17 @@
<string name="use_two_phase_routing">2-Phasen-A*-Routing-Algorithmus verwenden</string>
<string name="message_need_calculate_route_before_show_graph">%1$s Daten sind nur auf den Straßen verfügbar, Sie müssen eine Route mit \"Route zwischen Punkten\" berechnen, um sie zu erhalten.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="navigate_point_mgrs">MGRS</string>
<string name="message_graph_will_be_available_after_recalculation">Warte auf die Neuberechnung der Route.
\nDie Graphik wird nach der Neuberechnung verfügbar sein.</string>
<string name="icon_group_amenity">Einrichtung</string>
<string name="icon_group_transport">ÖPNV</string>
<string name="icon_group_service">Dienstleistung</string>
<string name="icon_group_travel">Reisen</string>
<string name="icon_group_sport">Sport</string>
<string name="icon_group_emergency">Notfall</string>
<string name="shared_string_graph">Graph</string>
<string name="icon_group_symbols">Symbole</string>
<string name="shared_string_local_maps">Lokale Karten</string>
<string name="icon_group_special">Spezial</string>
</resources>

View file

@ -3842,4 +3842,5 @@
<string name="poi_parking_sheds">privataj garaĝ-budoj</string>
<string name="poi_parking_rooftop">tegmento</string>
<string name="poi_gpx_point">GPX-punkto</string>
<string name="poi_radar_tower">Radar-turo</string>
</resources>

View file

@ -3934,4 +3934,16 @@
\nDiagramo estos videbla post rekalkulado.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="app_mode_gap">Manko</string>
<string name="shared_string_local_maps">Lokaj mapoj</string>
<string name="icon_group_amenity">Oportunaĵo</string>
<string name="icon_group_special">Specialaj</string>
<string name="icon_group_transport">Transporto</string>
<string name="icon_group_service">Servo</string>
<string name="icon_group_symbols">Simboloj</string>
<string name="icon_group_sport">Sporto</string>
<string name="icon_group_emergency">Vivsavo</string>
<string name="icon_group_travel">Vojaĝo</string>
<string name="navigate_point_mgrs">MGRS</string>
<string name="navigate_point_format_mgrs">MGRS</string>
<string name="mgrs_format_descr">OsmAnd uzas MGRS, kiu estas simila al la formo UTM NATO.</string>
</resources>

View file

@ -3047,7 +3047,7 @@
<string name="poi_cuisine_shawarma">Shawarma;Carne a las brasas en asador horizontal</string>
<string name="poi_waterway_fuel">Estación de combustible náutica;Gasolinera náutica</string>
<string name="poi_feeding_place">Cebadero para animales</string>
<string name="poi_party">Artículos de cotillón;Artículos para fiestas</string>
<string name="poi_party">Artículos para fiestas;Cotillón</string>
<string name="poi_electrical">Artículos de electricidad</string>
<string name="poi_locksmith">Cerrajería</string>
<string name="poi_lighting">Artículos de iluminación</string>
@ -3206,7 +3206,7 @@
<string name="poi_gorge">Cañón (desfiladero)</string>
<string name="poi_couloir">Couloir (barranco estrecho y empinado)</string>
<string name="poi_mountain_area">Área montañosa</string>
<string name="poi_surface_clay">Polvo de ladrillo</string>
<string name="poi_surface_clay">Polvo de ladrillo (arcilla)</string>
<string name="poi_surface_tartan">Tartán</string>
<string name="poi_surface_artificial_turf">Césped artificial</string>
<string name="poi_surface_decoturf">Decoturf (superficie dura para tenis)</string>
@ -3811,7 +3811,7 @@
<string name="poi_tactile_paving_contrasted">Contrastado</string>
<string name="poi_tactile_paving_primitive">Primitivo</string>
<string name="poi_tactile_paving_incorrect">Incorrecto</string>
<string name="poi_internet_access_fee_customers">Señal para encontrar el poste</string>
<string name="poi_internet_access_fee_customers">Conexión a Internet: clientes</string>
<string name="poi_seamark_water_level_part_submerged">Nivel del agua: parcialmente sumergido</string>
<string name="poi_seamark_water_level_submerged">Nivel del agua: sumergido</string>
<string name="poi_seamark_water_level_dry">Nivel de agua: seco</string>
@ -3852,4 +3852,9 @@
<string name="poi_beehive">Panal de abejas</string>
<string name="poi_nuts">Frutos secos</string>
<string name="poi_fuel_lng">Gas natural licuado</string>
<string name="poi_parking_layby">Apartadero</string>
<string name="poi_parking_sheds">Cobertizos</string>
<string name="poi_parking_rooftop">Azotea</string>
<string name="poi_gpx_point">Punto GPX</string>
<string name="poi_radar_tower">Torre de radar</string>
</resources>

View file

@ -3121,7 +3121,7 @@
<string name="shared_string_crash">Error</string>
<string name="last_launch_crashed">OsmAnd falló la última vez. Por favor, ayúdanos a mejorar OsmAnd compartiendo el mensaje de error.</string>
<string name="app_mode_ufo">OVNI</string>
<string name="release_3_4">• Perfiles de aplicación: crea un perfil personalizado según tus necesidades, con un icono y color personalizado
<string name="release_3_4">• Perfiles de aplicación: crea un perfil personalizado según tus necesidades, con un icono y color personalizado.
\n
\n • Ahora puedes personalizar las velocidades predefinidas, máximas y mínimas de cualquier perfil
\n
@ -3133,6 +3133,8 @@
\n
\n • Se mejoraron las descargas de mapas en segundo plano
\n
\n • Se ha vuelto a añadir la opción «Encender pantalla»
\n
\n • Se ha corregido la selección de idioma de Wikipedia
\n
\n • Se ha corregido el comportamiento de los botones de la brújula durante la navegación
@ -3551,7 +3553,7 @@
<string name="saving_new_profile">Guardando el nuevo perfil</string>
<string name="profile_backup_failed">No se pudo respaldar el perfil.</string>
<string name="clear_recorded_data_warning">¿Borrar los datos registrados\?</string>
<string name="importing_from">Importando de datos de «%1$s»</string>
<string name="importing_from">Importando datos de «%1$s»</string>
<string name="shared_string_importing">Importando</string>
<string name="checking_for_duplicate_description">OsmAnd comprueba %1$s para ver si hay duplicados con los elementos existentes en la aplicación.
\n
@ -3829,7 +3831,7 @@
<string name="reverse_route">Ruta inversa</string>
<string name="route_between_points_next_segment_button_desc">Recalcular sólo el siguiente segmento usando el perfil elegido.</string>
<string name="route_between_points_whole_track_button_desc">Recalcular toda la traza usando el perfil elegido.</string>
<string name="route_between_points_desc">Marca cómo conectar los puntos, con una línea recta o calcular una ruta entre ellos como se detalla a continuación.</string>
<string name="route_between_points_desc">Elige cómo conectar los puntos, con una línea recta o calcular una ruta entre ellos como se detalla a continuación.</string>
<string name="whole_track">Traza completa</string>
<string name="next_segment">Siguiente segmento</string>
<string name="route_between_points_warning_desc">A continuación, ajusta la traza al camino permitido más cercano con un perfil de navegación.</string>
@ -3937,4 +3939,16 @@
<string name="message_graph_will_be_available_after_recalculation">Espera el recálculo de la ruta.
\nEl gráfico estará disponible después del recálculo.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="shared_string_local_maps">Mapas locales</string>
<string name="icon_group_amenity">Comodidad</string>
<string name="icon_group_special">Especial</string>
<string name="icon_group_transport">Transporte</string>
<string name="icon_group_service">Servicio</string>
<string name="icon_group_symbols">Símbolos</string>
<string name="icon_group_sport">Deporte</string>
<string name="icon_group_emergency">Emergencia</string>
<string name="icon_group_travel">Viaje</string>
<string name="navigate_point_mgrs">MGRS</string>
<string name="navigate_point_format_mgrs">MGRS</string>
<string name="mgrs_format_descr">OsmAnd usa MGRS, similar al formato UTM de la OTAN.</string>
</resources>

View file

@ -3568,8 +3568,8 @@
<string name="poi_health_specialty_radiotheraphy_yes">Radioterapia</string>
<string name="poi_hazard">Advertencia de peligro</string>
<string name="poi_rtsa_scale_filter">Categoría de dificultad</string>
<string name="poi_rtsa_scale_nc">н/к (sin categoría)</string>
<string name="poi_rtsa_scale_nc_asterisk">н/к* (sin categoría, posible peligro)</string>
<string name="poi_rtsa_scale_nc">s/c (sin categoría)</string>
<string name="poi_rtsa_scale_nc_asterisk">s/c* (sin categoría, posible peligro)</string>
<string name="poi_rtsa_scale_1a">1A</string>
<string name="poi_rtsa_scale_1a_asterisk">1A*</string>
<string name="poi_rtsa_scale_1b">1B</string>
@ -3807,7 +3807,7 @@
<string name="poi_booth">Tipo de cabina</string>
<string name="poi_video_yes"></string>
<string name="poi_video_no">No</string>
<string name="poi_internet_access_fee_customers">Señal para encontrar el poste</string>
<string name="poi_internet_access_fee_customers">Conexión a Internet: clientes</string>
<string name="poi_traffic_signals_sound_locate">Sólo se permite al caminar</string>
<string name="poi_tactile_paving_contrasted">Contrastado</string>
<string name="poi_tactile_paving_primitive">Primitivo</string>
@ -3852,4 +3852,9 @@
<string name="poi_nuts">Frutos secos</string>
<string name="poi_beehive">Panal de abejas</string>
<string name="poi_fuel_lng">Gas natural licuado</string>
<string name="poi_radar_tower">Torre de radar</string>
<string name="poi_parking_sheds">Cobertizos</string>
<string name="poi_parking_rooftop">Azotea</string>
<string name="poi_parking_layby">Apartadero</string>
<string name="poi_gpx_point">Punto GPX</string>
</resources>

View file

@ -3551,14 +3551,14 @@
<string name="saving_new_profile">Guardando el nuevo perfil</string>
<string name="profile_backup_failed">No se pudo respaldar el perfil.</string>
<string name="clear_recorded_data_warning">¿Borrar los datos registrados\?</string>
<string name="importing_from">Importación de datos de %1$s</string>
<string name="shared_string_importing">Importación</string>
<string name="importing_from">Importando datos de «%1$s»</string>
<string name="shared_string_importing">Importando</string>
<string name="checking_for_duplicate_description">OsmAnd comprueba %1$s para ver si hay duplicados con los elementos existentes en la aplicación.
\n
\nPuede llevar algún tiempo.</string>
<string name="items_added">Elementos añadidos</string>
<string name="shared_string_import_complete">Importación completa</string>
<string name="import_complete_description">Todos los datos de %1$s son importados, puedes usar los botones de abajo para abrir la parte necesaria de la aplicación para manejarla.</string>
<string name="import_complete_description">Todos los datos de «%1$s» fueron importados. Puedes usar los botones de abajo para gestionar la sección necesaria de la aplicación.</string>
<string name="shared_string_terrain">Terreno</string>
<string name="hillshade_description">Mapa de sombreado usando sombras oscuras para mostrar las laderas, picos y tierras bajas.</string>
<string name="slope_description">La pendiente utiliza colores para visualizar la inclinación del terreno.</string>
@ -3838,7 +3838,7 @@
<string name="route_between_points_whole_track_button_desc">Recalcular toda la traza usando el perfil elegido.</string>
<string name="route_between_points_warning_desc">A continuación, ajusta la traza al camino permitido más cercano con un perfil de navegación.</string>
<string name="route_between_points_next_segment_button_desc">Recalcular sólo el siguiente segmento usando el perfil elegido.</string>
<string name="route_between_points_desc">Marca cómo conectar los puntos, con una línea recta o calcular una ruta entre ellos como se detalla a continuación.</string>
<string name="route_between_points_desc">Elige cómo conectar los puntos, con una línea recta o calcular una ruta entre ellos como se detalla a continuación.</string>
<string name="route_between_points_add_track_desc">Elige un archivo de traza al que se añadirá un nuevo segmento.</string>
<string name="reverse_route">Ruta inversa</string>
<string name="quick_action_add_gpx">Añadir punto de referencia de la traza</string>
@ -3926,4 +3926,24 @@
<string name="development">Desarrollo</string>
<string name="complex_routing_descr">Navegación bifásica en automóvil.</string>
<string name="clear_osm_token">Vaciar llave OAuth de OpenStreetMap</string>
<string name="use_two_phase_routing">Usar el algoritmo de navegación A* bifásica</string>
<string name="snowmobile_render_descr">Para caminos y senderos exclusivos de motos de nieve.</string>
<string name="shared_string_local_maps">Mapas locales</string>
<string name="shared_string_graph">Gráfico</string>
<string name="navigate_point_mgrs">MGRS</string>
<string name="navigate_point_format_mgrs">MGRS</string>
<string name="mgrs_format_descr">OsmAnd usa MGRS, similar al formato UTM de la OTAN.</string>
<string name="message_need_calculate_route_before_show_graph">%1$s datos disponibles sólo en los caminos, necesitas calcular una ruta usando «Ruta entre puntos» para obtenerla.</string>
<string name="message_graph_will_be_available_after_recalculation">Espera el recálculo de la ruta.
\nEl gráfico estará disponible después del recálculo.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="icon_group_travel">Viaje</string>
<string name="icon_group_transport">Transporte</string>
<string name="icon_group_symbols">Símbolos</string>
<string name="icon_group_sport">Deporte</string>
<string name="icon_group_special">Especial</string>
<string name="icon_group_service">Servicio</string>
<string name="icon_group_emergency">Emergencia</string>
<string name="icon_group_amenity">Comodidad</string>
<string name="file_already_imported">El archivo ya fue importado en OsmAnd</string>
</resources>

View file

@ -1868,7 +1868,7 @@
<string name="poi_fuel_100ll">100LL (con plomo, para aviones)</string>
<string name="poi_fuel_autogas">Autogas (Etanol libre de plomo)</string>
<string name="poi_fuel_jeta1">Jet A-1 (diésel)</string>
<string name="poi_fuel_adblue">Líquido de escape de diesel</string>
<string name="poi_fuel_adblue">Aditivo para escapes de Diesel (AdBlue)</string>
<string name="poi_fuel_wood">Combustible: madera</string>
<string name="poi_fuel_charcoal">Combustible: carbón vegetal</string>
<string name="poi_fuel_coal">Combustible: carbón</string>
@ -3562,8 +3562,8 @@
<string name="poi_health_specialty_radiotheraphy_yes">Radioterapia</string>
<string name="poi_hazard">Advertencia de peligro</string>
<string name="poi_rtsa_scale_filter">Categoría de dificultad</string>
<string name="poi_rtsa_scale_nc">н/к (sin categoría)</string>
<string name="poi_rtsa_scale_nc_asterisk">н/к* (sin categoría, posible peligro)</string>
<string name="poi_rtsa_scale_nc">s/c (sin categoría)</string>
<string name="poi_rtsa_scale_nc_asterisk">s/c* (sin categoría, posible peligro)</string>
<string name="poi_rtsa_scale_1a">1А</string>
<string name="poi_rtsa_scale_1a_asterisk">1А*</string>
<string name="poi_rtsa_scale_1b">1B</string>
@ -3808,7 +3808,7 @@
<string name="poi_seamark_water_level_part_submerged">Nivel de agua: parcialmente sumergido</string>
<string name="poi_tactile_paving_incorrect">Incorrecto</string>
<string name="poi_traffic_signals_sound_locate">Sólo se permite al caminar</string>
<string name="poi_internet_access_fee_customers">Señal para encontrar el poste</string>
<string name="poi_internet_access_fee_customers">Acceso a Internet: clientes</string>
<string name="poi_booth">Tipo de cabina</string>
<string name="poi_covered_booth">Cabina</string>
<string name="poi_dive_centre">Centro de buceo</string>
@ -3845,4 +3845,10 @@
<string name="poi_recycling_small_electrical_appliances">Pequeños electrodomésticos</string>
<string name="poi_departures_board">Tablero de salidas</string>
<string name="poi_drinking_water_refill">Relleno de agua potable</string>
<string name="poi_radar_tower">Torre de radar</string>
<string name="poi_parking_layby">Apartadero</string>
<string name="poi_parking_sheds">Cobertizos</string>
<string name="poi_parking_rooftop">Azotea</string>
<string name="poi_gpx_point">Punto GPX</string>
<string name="poi_fuel_lng">Gas natural licuado</string>
</resources>

View file

@ -609,18 +609,18 @@
<string name="map_online_data_descr">Usa mapas en línea (descarga y guarda teselas en la tarjeta de memoria).</string>
<string name="shared_string_online_maps">Mapas en línea</string>
<string name="online_map_settings_descr">Elige las fuentes de teselas de mapas en línea o en caché.</string>
<string name="osmand_rastermaps_plugin_description">"Accede a muchos tipos de mapas en línea (llamados teselas o ráster), desde teselas predefinidas de OpenStreetMap (como Mapnik) a imágenes satelitales y capas de propósito especial como mapas meteorológicos, mapas del clima, mapas geológicos, capas de sombreado, etc.
<string name="osmand_rastermaps_plugin_description">Accede a muchos tipos de mapas en línea (llamados teselas o ráster), desde teselas predefinidas de OpenStreetMap (como Mapnik) a imágenes satelitales y capas de propósito especial como mapas meteorológicos, mapas del clima, mapas geológicos, capas de sombreado, etc.
\n
\nCualquiera de estos mapas puede mostrarse como el mapa (base) principal, o como una superposición o subyacencia de otro mapa base (como los mapas estándar de OsmAnd sin conexión). Ciertos elementos de los mapas vectoriales OsmAnd se pueden ocultar a través del menú «Configurar mapa» para hacer más visible cualquier mapa subyacente.
\n
\nDescarga los mapas de teselas directamente a través de fuentes en línea, o prepararlos para tu uso sin conexión (copiándolos manualmente en la carpeta de datos OsmAnd) como una base de datos SQLite que puede generarse con varias herramientas de preparación de mapas de terceros."</string>
\nDescarga los mapas de teselas directamente a través de fuentes en línea, o prepararlos para tu uso sin conexión (copiándolos manualmente en la carpeta de datos OsmAnd) como una base de datos SQLite que puede generarse con varias herramientas de preparación de mapas de terceros.</string>
<string name="osmand_background_plugin_description">Muestra los ajustes para activar en modo reposo el seguimiento y la navegación, activando periódicamente el dispositivo GPS (con la pantalla apagada).</string>
<string name="osmand_accessibility_description">Activa las funciones de accesibilidad del dispositivo directamente en OsmAnd. Facilita por ejemplo, el ajuste de la velocidad de la voz para voces de texto a voz, la configuración de navegación de pantalla con el panel direccional, usando la rueda de desplazamiento para el control del zoom, o la retroalimentación de texto a voz, por ejemplo, para anunciar la ubicación automáticamente.</string>
<string name="osmand_development_plugin_description">Este complemento muestra los ajustes de funciones de desarrollo y depuración para probar la simulación de rutas, el rendimiento del renderizado, o las indicaciones por voz. Estos ajustes están destinados para los desarrolladores y no son necesarios para el usuario general.</string>
<string name="plugins_screen">Complementos</string>
<string name="prefs_plugins_descr">Los complementos activan ajustes avanzados y funcionalidades adicionales.</string>
<string name="prefs_plugins">Complementos</string>
<string name="osm_editing_plugin_description">Este complemento puede usarse para hacer contribuciones en OSM, como el crear o modificar objetos PDI, abrir o comentar notas de OSM y contribuir con archivos de trazas GPX. OSM es un proyecto de mapeo global impulsado por la comunidad y de dominio público. Para más detalles, consulta https://openstreetmap.org. Se aprecia la participación activa, y las contribuciones pueden hacerse directamente desde OsmAnd, especificando las credenciales personales de OSM en la aplicación.</string>
<string name="osm_editing_plugin_description">Haz contribuciones en OSM, como el crear o modificar objetos PDI, abrir o comentar notas de OSM y contribuir con archivos de trazas GPX grabados en OsmAnd, proporcionando tu nombre de usuario y contraseña. OpenStreetMap.org es un proyecto de mapeo de dominio público, global, libre e impulsado por la comunidad.</string>
<string name="vector_maps_may_display_faster_on_some_devices">Los mapas vectoriales pueden mostrarse más rápido. Puede no funcionar correctamente en algunos dispositivos.</string>
<string name="play_commands_of_currently_selected_voice">Elige una voz y reproduce pruebas de los avisos:</string>
<string name="debugging_and_development">Desarrollo de OsmAnd</string>
@ -890,7 +890,7 @@
<string name="audionotes_plugin_description">Tomar notas de audio/foto/video durante un viaje, usando un botón de mapa o un menú contextual de la ubicación.</string>
<string name="audionotes_plugin_name">Notas audio/vídeo</string>
<string name="osmand_srtm_short_description_80_chars">Complemento OsmAnd para curvas de nivel sin conexión</string>
<string name="osmand_srtm_long_description_1000_chars">Este complemento proporciona una capa superpuesta de curvas de nivel y una capa (de relieve) sombreada, que se pueden visualizar sobre los mapas descargados de OsmAnd. Esta funcionalidad será muy apreciada por atletas, caminantes, excursionistas, y cualquiera interesado en la estructura de relieve de un paisaje.
<string name="osmand_srtm_long_description_1000_chars">Proporciona una capa superpuesta de curvas de nivel y una capa (de relieve) sombreada, que se pueden visualizar sobre los mapas descargados de OsmAnd. Esta funcionalidad será muy apreciada por atletas, caminantes, excursionistas, y cualquiera interesado en la estructura de relieve de un paisaje.
\n
\nLos datos globales (entre 70° norte y 70° sur) se basan en mediciones de SRTM (Shuttle Radar Topography Mission, o en español Misión de Topografía por Radar desde Transbordador) y ASTER (Advanced Spaceborne Thermal Emission and Reflection Radiometer, o en español Radiómetro Espacial Avanzado de Emisión Térmica y Reflexión), un instrumento de captura de imágenes a bordo de Terra, el satélite insignia del Sistema de Observación de la Tierra de la NASA. ASTER es un esfuerzo cooperativo entre la NASA, el Ministerio de Economía, Comercio e Industria de Japón (METI) y Sistemas Espaciales de Japón (J-spacesystems).</string>
<string name="map_widget_distancemeasurement">Medición de distancia</string>
@ -3026,6 +3026,8 @@
\n
\n • Se mejoraron las descargas de mapas en segundo plano
\n
\n • Se ha vuelto a añadir la opción «Encender pantalla»
\n
\n • Se ha corregido la selección de idioma de Wikipedia
\n
\n • Se ha corregido el comportamiento de los botones de la brújula durante la navegación
@ -3840,7 +3842,7 @@
<string name="reverse_route">Ruta inversa</string>
<string name="route_between_points_whole_track_button_desc">La traza completa será recalculada utilizando el perfil seleccionado.</string>
<string name="route_between_points_next_segment_button_desc">Sólo el siguiente segmento será recalculado usando el perfil seleccionado.</string>
<string name="route_between_points_desc">Selecciona cómo conectar puntos, con línea recta, o calcula una ruta entre ellos como se especifica a continuación.</string>
<string name="route_between_points_desc">Elija cómo conectar los puntos, en línea recta o calcular una ruta entre ellos como se especifica a continuación.</string>
<string name="whole_track">Traza completa</string>
<string name="next_segment">Siguiente segmento</string>
<string name="route_between_points_warning_desc">A continuación, ajusta tu traza a la carretera permitida más cercana con uno de tus perfiles de navegación para usar esta opción.</string>

View file

@ -3831,4 +3831,5 @@
<string name="poi_parking_layby">Parkla kiirtee ääres</string>
<string name="poi_parking_sheds">Parkimine varjualustes</string>
<string name="poi_parking_rooftop">Parkla katusel</string>
<string name="poi_radar_tower">Radarimast</string>
</resources>

View file

@ -3795,4 +3795,7 @@
<string name="icon_group_symbols">Sümbolid</string>
<string name="icon_group_service">Teenused</string>
<string name="icon_group_transport">Transport</string>
<string name="mgrs_format_descr">OsmAnd kasutab MGRS-vormingut, mis on sarnane NATO UTM-vormingule.</string>
<string name="navigate_point_format_mgrs">MGRS</string>
<string name="navigate_point_mgrs">MGRS</string>
</resources>

View file

@ -226,14 +226,14 @@
<string name="poi_pension_fund">صندوق بازنشستگی</string>
<string name="poi_migration">سازمان مهاجرت</string>
<string name="poi_tax_inspection">اداره مالیات</string>
<string name="poi_office_administrative">دفتر اجرایی</string>
<string name="poi_office_administrative">اداره حکومتی</string>
<string name="poi_customs">گمرک</string>
<string name="poi_city">شهر</string>
<string name="poi_town">شهر</string>
<string name="poi_village">روستا</string>
<string name="poi_hamlet">دهکده</string>
<string name="poi_isolated_dwelling">سکونتگاه دورافتاده</string>
<string name="poi_suburb">حومه شهر</string>
<string name="poi_suburb">منطقه شهری</string>
<string name="poi_neighbourhood">محله</string>
<string name="poi_locality">محل</string>
<string name="poi_place_allotments"/>
@ -346,7 +346,7 @@
<string name="poi_artwork">اثر هنری</string>
<string name="poi_archaeological_site">مرکز باستان شناسی</string>
<string name="poi_battlefield">میدان جنگ</string>
<string name="poi_boundary_stone">سنگ یادبود</string>
<string name="poi_boundary_stone">سنگ مرز</string>
<string name="poi_historic_cannon">توپ تاریخی</string>
<string name="poi_castle">قلعه</string>
<string name="poi_city_gate">دروازه شهر</string>
@ -1452,4 +1452,5 @@
<string name="poi_access_bus">دسترسی اتوبوس</string>
<string name="poi_climbing_crag">بله</string>
<string name="poi_protected_area">منطقهٔ حفاظت‌شده</string>
<string name="poi_badminton">بدمینتون</string>
</resources>

View file

@ -3482,7 +3482,7 @@
<string name="tracks_view_descr">ردهای ضبط‌شدهٔ شما در %1$s یا در پوشهٔ OsmAnd قرار دارند.</string>
<string name="multimedia_notes_view_descr">یادداشت‌های OSMای شما در %1$s قرار دارند.</string>
<string name="osm_edits_view_descr">ویرایش‌ها یا یادداشت‌های OSMای خود که هنوز بارگذاری نشده‌اند را در %1$s ببینید. نقاط بارگذاری‌شده را دیگر نمی‌بینید.</string>
<string name="logcat_buffer_descr">لاگ‌های جزئی برنامه را ببینید و هم‌رسانی کنید</string>
<string name="logcat_buffer_descr">لاگ‌های جزئی برنامه را بررسی و هم‌رسانی کنید</string>
<string name="multimedia_use_system_camera">استفاده از برنامهٔ سیستم</string>
<string name="multimedia_photo_play_sound">صدای شاتر دوربین</string>
<string name="osm_authorization_success">احراز هویت موفقیت‌آمیز بود</string>
@ -3631,7 +3631,7 @@
<string name="shared_string_all_languages">همهٔ زبان‌ها</string>
<string name="ui_customization_description">تعداد اقلام «کشو»، «پیکربندی نقشه» و «منوی زمینه» را به‌دلخواه تنظیم کنید.
\n
\nافزونههای بی‌استفاده را غیرفعال کنید تا همهٔ کنترل‌های آن‌ها از برنامه پنهان شود.</string>
\nافزونههای بی‌استفاده را غیرفعال کنید تا همهٔ کنترل‌های آن‌ها از برنامه پنهان شود. %1$s.</string>
<string name="reset_items_descr">پنهان‌سازی تنظیمات آن‌ها را به حالت اولیه بازنشانی می‌کند.</string>
<string name="hidden_items_descr">این اقلام از منو پنهان می‌شوند، اما گزینه‌ها یا افزونه‌های متناظر همچنان کار می‌کنند.</string>
<string name="shared_string_hidden">پنهان</string>
@ -3942,4 +3942,12 @@
<string name="complex_routing_descr">مسیریابی دومرحله‌ای برای ناوبری خودرویی.</string>
<string name="use_complex_routing">مسیریابی پیچیده</string>
<string name="use_native_pt_desc">برای مسیریابی حمل‌ونقل عمومی از محاسبات جاوا (امن) استفاده می‌کند</string>
<string name="shared_string_local_maps">نقشه‌های محلی</string>
<string name="icon_group_special">ویژه</string>
<string name="icon_group_transport">حمل‌ونقل</string>
<string name="icon_group_service">خدمات</string>
<string name="icon_group_symbols">نمادها</string>
<string name="icon_group_sport">ورزش</string>
<string name="icon_group_emergency">اورژانس</string>
<string name="icon_group_travel">سفر</string>
</resources>

View file

@ -3923,4 +3923,7 @@
<string name="icon_group_sport">Sport</string>
<string name="icon_group_emergency">Urgence</string>
<string name="icon_group_travel">Voyage</string>
<string name="mgrs_format_descr">OsmAnd utilise le système de référence MDRS de l\'OTAN dérivé des formats UTM et UPS.</string>
<string name="navigate_point_format_mgrs">MGRS</string>
<string name="navigate_point_mgrs">MGRS</string>
</resources>

View file

@ -72,14 +72,14 @@
<string name="poi_motorcycle_parking">Aparcadoiro de motos</string>
<string name="poi_parking_entrance">Entrada de aparcadoiro</string>
<string name="poi_garages">Garaxes</string>
<string name="poi_public_transport_platform">Paraxe de transporte público</string>
<string name="poi_public_transport_platform_bus">Paraxe de bus</string>
<string name="poi_public_transport_platform_trolleybus">Paraxe de trolebus</string>
<string name="poi_public_transport_platform_tram">Paraxe do tranvía</string>
<string name="poi_public_transport_platform">Parada de transporte público</string>
<string name="poi_public_transport_platform_bus">Parada de bus</string>
<string name="poi_public_transport_platform_trolleybus">Parada de trolebus</string>
<string name="poi_public_transport_platform_tram">Parada de tranvía</string>
<string name="poi_public_transport_station">Estación de transporte público</string>
<string name="poi_subway_entrance">Entrada de metro</string>
<string name="poi_subway_station">Si</string>
<string name="poi_taxi">Paraxe de taxis</string>
<string name="poi_taxi">Parada de taxis</string>
<string name="poi_aerodrome">Aeroporto</string>
<string name="poi_helipad">Heliporto</string>
<string name="poi_lighthouse">Faro</string>
@ -428,8 +428,8 @@
<string name="poi_fuel_methanol">Metanol</string>
<string name="poi_fuel_lh2">Hidróxeno líquido</string>
<string name="poi_fuel_electricity">Electricidade</string>
<string name="poi_bus_stop">Paraxe de bus</string>
<string name="poi_tram_stop">Paraxe do tranvía</string>
<string name="poi_bus_stop">Parada de bus</string>
<string name="poi_tram_stop">Parada de tranvía</string>
<string name="poi_bus_station">Estación de autobuses</string>
<string name="poi_railway_station">Estación de trens</string>
<string name="poi_ferry_terminal">Terminal dos ferris</string>
@ -1352,7 +1352,7 @@
<string name="poi_payment_ov_chipkaart_yes">OV-Chipkaart</string>
<string name="poi_cafeteria">Cafetaría</string>
<string name="poi_zoo_type">Tipo</string>
<string name="poi_public_transport_stop_position">Punto de paraxe do transporte público</string>
<string name="poi_public_transport_stop_position">Lugar de parada de transporte público</string>
<string name="poi_survey_point">Vértice xeodésico</string>
<string name="poi_social_facility">Instalación social</string>
<string name="poi_tax_advisor">Asesoramento fiscal</string>
@ -1403,7 +1403,7 @@
<string name="poi_glacier_type">Tipo de glaciar</string>
<string name="poi_checkpoint_type">Tipo de posto de control</string>
<string name="poi_convenience">Tenda de ultramarinos</string>
<string name="poi_halt">Paraxe de trens</string>
<string name="poi_halt">Parada de tren</string>
<string name="poi_railway_buffer_stop">Fin da vía</string>
<string name="poi_food_court">Estabelecemento de comidas</string>
<string name="poi_buoy_installation">Boia de instalación</string>
@ -3554,18 +3554,18 @@
<string name="poi_rtsa_scale_filter">Categoría da dificultade</string>
<string name="poi_health_specialty_radiotheraphy_yes">Radioterapia</string>
<string name="poi_hazard">Perigo</string>
<string name="poi_rtsa_scale_nc">н/к</string>
<string name="poi_rtsa_scale_nc_asterisk">н/к*</string>
<string name="poi_rtsa_scale_1a">1А</string>
<string name="poi_rtsa_scale_1a_asterisk">1А*</string>
<string name="poi_rtsa_scale_nc">n/c</string>
<string name="poi_rtsa_scale_nc_asterisk">n/c*</string>
<string name="poi_rtsa_scale_1a">1A</string>
<string name="poi_rtsa_scale_1a_asterisk">1A*</string>
<string name="poi_rtsa_scale_1b">1B</string>
<string name="poi_rtsa_scale_1b_asterisk">1B*</string>
<string name="poi_rtsa_scale_2a">2А</string>
<string name="poi_rtsa_scale_2a_asterisk">2А*</string>
<string name="poi_rtsa_scale_2a">2A</string>
<string name="poi_rtsa_scale_2a_asterisk">2A*</string>
<string name="poi_rtsa_scale_2b">2B</string>
<string name="poi_rtsa_scale_2b_asterisk">2B*</string>
<string name="poi_rtsa_scale_3a">3А</string>
<string name="poi_rtsa_scale_3a_asterisk">3А*</string>
<string name="poi_rtsa_scale_3a">3A</string>
<string name="poi_rtsa_scale_3a_asterisk">3A*</string>
<string name="poi_rtsa_scale_3b">3B</string>
<string name="poi_rtsa_scale_3b_asterisk">3B*</string>
<string name="poi_flare">Chama de gas;Queimadura de facho</string>
@ -3793,7 +3793,7 @@
<string name="poi_booth">Tipo de cabina</string>
<string name="poi_video_yes">Si</string>
<string name="poi_video_no">Non</string>
<string name="poi_internet_access_fee_customers">Sinal para atopar o poste</string>
<string name="poi_internet_access_fee_customers">Acceso á internet: clientes</string>
<string name="poi_traffic_signals_sound_locate">Só é permitido ó camiñar</string>
<string name="poi_tactile_paving_contrasted">Contrastado</string>
<string name="poi_tactile_paving_primitive">Primitivo</string>
@ -3838,4 +3838,8 @@
<string name="poi_departures_board">Taboleiro de saídas</string>
<string name="poi_drinking_water_refill">Recarga de auga potábel</string>
<string name="poi_fuel_lng">GNL</string>
<string name="poi_parking_layby">Apartadoiro</string>
<string name="poi_parking_sheds">Pendellos</string>
<string name="poi_parking_rooftop">Terrazo</string>
<string name="poi_gpx_point">Punto GPX</string>
</resources>

View file

@ -508,7 +508,7 @@
\n - Funcionalidade completa sen conexión (os mapas vectoriais ou de teselas baixados almacénanse no cartafol que se escolla)
\n - Mapas vectoriais compactos sen conexión para todo o mundo
\n - Pódense baixar mapas de países ou rexións de xeito directo dende a aplicación
\n - É posíbel sobrepor varias capas de mapas, coma pistas de GPX ou de navegación, puntos de interese (PDI), favoritos, curvas do nivel, paraxes de transporte público ou mapas adicionais con transparencia regulábel
\n - É posíbel sobrepor varias capas de mapas, coma pistas de GPX ou de navegación, puntos de interese (PDI), favoritos, curvas do nivel, paradas de transporte público ou mapas adicionais con transparencia regulábel
\n - Procura sen conexión dos enderezos e lugares (PDI)
\n - Cálculo de rotas sen conexión para distancias medias
\n - Modos para automóbil, bicicleta e peóns, opcionalmente con:
@ -532,7 +532,7 @@
\n-Funcionalidade completa sen conexión (os mapas vectoriais ou de teselas baixados almacénanse no cartafol que se escolleu)
\n-Mapas vectoriais compactos sen conexión para todo o mundo.
\n-Pódense baixar mapas de países ou rexións de xeito directo dende a aplicación.
\n-É posíbel sobrepór varias capas de mapas, coma pistas de GPX ou de navegación, puntos de interese (PDI), favoritos, curvas do nivel, paraxes de transporte público ou mapas adicionais con transparencia regulábel.
\n-É posíbel sobrepór varias capas de mapas, coma pistas de GPX ou de navegación, puntos de interese (PDI), favoritos, curvas do nivel, paradas de transporte público ou mapas adicionais con transparencia regulábel.
\n
\n- Procura sen conexión de enderezos e lugares (PDI).
\n-Cálculo de rotas sen conexión para distancias curtas (distancias medias)
@ -1043,7 +1043,7 @@
<string name="gpx_files_not_found">Non foi posíbel atopar ficheiros GPX no cartafol de pistas</string>
<string name="error_reading_gpx">Non foi posíbel ler os datos do GPX.</string>
<string name="vector_data">Mapas vectoriais sen conexión</string>
<string name="transport_context_menu">Procurar transporte na paraxe</string>
<string name="transport_context_menu">Procurar transporte na parada</string>
<string name="poi_context_menu_modify">Modificar o PDI</string>
<string name="poi_context_menu_delete">Eliminar PDI</string>
<string name="rotate_map_compass_opt">Dirección do compás</string>
@ -1126,19 +1126,19 @@
<string name="add_new_rule">Engadir unha regra nova</string>
<string name="transport_Routes">Liñas</string>
<string name="transport_Stop">Stop</string>
<string name="transport_stops">paraxes</string>
<string name="transport_stops">paradas</string>
<string name="transport_search_after">Itinerario posterior</string>
<string name="transport_search_before">Itinerario anterior</string>
<string name="transport_finish_search">Rematar a procura</string>
<string name="transport_stop_to_go_out">Escolle a paraxe na que baixar</string>
<string name="transport_stop_to_go_out">Escolle a parada na que baixar</string>
<string name="transport_to_go_after">distancia anterior</string>
<string name="transport_to_go_before">distancia posterior</string>
<string name="transport_stops_to_pass">paraxes a pasar</string>
<string name="transport_stops_to_pass">paradas a pasar</string>
<string name="transport_route_distance">Distancia do itinerario</string>
<string name="transport">Transporte</string>
<string name="shared_string_ok">Feito</string>
<string name="show_transport_over_map_description">Amosar paraxes do transporte público no mapa.</string>
<string name="show_transport_over_map">Amosar paraxes do transporte</string>
<string name="show_transport_over_map_description">Amosar paradas de transporte público no mapa.</string>
<string name="show_transport_over_map">Amosar paradas de transporte</string>
<string name="hello">OsmAnd, aplicación de navegación</string>
<string name="update_poi_success">Os datos do PDI foron actualizados ({0} foron carregados)</string>
<string name="update_poi_error_local">Non podes atualizar a listaxe local de PDI.</string>
@ -1986,7 +1986,7 @@ Lon %2$s</string>
<string name="routing_attr_short_way_description">Empregar o camiño con aforro no combustíbel (normalmente máis curto).</string>
<string name="shared_string_change">Mudar</string>
<string name="get_started">Comezar</string>
<string name="route_stops_before">%1$s paraxes antes</string>
<string name="route_stops_before">%1$s paradas antes</string>
<string name="access_direction_haptic_feedback_descr">Inserir o enderezo do destino mediante vibración.</string>
<string name="use_osm_live_routing_description">Activar a navegación por modificacións do OsmAnd ao Vivo.</string>
<string name="access_disable_offroute_recalc">Non recalcular a ruta ó saírme da mesma</string>
@ -2362,8 +2362,8 @@ Lon %2$s</string>
<string name="map_imported_successfully">Mapa importado</string>
<string name="make_as_start_point">Converter isto no punto de partida</string>
<string name="shared_string_current">Actual</string>
<string name="last_intermediate_dest_description">Engade unha paraxe intermedia</string>
<string name="first_intermediate_dest_description">Engade a primeira paraxe do percorrido</string>
<string name="last_intermediate_dest_description">Engade unha parada intermedia</string>
<string name="first_intermediate_dest_description">Engade a primeira parada do percorrido</string>
<string name="subsequent_dest_description">Move o destino cara enriba e crea un novo</string>
<string name="switch_osm_notes_visibility_desc">Amosar/agochar as notas do OSM no mapa.</string>
<string name="gpx_file_desc">GPX - axeitado para exportar a JOSM ou outros editores do OSM.</string>
@ -2430,7 +2430,7 @@ Lon %2$s</string>
<string name="start_search_from_city">Primeiro especificar a cidade, vila ou lugar</string>
<string name="shared_string_restore">Restaurar</string>
<string name="keep_passed_markers">Manter no mapa as marcaxes desbotadas</string>
<string name="more_transport_on_stop_hint">Máis transportes dispoñíbeis dende esta paraxe.</string>
<string name="more_transport_on_stop_hint">Máis transportes dispoñíbeis dende esta parada.</string>
<string name="ask_for_location_permission">Para proseguer, permite acceder á localización ó OsmAnd.</string>
<string name="thank_you_for_feedback">Grazas polos teus comentarios</string>
<string name="poi_cannot_be_found">Non foi posíbel atopar o nó ou a vía.</string>
@ -2760,7 +2760,7 @@ Lon %2$s</string>
<string name="osmand_extended_description_part6">Camiñar, sendeirismo, turismo de cidade
\n • O mapa amosa as rotas para camiñar e de sendeirismo
\n • Wikipedia na lingua de preferencia, pode dicir moito durante unha visita turística
\n • As paraxes do transporte público (autobús, tranvía, tren), incluíndo os nomes de liña, axuda a navigar nunha nova cidade
\n • As paradas do transporte público (autobús, tranvía, tren), incluíndo os nomes de liña, axuda a navigar nunha nova cidade
\n • Navegación GPS no modo peón, constrúe a rota empregando rotas de sendeirismo
\n • Soba e sigua unha rota GPX ou grave e partille ou comparta as súas propias rotas
\n</string>
@ -2897,7 +2897,7 @@ Lon %2$s</string>
<string name="step_by_step">Tódolos cruzamentos (xiro a xiro)</string>
<string name="routeInfo_road_types_name">Tipos de estrada</string>
<string name="exit_at">Saír en</string>
<string name="sit_on_the_stop">Embarcar na paraxe</string>
<string name="sit_on_the_stop">Embarcar na parada</string>
<string name="shared_string_swap">Trocar</string>
<string name="show_more">Amosar máis</string>
<string name="tracks_on_map">Pistas amosadas</string>
@ -3879,7 +3879,7 @@ Lon %2$s</string>
<string name="reverse_route">Ruta inversa</string>
<string name="route_between_points_whole_track_button_desc">Recalcular toda a pista empregando o perfil escollido.</string>
<string name="route_between_points_next_segment_button_desc">Recalcular só o seguinte segmento empregando o perfil escollido.</string>
<string name="route_between_points_desc">Marca de que xeito conectar os puntos, cunha liña recta ou calcular unha ruta entre eles como se detalla deseguido.</string>
<string name="route_between_points_desc">Escolle de que xeito conectar os puntos, cunha liña recta ou calcular unha ruta entre eles como se detalla deseguido.</string>
<string name="whole_track">Pista enteira</string>
<string name="next_segment">Seguinte segmento</string>
<string name="route_between_points_warning_desc">Deseguido, axusta a pista á estrada permitida máis preto cun perfil de navegación.</string>
@ -3955,4 +3955,20 @@ Lon %2$s</string>
<string name="use_two_phase_routing">Usar algoritmo de enrutamento A* de 2 fases</string>
<string name="shared_string_graph">Gráfica</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="navigate_point_mgrs">MGRS</string>
<string name="navigate_point_format_mgrs">MGRS</string>
<string name="mgrs_format_descr">O OsmAnd emprega MGRS, que é semellante ó formato UTM NATO.</string>
<string name="message_need_calculate_route_before_show_graph">%1$s datos dispoñíbeis só nas estrada, necesitas calcular unha ruta empregando \"Ruta entre puntos\" para obtela.</string>
<string name="message_graph_will_be_available_after_recalculation">Agarda polo recálculo da ruta.
\nO gráfico estará dispoñíbel após o recálculo.</string>
<string name="shared_string_local_maps">Mapas locais</string>
<string name="app_mode_gap">Salto</string>
<string name="icon_group_amenity">Instalación</string>
<string name="icon_group_special">Especial</string>
<string name="icon_group_transport">Transporte</string>
<string name="icon_group_service">Servizo</string>
<string name="icon_group_symbols">Símbolos</string>
<string name="icon_group_sport">Deporte</string>
<string name="icon_group_emergency">Emerxencia</string>
<string name="icon_group_travel">Viaxe</string>
</resources>

View file

@ -3840,4 +3840,6 @@
<string name="poi_parking_sheds">Fedett parkolóhely</string>
<string name="poi_parking_rooftop">Tető</string>
<string name="poi_internet_access_fee_customers">Internetcsatlakozás: ügyfeleknek</string>
<string name="poi_radar_tower">Radartorony</string>
<string name="poi_gpx_point">GPX-pont</string>
</resources>

View file

@ -3935,4 +3935,7 @@
<string name="icon_group_sport">Sport</string>
<string name="icon_group_emergency">Vészhelyzet</string>
<string name="icon_group_travel">Utazás</string>
<string name="navigate_point_mgrs">MGRS</string>
<string name="navigate_point_format_mgrs">MGRS</string>
<string name="mgrs_format_descr">Az OsmAnd a NATO által is használt MGRS (Military Grid Reference System) koordinátákat alkamazza, amely hasonlít az UTM-formátumhoz.</string>
</resources>

View file

@ -106,15 +106,15 @@
<string name="favorite_category_select">Veldu flokk</string>
<string name="default_speed_system">Hraðaeining</string>
<string name="nm">sml</string>
<string name="si_nm">sjómílur</string>
<string name="si_kmh">kílómetrar á klukkustund</string>
<string name="si_mph">mílur á klukkustund</string>
<string name="si_m_s">metrar á sekúndu</string>
<string name="si_min_km">mínútur á kílómetra</string>
<string name="si_min_m">mínútur á mílu</string>
<string name="si_nm">Sjómílur</string>
<string name="si_kmh">Kílómetrar á klukkustund</string>
<string name="si_mph">Mílur á klukkustund</string>
<string name="si_m_s">Metrar á sekúndu</string>
<string name="si_min_km">Mínútur á kílómetra</string>
<string name="si_min_m">Mínútur á mílu</string>
<string name="si_nm_h">Sjómílur á klukkustund (hnútar)</string>
<string name="nm_h">hnútar</string>
<string name="min_mile">mín/m</string>
<string name="min_mile">mín/ml</string>
<string name="min_km">mín/km</string>
<string name="m_s">m/sek</string>
<string name="shared_string_navigation">Leiðsögn</string>
@ -238,7 +238,7 @@
<string name="shared_string_show_all">Sýna allt</string>
<string name="shared_string_collapse">Fella saman</string>
<string name="shared_string_show_on_map">Birta á korti</string>
<string name="shared_string_map">Kort</string>
<string name="shared_string_map">Landakort</string>
<string name="shared_string_favorite">Eftirlæti</string>
<string name="shared_string_favorites">Eftirlæti</string>
<string name="shared_string_address">Heimilisfang</string>
@ -2109,7 +2109,7 @@
<string name="save_poi_too_many_uppercase">Nafnið inniheldur of marga hástafi. Viltu halda áfram?</string>
<string name="quick_action_duplicate">Tvítekið nafn á flýtiaðgerð</string>
<string name="quick_action_category_descr">Flokkur til að vista eftirlætisstað í:</string>
<string name="shared_string_install">Setja inn</string>
<string name="shared_string_install">Setja upp</string>
<string name="online_photos">Ljósmyndir á netinu</string>
<string name="no_photos_descr">Engar myndir hér.</string>
<string name="nothing_found_descr">Breyttu leitarorðum eða stækkaðu radíus leitarinnar.</string>

View file

@ -222,7 +222,7 @@
<string name="version_index_is_not_supported">La versione dell\'indice \'\'{0}\'\' non è supportata</string>
<string name="osmand_routing_experimental">Il routing offline di OsmAnd è sperimentale e non funziona per distanze superiori ai 20 km.
\n
\nNavigazione eseguita temporaneamente tramite servizio online CloudMade.</string>
\nNavigazione temporaneamente spostata sul servizio online CloudMade.</string>
<string name="specified_dir_doesnt_exist">Impossibile trovare la cartella specificata.</string>
<string name="application_dir">Cartella salvataggio dei dati</string>
<string name="osmand_net_previously_installed">Tutti i dati offline nella vecchia app verranno supportati dalla nuova, ma i Preferiti devono essere esportati dalla vecchia app e importati nella nuova.</string>
@ -313,13 +313,13 @@
<string name="gps_provider">GPS</string>
<string name="int_seconds">secondi</string>
<string name="int_min">min.</string>
<string name="background_service_int_descr">Intervallo di tempo di risveglio usato dal servizio in background:</string>
<string name="background_service_int_descr">Intervallo di risveglio usato dal servizio in background:</string>
<string name="background_service_int">Intervallo di risveglio GPS</string>
<string name="background_service_provider_descr">Fornitore di posizione utilizzato dal servizio in background:</string>
<string name="background_service_provider_descr">Metodo di localizzazione utilizzato dal servizio in background:</string>
<string name="background_service_provider">Fornitore di posizionamento</string>
<string name="background_router_service_descr">Traccia la posizione mentre lo schermo è spento.</string>
<string name="background_router_service">Esegui OsmAnd in background</string>
<string name="off_router_service_no_gps_available">Il servizio di navigazione in background di OsmAnd necessita del sistema di posizionamento attivato.</string>
<string name="off_router_service_no_gps_available">Il servizio di navigazione in background necessita di un sistema di posizionamento attivo.</string>
<string name="hide_poi_filter">Nascondi filtro</string>
<string name="show_poi_filter">Visualizza filtro</string>
<string name="search_poi_filter">Filtro</string>
@ -2697,11 +2697,11 @@
<string name="how_to_open_wiki_title">Come aprire gli articoli di Wikipedia?</string>
<string name="osmand_plus_extended_description_part2">Navigazione
\n • Funziona online (veloce) o offline (nessuna tariffa di roaming quando sei all\'estero)
\n • Guida vocale svolta-dopo-svolta (voci registrate e sintetizzate)
\n • Guida sulla corsia opzionale, visualizzazione dei nomi delle strade, e tempo di arrivo stimato
\n • Supporto per punti intermedi del tuo itinerario
\n • Guida vocale svolta-per-svolta (voci registrate e sintetizzate)
\n • Indicazioni di corsia opzionali, visualizzazione dei nomi delle strade, e tempo di arrivo stimato
\n • Supporto dei punti intermedi del tuo itinerario
\n • Rielaborazione del percorso automatico ogni volta che si devia
\n • Ricerca di posti per indirizzo, per tipo (es: ristorante, albergo, stazione di servizio, museo) o per coordinate geografiche
\n • Ricerca di luoghi per indirizzo, per tipo (es: ristorante, albergo, stazione di servizio, museo) o per coordinate geografiche
\n</string>
<string name="hide_full_description">Nascondi la descrizione completa</string>
<string name="show_full_description">Mostra la descrizione completa</string>
@ -2743,12 +2743,12 @@
\n • Condividi la tua posizione in modo tale che i tuoi amici possano trovarti
\n</string>
<string name="osmand_plus_extended_description_part6">Funzioni per pedoni e velocipedi
\n • Mostra percorsi per pedoni, escursionisti e biciclette, ottimo per le attività allaperto
\n • Mostra percorsi per pedoni, escursionisti e biciclette, ottimo per le attività all\'aperto
\n • Navigazione e visualizzazione speciali per pedoni e velocipedi
\n • Scegli se mostrare le fermate del trasporto pubblico (bus, tram e treno) inclusi i nomi delle linee
\n • Scegli se registrare la tua visita su un file GPX locale oppure su di un servizio online
\n • Scegli se mostrare la velocità e laltitudine
\n • Mostra le curve di livello e lombreggiatura dei rilievi</string>
\n • Mostra le curve di livello e lombreggiatura dei rilievi (attraverso il componente aggiuntivo)</string>
<string name="unirs_render_descr">Modifica dello stile standard per un maggior contrasto delle strade pedonali e piste ciclabili. Utilizza i colori della versione vecchia di Mapnik.</string>
<string name="access_intermediate_arrival_time">Orario di arrivo intermedio</string>
<string name="map_widget_intermediate_time">Orario intermedio</string>
@ -3933,4 +3933,16 @@
\nIl grafico sarà disponibile dopo il ricalcolo.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="app_mode_gap">Buco</string>
<string name="navigate_point_mgrs">MGRS</string>
<string name="navigate_point_format_mgrs">MGRS</string>
<string name="mgrs_format_descr">OsmAnd utilizza MGRS, che è simile al formato UTM NATO.</string>
<string name="shared_string_local_maps">Mappe locali</string>
<string name="icon_group_amenity">Amenità</string>
<string name="icon_group_special">Speciale</string>
<string name="icon_group_transport">Trasporto</string>
<string name="icon_group_service">Servizi</string>
<string name="icon_group_symbols">Simboli</string>
<string name="icon_group_sport">Sport</string>
<string name="icon_group_emergency">Emergenza</string>
<string name="icon_group_travel">Viaggio</string>
</resources>

View file

@ -3948,4 +3948,7 @@
<string name="icon_group_sport">ספורט</string>
<string name="icon_group_emergency">חירום</string>
<string name="icon_group_travel">טיול</string>
<string name="mgrs_format_descr">ב־OsmAnd נעשה שימוש ב־MGRS, שדומה לתצורת UTM NATO.</string>
<string name="navigate_point_mgrs">MGRS</string>
<string name="navigate_point_format_mgrs">MGRS</string>
</resources>

View file

@ -361,7 +361,7 @@
<string name="poi_lawyer">法律事務所</string>
<string name="poi_office_telecommunication">通信会社事務所</string>
<string name="poi_ngo">NGO・非政府組織</string>
<string name="poi_townhall">役場・庁舎</string>
<string name="poi_townhall">役場・庁舎</string>
<string name="poi_employment_agency">職業紹介所</string>
<string name="poi_research">研究所</string>
<string name="poi_it">IT関連事務所</string>
@ -370,7 +370,7 @@
<string name="poi_advertising_agency">広告代理店</string>
<string name="poi_educational_institution">教育団体事務所</string>
<string name="poi_studio">テレビ・ラジオ・録音スタジオ</string>
<string name="poi_bookmaker">賭博場</string>
<string name="poi_bookmaker">ブックメーカー</string>
<string name="poi_stadium">スタジアム</string>
<string name="poi_sports_centre">総合スポーツ場</string>
<string name="poi_golf_course">ゴルフ場</string>
@ -3839,4 +3839,5 @@
<string name="poi_parking_layby">待避所</string>
<string name="poi_parking_sheds">車庫</string>
<string name="poi_parking_rooftop">屋上</string>
<string name="poi_radar_tower">レーダー塔</string>
</resources>

View file

@ -827,7 +827,7 @@ POIの更新は利用できません</string>
<string name="shared_string_help">ヘルプ</string>
<string name="accessibility_mode">アクセシビリティモード</string>
<string name="accessibility_mode_descr">アクセシビリティ(ユーザー補助)機能を設定します</string>
<string name="shared_string_on">ON</string>
<string name="shared_string_on">On</string>
<string name="shared_string_off">OFF</string>
<string name="accessibility_default">デバイス側のユーザー補助設定に従う</string>
<string name="backToMenu">メニューに戻る</string>
@ -1547,7 +1547,7 @@ POIの更新は利用できません</string>
<string name="storage_directory">マップストレージ</string>
<string name="shared_string_copy">コピー</string>
<string name="osm_edit_context_menu_delete">OSMの編集を削除</string>
<string name="rendering_value_disabled_name">無効</string>
<string name="rendering_value_disabled_name">無効</string>
<string name="shared_string_logoff">ログオフ</string>
<string name="routing_attr_avoid_borders_description">国境を越えて別の国に入るようなルート設定を避けます。</string>
<string name="routing_attr_height_name">高さ制限</string>
@ -1808,7 +1808,7 @@ POIの更新は利用できません</string>
<string name="item_removed">項目の削除</string>
<string name="n_items_removed">項目は削除されました</string>
<string name="shared_string_undo_all">すべて元に戻す</string>
<string name="shared_string_type">タイプ</string>
<string name="shared_string_type">種類</string>
<string name="starting_point">出発地点</string>
<string name="shared_string_not_selected">指定しない</string>
<string name="report">レポート</string>
@ -2853,7 +2853,7 @@ POIの更新は利用できません</string>
<string name="by_transport_type">%1$s を利用</string>
<string name="routeInfo_road_types_name">道路種別</string>
<string name="shared_string_swap">入れ替え</string>
<string name="show_more">詳細を見る</string>
<string name="show_more">さらに表示</string>
<string name="tracks_on_map">マップ上の経路</string>
<string name="quick_action_show_hide_gpx_tracks">GPX経路の表示/非表示</string>
<string name="quick_action_show_hide_gpx_tracks_descr">マップ上にある選択したGPX経路の表示/非表示を切り替えるボタンです。</string>
@ -2898,7 +2898,7 @@ POIの更新は利用できません</string>
<string name="default_price_currency_format">%1$.2f %2$s</string>
<string name="osm_live_payment_header">支払い方法の選択:</string>
<string name="osm_live_payment_contribute_descr">寄付金はOSMの地図製作に役立てられます。</string>
<string name="mapillary_menu_title_pano">360°イメージのみ表示</string>
<string name="mapillary_menu_title_pano">360°画像のみを表示</string>
<string name="osm_recipient_stat">編集 %1$s, 合計 %2$s mBTC</string>
<string name="shared_string_launch">起動</string>
<string name="lang_gn_py">グアラニー語</string>
@ -3048,9 +3048,9 @@ POIの更新は利用できません</string>
<string name="rendering_attr_showLez_description">マップ上に低排出ゾーン(CO2排出量の多い車両に課税するエリア)を表示します。ルーティングには影響しません。</string>
<string name="rendering_attr_showLez_name">低排出ゾーンの表示</string>
<string name="shared_string_default">デフォルト</string>
<string name="exit_at">出口:</string>
<string name="exit_at">降車</string>
<string name="transfers_size">%1$d回の乗り換え</string>
<string name="shared_string_walk"></string>
<string name="shared_string_walk"></string>
<string name="send_log">ログの送信</string>
<string name="files_moved">%1$d個のファイルを移動しました。(%2$s)</string>
<string name="files_copied">%1$d個のファイルをコピーしました。(%2$s)</string>
@ -3106,12 +3106,12 @@ POIの更新は利用できません</string>
<string name="select_base_profile_dialog_title">開始時に表示するプロファイルの選択</string>
<string name="select_base_profile_dialog_message">カスタムプロファイルは標準のアプリケーションプロファイルを元に作成します。ウィジェットなどの表示設定や速度と距離の単位などの標準設定をプロファイルごとに定義可能です。これらは標準のアプリプロファイルを基本としており、今後それらと共に拡張される可能性があります:</string>
<string name="select_nav_profile_dialog_title">ナビゲーションタイプの選択</string>
<string name="base_profile_descr_car">乗用車,トラック,オートバイ</string>
<string name="base_profile_descr_bicycle">マウンテンバイク、モペッド(ペダル付き原動機付自転車)、馬</string>
<string name="base_profile_descr_pedestrian">徒歩,ハイキング,ランニング</string>
<string name="base_profile_descr_car">乗用車、トラック、オートバイ</string>
<string name="base_profile_descr_bicycle">マウンテンバイク、モペッド、馬</string>
<string name="base_profile_descr_pedestrian">徒歩、ハイキング、ランニング</string>
<string name="base_profile_descr_public_transport">公共交通機関の種類</string>
<string name="base_profile_descr_boat">エンジン付き船舶,漕ぎボート,帆船</string>
<string name="base_profile_descr_aircraft">航空機,グライダー</string>
<string name="base_profile_descr_boat">船舶、漕ぎボート、帆船</string>
<string name="base_profile_descr_aircraft">航空機グライダー</string>
<string name="routing_profile_geocoding">ジオコーディング</string>
<string name="routing_profile_straightline">直線</string>
<string name="routing_profile_broutrer">BRouter(オフライン)</string>
@ -3206,7 +3206,7 @@ POIの更新は利用できません</string>
<string name="map_look">マップ外観</string>
<string name="list_of_installed_plugins">インストール済みプラグインリスト</string>
<string name="configure_navigation">ナビゲーション設定</string>
<string name="general_settings_profile_descr">アプリテーマ、ユニット、リージョン</string>
<string name="general_settings_profile_descr">アプリテーマ、単位、地域</string>
<string name="configure_profile">プロファイルの構築</string>
<string name="switch_profile">プロファイル切替</string>
<string name="application_profile_changed">アプリケーションプロファイルが\"%s\"に切り替えられました</string>
@ -3809,8 +3809,8 @@ POIの更新は利用できません</string>
<string name="add_online_source">オンラインソースを追加</string>
<string name="clear_tiles_warning">これらの変更を適用すると、このタイルソースのキャッシュデータがクリアされます</string>
<string name="vessel_height_warning_link">船の高さを設定</string>
<string name="vessel_height_warning">低い橋を避けるために船の高さを調整できます。ブリッジが可動式の場合は、開いた状態の高さが参照されます。</string>
<string name="vessel_height_limit_description">低い橋を避けるために船の高さを設定します。注:ブリッジが可動式の場合は、開いた状態の高さが参照されます。</string>
<string name="vessel_height_warning">低い橋を避けるために船の高さを調整できます。が可動式の場合は、開いた状態の高さが参照されます。</string>
<string name="vessel_height_limit_description">低い橋を避けるために船の高さを設定します。注:が可動式の場合は、開いた状態の高さが参照されます。</string>
<string name="vessel_width_limit_description">狭い橋を避けるために船の幅を設定します</string>
<string name="quick_action_showhide_mapillary_title">Mapillaryの表示切替</string>
<string name="quick_action_mapillary_hide">Mapillaryを非表示</string>

View file

@ -3233,7 +3233,7 @@
<string name="routing_attr_freeride_policy_description">\'Freeride\' en \'Off-piste\' zijn officieuze routes en passages. Meestal onverzorgd en niet onderhouden, en niet \'s avonds gecontroleerd. Betreden op eigen risico.</string>
<string name="collected_data">Verzamelde data</string>
<string name="last_launch_crashed">Laatste OsmAnd uitvoering gecrasht. Help ons alstublieft OsmAnd te verbeteren door de foutmelding te delen.</string>
<string name="app_mode_personal_transporter">Persoonlijke transporteur</string>
<string name="app_mode_personal_transporter">Persoonlijk transport</string>
<string name="app_mode_offroad">Offroad</string>
<string name="sett_wunderlinq_ext_input">WunderLINQ</string>
<string name="routeInfo_roadClass_name">Wegtype</string>
@ -3797,11 +3797,11 @@
\n"</string>
<string name="release_3_6">"• Profielen: nu kunt u de volgorde wijzigen, het pictogram voor de kaart instellen, alle instellingen voor basisprofielen wijzigen en ze terugzetten naar de standaardinstellingen
\n
\n • Exitnummer toegevoegd in de navigatie
\n • Exitnummer toegevoegd in de navigatie
\n
\n • Herwerkte plug-in instellingen
\n • Herwerkte plug-in instellingen
\n
\n • Herwerkt instellingenscherm voor snelle toegang tot alle profielen
\n • Herwerkt instellingenscherm voor snelle toegang tot alle profielen
\n
\n • Optie toegevoegd om instellingen van een ander profiel te kopiëren
\n

View file

@ -3675,7 +3675,7 @@
<string name="osmand_purchases_item">Zakupy w OsmAnd</string>
<string name="osm_live_payment_subscription_management">Opłata zostanie pobrana z twojego konta Google Play przy potwierdzeniu zakupu.
\n
\nSubskrypcja automatycznie odnawia się, chyba że anulujesz ją przed dniem odnowienia. Twoje konto zostanie obciążone za okres odnowienia (miesiąc/trzy miesiące/rok) dopiero w dniu odnowienia.
\nSubskrypcja automatycznie odnawia się, chyba że anulujesz ją przed dniem odnowienia. Twoje konto zostanie obciążone za okres odnowienia (miesiąc/trzy miesiące/rok) dopiero w dniu odnowienia.
\n
\nMożesz zarządzać subskrypcjami i anulować je w ustawieniach Google Play.</string>
<string name="release_3_7">• Nowe mapy stoków offline
@ -3802,7 +3802,7 @@
<string name="use_volume_buttons_as_zoom">Przyciski głośności jako powiększenie</string>
<string name="app_mode_wheelchair">Wózek inwalidzki</string>
<string name="app_mode_go_cart">Gokart</string>
<string name="osm_edit_closed_note">Zamknięta notatka OSM</string>
<string name="osm_edit_closed_note">Zamknięta uwaga OSM</string>
<string name="set_working_days_to_continue">Aby kontynuować, musisz ustawić dni robocze</string>
<string name="route_between_points">Droga pomiędzy punktami</string>
<string name="plan_a_route">Zaplanuj trasę</string>
@ -3844,7 +3844,7 @@
<string name="plan_route_exit_dialog_descr">Czy na pewno chcesz odrzucić wszystkie zmiany w zaplanowanej trasie, zamykając ją\?</string>
<string name="in_case_of_reverse_direction">W przypadku odwrotnego kierunku</string>
<string name="navigate_to_track_descr">Przejdź z mojej lokalizacji na trasę</string>
<string name="app_mode_wheelchair_forward">Wózek naprzód</string>
<string name="app_mode_wheelchair_forward">Wózek inwalidzki naprzód</string>
<string name="show_gpx">Ślady</string>
<string name="follow_track">Podążanie za śladem</string>
<string name="import_track_descr">Wybierz plik śladu do śledzenia lub zaimportuj go z urządzenia.</string>
@ -3913,7 +3913,7 @@
<string name="sort_name_ascending">Nazwa: A Z</string>
<string name="what_is_new">Co nowego</string>
<string name="start_finish_icons">Ikony start/koniec</string>
<string name="contour_lines_thanks">Dziękujemy za zakup linii konturowych</string>
<string name="contour_lines_thanks">Dziękujemy za zakup \"Linii konturowych\"</string>
<string name="osm_live_payment_desc_hw">Subskrypcja naliczona za wybrany okres. Anuluj ją w AppGallery w dowolnym momencie.</string>
<string name="osm_live_payment_subscription_management_hw">Płatność zostanie pobrana z konta AppGallery po potwierdzeniu zakupu.
\n
@ -3935,4 +3935,21 @@
<string name="osm_edit_logout_success">Wylogowanie powiodło się</string>
<string name="file_already_imported">Plik jest już zaimportowany do OsmAnd</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="navigate_point_mgrs">MGRS</string>
<string name="navigate_point_format_mgrs">MGRS</string>
<string name="use_two_phase_routing">Użyj 2-fazowego algorytmu routingu A *</string>
<string name="shared_string_graph">Wykres</string>
<string name="message_need_calculate_route_before_show_graph">%1$s dane dostępne tylko na drogach, aby je uzyskać, musisz obliczyć trasę za pomocą opcji „Trasa między punktami”.</string>
<string name="message_graph_will_be_available_after_recalculation">Poczekaj na ponowne obliczenie trasy.
\nWykres będzie dostępny po ponownym obliczeniu.</string>
<string name="shared_string_local_maps">Mapy lokalne</string>
<string name="app_mode_gap">Luka</string>
<string name="icon_group_amenity">Udogodnienie</string>
<string name="icon_group_special">Specjalne</string>
<string name="icon_group_transport">Transport</string>
<string name="icon_group_service">Usługi</string>
<string name="icon_group_symbols">Symbole</string>
<string name="icon_group_sport">Sport</string>
<string name="icon_group_emergency">Służby ratunkowe</string>
<string name="icon_group_travel">Podróże</string>
</resources>

View file

@ -3847,4 +3847,7 @@
<string name="poi_fuel_lng">GNL</string>
<string name="poi_parking_sheds">Galpões</string>
<string name="poi_gpx_point">Ponto GPX</string>
<string name="poi_radar_tower">Torre de radar</string>
<string name="poi_parking_layby">Tapume</string>
<string name="poi_parking_rooftop">Terraço</string>
</resources>

View file

@ -3938,4 +3938,7 @@
<string name="icon_group_sport">Esporte</string>
<string name="icon_group_emergency">Emergência</string>
<string name="icon_group_travel">Viagem</string>
<string name="navigate_point_mgrs">MGRS</string>
<string name="navigate_point_format_mgrs">MGRS</string>
<string name="mgrs_format_descr">OsmAnd usa MGRS, que é semelhante ao formato UTM NATO.</string>
</resources>

View file

@ -3786,7 +3786,7 @@
<string name="poi_tactile_paving_primitive">Primitivo</string>
<string name="poi_tactile_paving_contrasted">Contrastado</string>
<string name="poi_traffic_signals_sound_locate">Somente quando é permitido caminhar</string>
<string name="poi_internet_access_fee_customers">Sinal para encontrar o poste</string>
<string name="poi_internet_access_fee_customers">Acesso à Internet: clientes</string>
<string name="poi_video_no">Não</string>
<string name="poi_video_yes">Sim</string>
<string name="poi_booth">Tipo de cabine</string>
@ -3830,4 +3830,9 @@
<string name="poi_beehive">Colmeia</string>
<string name="poi_nuts">Loja de nozes</string>
<string name="poi_fuel_lng">GNL</string>
<string name="poi_parking_sheds">Barracão</string>
<string name="poi_parking_rooftop">Telhado</string>
<string name="poi_gpx_point">Ponto GPX</string>
<string name="poi_radar_tower">Torre de radar</string>
<string name="poi_parking_layby">Área de repouso</string>
</resources>

View file

@ -3829,7 +3829,7 @@
<string name="reverse_route">Rota inversa</string>
<string name="route_between_points_whole_track_button_desc">O trilho inteiro será recalculado a usar o perfil selecionado.</string>
<string name="route_between_points_next_segment_button_desc">Somente o próximo segmento será recalculado a usar o perfil selecionado.</string>
<string name="route_between_points_desc">Selecione como ligar pontos, por uma linha reta ou a calcular uma rota entre eles como especificado abaixo.</string>
<string name="route_between_points_desc">Escolha como ligar os pontos por uma linha reta ou calcule uma rota entre eles como especificado abaixo.</string>
<string name="whole_track">Trilho inteiro</string>
<string name="next_segment">Próximo segmento</string>
<string name="route_between_points_warning_desc">Em seguida, encaixe a sua pista na estrada mais próxima permitida com um dos seus perfis de navegação para usar esta opção.</string>
@ -3937,4 +3937,16 @@
\nO gráfico estará disponível após o recalculo.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="app_mode_gap">Lacuna</string>
<string name="navigate_point_mgrs">MGRS</string>
<string name="navigate_point_format_mgrs">MGRS</string>
<string name="mgrs_format_descr">O OsmAnd utiliza o MGRS, que é semelhante ao formato UTM NATO.</string>
<string name="shared_string_local_maps">Mapas locais</string>
<string name="icon_group_amenity">Amenidade</string>
<string name="icon_group_special">Especial</string>
<string name="icon_group_transport">Transporte</string>
<string name="icon_group_service">Serviço</string>
<string name="icon_group_symbols">Símbolos</string>
<string name="icon_group_sport">Desporto</string>
<string name="icon_group_emergency">Emergência</string>
<string name="icon_group_travel">Viagem</string>
</resources>

View file

@ -3835,4 +3835,5 @@
<string name="poi_fuel_lng">СПГ</string>
<string name="poi_parking_sheds">Навесы</string>
<string name="poi_gpx_point">Точка GPX</string>
<string name="poi_radar_tower">Радиолокационная вышка</string>
</resources>

View file

@ -3937,4 +3937,8 @@
<string name="icon_group_sport">Спорт</string>
<string name="icon_group_emergency">Экстренные службы</string>
<string name="icon_group_travel">Путешествие</string>
<string name="navigate_point_mgrs">MGRS</string>
<string name="navigate_point_format_mgrs">MGRS</string>
<string name="mgrs_format_descr">OsmAnd использует MGRS, который похож на формат UTM NATO.</string>
<string name="use_native_pt">Развитие местного общественного транспорта</string>
</resources>

View file

@ -3932,4 +3932,11 @@
<string name="message_graph_will_be_available_after_recalculation">Iseta su càrculu nou de s\'àndala.
\nSu gràficu at a èssere a disponimentu a pustis de su càrculu.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="icon_group_emergency">Apretu/Emergèntzia</string>
<string name="icon_group_special">Ispetziales</string>
<string name="icon_group_transport">Trasportu</string>
<string name="icon_group_service">Servìtziu</string>
<string name="icon_group_symbols">Sìmbulos</string>
<string name="icon_group_sport">Isport</string>
<string name="icon_group_travel">Biàgiu</string>
</resources>

View file

@ -3944,4 +3944,7 @@
<string name="icon_group_sport">Šport</string>
<string name="icon_group_emergency">Núdzová situácia/Záchrana</string>
<string name="icon_group_travel">Cestovanie</string>
<string name="navigate_point_mgrs">MGRS</string>
<string name="navigate_point_format_mgrs">MGRS</string>
<string name="mgrs_format_descr">OsmAnd používa MGSR, ktorý je podobný ako formát UTM NATO.</string>
</resources>

View file

@ -3783,7 +3783,7 @@
<string name="reverse_route">Ters güzergah</string>
<string name="route_between_points_whole_track_button_desc">Tüm yol, seçilen profil kullanılarak yeniden hesaplanacaktır.</string>
<string name="route_between_points_next_segment_button_desc">Sadece sonraki bölüm, seçilen profil kullanılarak yeniden hesaplanacaktır.</string>
<string name="route_between_points_desc">Düz bir çizgi ile noktaları nasıl birleştireceğinizi veya aşağıda belirtildiği gibi aralarında nasıl güzergah hesaplayacağınızı seçin.</string>
<string name="route_between_points_desc">Düz bir çizgi ile noktaların nasıl birleştirileceğini veya aşağıda belirtildiği gibi aralarında nasıl güzergah hesaplanacağını seçin.</string>
<string name="whole_track">Tüm yol</string>
<string name="next_segment">Sonraki bölüm</string>
<string name="threshold_distance">Eşik mesafesi</string>
@ -3888,4 +3888,18 @@
<string name="message_need_calculate_route_before_show_graph">%1$s verileri yalnızca yollarda kullanılabilir, elde etmek için “Noktalar arasındaki güzergah” kullanarak bir rota hesaplamanız gerekir.</string>
<string name="message_graph_will_be_available_after_recalculation">Güzergahın yeniden hesaplanmasını bekleyin.
\nGrafik yeniden hesaplandıktan sonra kullanılabilir olacak.</string>
<string name="app_mode_gap">Boşluk</string>
<string name="navigate_point_mgrs">MGRS</string>
<string name="navigate_point_format_mgrs">MGRS</string>
<string name="mgrs_format_descr">OsmAnd, UTM NATO biçimine benzer olan MGRS\'yi kullanmaktadır.</string>
<string name="shared_string_local_maps">Yerel haritalar</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="icon_group_amenity">Tesis</string>
<string name="icon_group_special">Özel</string>
<string name="icon_group_transport">Ulaşım</string>
<string name="icon_group_service">Hizmet</string>
<string name="icon_group_symbols">Semboller</string>
<string name="icon_group_sport">Spor</string>
<string name="icon_group_emergency">Acil</string>
<string name="icon_group_travel">Seyahat</string>
</resources>

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -1,2 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>
<resources>
<string name="shared_string_local_maps">Takaṛḍa tadɣarant</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="icon_group_service">Tanafut</string>
<string name="shared_string_name"></string>
<string name="shared_string_all"></string>
<string name="shared_string_add"></string>
<string name="shared_string_map"></string>
<string name="shared_string_exit"></string>
<string name="shared_string_close"></string>
<string name="shared_string_share"></string>
<string name="shared_string_save"></string>
<string name="shared_string_ok"></string>
<string name="shared_string_search"></string>
<string name="shared_string_update"></string>
<string name="shared_string_hide"></string>
<string name="shared_string_select"></string>
<string name="shared_string_status"></string>
<string name="shared_string_sort"></string>
<string name="shared_string_back"></string>
</resources>

View file

@ -3837,4 +3837,5 @@
<string name="poi_parking_sheds">Навіси</string>
<string name="poi_parking_rooftop">Дах</string>
<string name="poi_gpx_point">Точка GPX</string>
<string name="poi_radar_tower">Радіолокаційна вежа</string>
</resources>

View file

@ -3940,4 +3940,7 @@
<string name="icon_group_sport">Спорт</string>
<string name="icon_group_emergency">Аварійні служби</string>
<string name="icon_group_travel">Мандрівка</string>
<string name="navigate_point_mgrs">MGRS</string>
<string name="navigate_point_format_mgrs">MGRS</string>
<string name="mgrs_format_descr">OsmAnd використовує MGRS, який подібний формату UTM NATO.</string>
</resources>

View file

@ -3848,4 +3848,5 @@
<string name="poi_parking_sheds">車棚</string>
<string name="poi_parking_rooftop">屋頂</string>
<string name="poi_gpx_point">GPX 點</string>
<string name="poi_radar_tower">雷達塔</string>
</resources>

View file

@ -3939,4 +3939,7 @@
<string name="icon_group_sport">運動</string>
<string name="icon_group_emergency">警急</string>
<string name="icon_group_travel">旅行</string>
<string name="navigate_point_mgrs">MGRS</string>
<string name="navigate_point_format_mgrs">MGRS</string>
<string name="mgrs_format_descr">OsmAnd 使用 MGRS其類似於 UTM NATO 格式。</string>
</resources>

View file

@ -19,6 +19,7 @@
<attr name="expandable_list_background" format="color"/>
<attr name="bg_color" format="reference" />
<attr name="bg_circle" format="reference"/>
<attr name="bg_circle_contour" format="reference" />
<attr name="btn_round" format="reference" />
<attr name="btn_round_border" format="reference" />
<attr name="btn_round_border_2" format="reference" />

View file

@ -4265,4 +4265,6 @@
<string name="poi_parking_sheds">Sheds</string>
<string name="poi_parking_layby">Layby</string>
<string name="poi_radar_tower">Radar tower</string>
</resources>

View file

@ -11,6 +11,12 @@
Thx - Hardy
-->
<string name="subscription_on_hold_title">OsmAnd Live subscription is on hold</string>
<string name="subscription_paused_title">OsmAnd Live subscription has been paused</string>
<string name="subscription_expired_title">OsmAnd Live subscription has been expired</string>
<string name="subscription_payment_issue_title">There is a problem with your subscription. Click the button to go to the Google Play subscription settings to fix your payment method.</string>
<string name="manage_subscription">Manage subscription</string>
<string name="message_you_need_add_two_points_to_show_graphs">You must add at least two points.</string>
<string name="icon_group_travel">Travel</string>
<string name="icon_group_emergency">Emergency</string>
<string name="icon_group_sport">Sport</string>

View file

@ -92,6 +92,7 @@
<item name="actionBarStyle">@style/Widget.Styled.ActionBarLight</item>
<item name="bg_color">@color/list_background_color_light</item>
<item name="bg_circle">@drawable/circle_background_light</item>
<item name="bg_circle_contour">@drawable/circle_contour_bg_light</item>
<item name="btn_round">@drawable/btn_round_light</item>
<item name="btn_round_border">@drawable/btn_round_border_light</item>
<item name="btn_round_border_2">@drawable/btn_round_border_light_2</item>
@ -394,6 +395,7 @@
<item name="actionBarStyle">@style/Widget.Styled.ActionBarDark</item>
<item name="bg_color">@color/list_background_color_dark</item>
<item name="bg_circle">@drawable/circle_background_dark</item>
<item name="bg_circle_contour">@drawable/circle_contour_bg_dark</item>
<item name="btn_round">@drawable/btn_round_dark</item>
<item name="btn_round_border">@drawable/btn_round_border_dark</item>
<item name="btn_round_border_2">@drawable/btn_round_border_dark_2</item>

View file

@ -21,8 +21,10 @@ import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.inapp.InAppPurchases.InAppPurchase;
import net.osmand.plus.inapp.InAppPurchases.InAppSubscription;
import net.osmand.plus.inapp.InAppPurchases.InAppSubscription.SubscriptionState;
import net.osmand.plus.inapp.InAppPurchasesImpl.InAppPurchaseLiveUpdatesOldSubscription;
import net.osmand.plus.inapp.util.BillingManager;
import net.osmand.plus.settings.backend.CommonPreference;
import net.osmand.plus.settings.backend.OsmandPreference;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.srtmplugin.SRTMPlugin;
@ -33,6 +35,7 @@ import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map.Entry;
public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
@ -139,6 +142,7 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
for (Purchase p : purchases) {
skuSubscriptions.add(p.getSku());
}
skuSubscriptions.addAll(subscriptionStateMap.keySet());
BillingManager billingManager = getBillingManager();
// Have we been disposed of in the meantime? If so, quit.
@ -291,7 +295,7 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
}
// Listener that's called when we finish querying the items and subscriptions we own
private SkuDetailsResponseListener mSkuDetailsResponseListener = new SkuDetailsResponseListener() {
private final SkuDetailsResponseListener mSkuDetailsResponseListener = new SkuDetailsResponseListener() {
@NonNull
private List<String> getAllOwnedSubscriptionSkus() {
@ -304,6 +308,15 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
}
}
}
for (Entry<String, SubscriptionState> entry : subscriptionStateMap.entrySet()) {
SubscriptionState state = entry.getValue();
if (state == SubscriptionState.PAUSED || state == SubscriptionState.ON_HOLD) {
String sku = entry.getKey();
if (!result.contains(sku)) {
result.add(sku);
}
}
}
return result;
}
@ -399,35 +412,28 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
// Do we have the live updates?
boolean subscribedToLiveUpdates = false;
List<Purchase> liveUpdatesPurchases = new ArrayList<>();
for (InAppPurchase p : getLiveUpdates().getAllSubscriptions()) {
Purchase purchase = getPurchase(p.getSku());
if (purchase != null) {
liveUpdatesPurchases.add(purchase);
for (InAppSubscription s : getLiveUpdates().getAllSubscriptions()) {
Purchase purchase = getPurchase(s.getSku());
if (purchase != null || s.getState().isActive()) {
if (purchase != null) {
liveUpdatesPurchases.add(purchase);
}
if (!subscribedToLiveUpdates) {
subscribedToLiveUpdates = true;
}
}
}
OsmandPreference<Long> subscriptionCancelledTime = ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_TIME;
if (!subscribedToLiveUpdates && ctx.getSettings().LIVE_UPDATES_PURCHASED.get()) {
if (subscriptionCancelledTime.get() == 0) {
subscriptionCancelledTime.set(System.currentTimeMillis());
ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_FIRST_DLG_SHOWN.set(false);
ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_SECOND_DLG_SHOWN.set(false);
} else if (System.currentTimeMillis() - subscriptionCancelledTime.get() > SUBSCRIPTION_HOLDING_TIME_MSEC) {
ctx.getSettings().LIVE_UPDATES_PURCHASED.set(false);
if (!isDepthContoursPurchased(ctx)) {
ctx.getSettings().getCustomRenderBooleanProperty("depthContours").set(false);
}
ctx.getSettings().LIVE_UPDATES_PURCHASED.set(false);
if (!isDepthContoursPurchased(ctx)) {
ctx.getSettings().getCustomRenderBooleanProperty("depthContours").set(false);
}
} else if (subscribedToLiveUpdates) {
subscriptionCancelledTime.set(0L);
ctx.getSettings().LIVE_UPDATES_PURCHASED.set(true);
}
lastValidationCheckTime = System.currentTimeMillis();
logDebug("User " + (subscribedToLiveUpdates ? "HAS" : "DOES NOT HAVE")
+ " live updates purchased.");
logDebug("User " + (subscribedToLiveUpdates ? "HAS" : "DOES NOT HAVE") + " live updates purchased.");
OsmandSettings settings = ctx.getSettings();
settings.INAPPS_READ.set(true);
@ -490,12 +496,24 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
}
}
if (inAppPurchase instanceof InAppSubscription) {
InAppSubscription s = (InAppSubscription) inAppPurchase;
SubscriptionState state = subscriptionStateMap.get(inAppPurchase.getSku());
s.setState(state == null ? SubscriptionState.UNDEFINED : state);
CommonPreference<String> statePref = ctx.getSettings().registerStringPreference(
s.getSku() + "_state", SubscriptionState.UNDEFINED.getStateStr()).makeGlobal();
s.setPrevState(SubscriptionState.getByStateStr(statePref.get()));
statePref.set(s.getState().getStateStr());
if (s.getState().isGone() && s.hasStateChanged()) {
ctx.getSettings().LIVE_UPDATES_EXPIRED_FIRST_DLG_SHOWN_TIME.set(0L);
ctx.getSettings().LIVE_UPDATES_EXPIRED_SECOND_DLG_SHOWN_TIME.set(0L);
}
String introductoryPrice = skuDetails.getIntroductoryPrice();
String introductoryPricePeriod = skuDetails.getIntroductoryPricePeriod();
String introductoryPriceCycles = skuDetails.getIntroductoryPriceCycles();
long introductoryPriceAmountMicros = skuDetails.getIntroductoryPriceAmountMicros();
if (!Algorithms.isEmpty(introductoryPrice)) {
InAppSubscription s = (InAppSubscription) inAppPurchase;
try {
s.setIntroductoryInfo(new InAppPurchases.InAppSubscriptionIntroductoryInfo(s, introductoryPrice,
introductoryPriceAmountMicros, introductoryPricePeriod, introductoryPriceCycles));

View file

@ -134,11 +134,11 @@ public class Version {
}
public static boolean isDeveloperVersion(OsmandApplication ctx){
return getAppName(ctx).contains("~") || ctx.getPackageName().equals(FREE_DEV_VERSION_NAME);
return false;//getAppName(ctx).contains("~") || ctx.getPackageName().equals(FREE_DEV_VERSION_NAME);
}
public static boolean isDeveloperBuild(OsmandApplication ctx){
return getAppName(ctx).contains("~");
return false;//getAppName(ctx).contains("~");
}
public static String getVersionForTracker(OsmandApplication ctx) {

View file

@ -83,7 +83,7 @@ import net.osmand.plus.base.BaseOsmAndFragment;
import net.osmand.plus.base.ContextMenuFragment;
import net.osmand.plus.base.FailSafeFuntions;
import net.osmand.plus.base.MapViewTrackingUtilities;
import net.osmand.plus.chooseplan.OsmLiveCancelledDialog;
import net.osmand.plus.chooseplan.OsmLiveGoneDialog;
import net.osmand.plus.dashboard.DashBaseFragment;
import net.osmand.plus.dashboard.DashboardOnMap;
import net.osmand.plus.dialogs.CrashBottomSheetDialogFragment;
@ -845,8 +845,6 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
getSupportFragmentManager().beginTransaction()
.add(R.id.fragmentContainer, new FirstUsageWelcomeFragment(),
FirstUsageWelcomeFragment.TAG).commitAllowingStateLoss();
} else if (!isFirstScreenShowing() && OsmLiveCancelledDialog.shouldShowDialog(app)) {
OsmLiveCancelledDialog.showInstance(getSupportFragmentManager());
} else if (SendAnalyticsBottomSheetDialogFragment.shouldShowDialog(app)) {
SendAnalyticsBottomSheetDialogFragment.showInstance(app, getSupportFragmentManager(), null);
}
@ -2290,6 +2288,9 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
@Override
public void onInAppPurchaseGetItems() {
DiscountHelper.checkAndDisplay(this);
if (!isFirstScreenShowing() && OsmLiveGoneDialog.shouldShowDialog(app)) {
OsmLiveGoneDialog.showInstance(app, getSupportFragmentManager());
}
}
public enum ShowQuickSearchMode {

View file

@ -1,245 +0,0 @@
package net.osmand.plus.chooseplan;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.Bundle;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.ProgressBar;
import androidx.annotation.ColorRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import net.osmand.PlatformUtil;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.Version;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.settings.backend.OsmandPreference;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.BaseOsmAndDialogFragment;
import net.osmand.plus.chooseplan.ChoosePlanDialogFragment.OsmAndFeature;
import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseListener;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseTaskType;
import net.osmand.plus.widgets.TextViewEx;
import org.apache.commons.logging.Log;
import static net.osmand.plus.inapp.InAppPurchaseHelper.SUBSCRIPTION_HOLDING_TIME_MSEC;
public class OsmLiveCancelledDialog extends BaseOsmAndDialogFragment implements InAppPurchaseListener {
public static final String TAG = OsmLiveCancelledDialog.class.getSimpleName();
private static final Log LOG = PlatformUtil.getLog(OsmLiveCancelledDialog.class);
private OsmandApplication app;
private InAppPurchaseHelper purchaseHelper;
private boolean nightMode;
private View osmLiveButton;
private final OsmAndFeature[] osmLiveFeatures = {
OsmAndFeature.DAILY_MAP_UPDATES,
OsmAndFeature.UNLIMITED_DOWNLOADS,
OsmAndFeature.WIKIPEDIA_OFFLINE,
OsmAndFeature.WIKIVOYAGE_OFFLINE,
OsmAndFeature.CONTOUR_LINES_HILLSHADE_MAPS,
OsmAndFeature.SEA_DEPTH_MAPS,
OsmAndFeature.UNLOCK_ALL_FEATURES,
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = getMyApplication();
purchaseHelper = app.getInAppPurchaseHelper();
nightMode = isNightMode(getMapActivity() != null);
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Activity ctx = requireActivity();
int themeId = nightMode ? R.style.OsmandDarkTheme_DarkActionbar : R.style.OsmandLightTheme_DarkActionbar_LightStatusBar;
Dialog dialog = new Dialog(ctx, themeId);
Window window = dialog.getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
if (!getSettings().DO_NOT_USE_ANIMATIONS.get()) {
window.getAttributes().windowAnimations = R.style.Animations_Alpha;
}
if (Build.VERSION.SDK_INT >= 21) {
window.setStatusBarColor(ContextCompat.getColor(ctx, getStatusBarColor()));
}
}
return dialog;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Context ctx = getContext();
if (ctx == null) {
return null;
}
int themeRes = nightMode ? R.style.OsmandDarkTheme_DarkActionbar : R.style.OsmandLightTheme_DarkActionbar_LightStatusBar;
View view = LayoutInflater.from(new ContextThemeWrapper(getContext(), themeRes))
.inflate(R.layout.osmlive_cancelled_dialog_fragment, container, false);
view.findViewById(R.id.button_close).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
TextViewEx infoDescr = (TextViewEx) view.findViewById(R.id.info_description);
StringBuilder descr = new StringBuilder();
descr.append(getString(R.string.purchase_cancelled_dialog_descr));
for (OsmAndFeature feature : osmLiveFeatures) {
descr.append("\n").append("").append(feature.toHumanString(ctx));
}
infoDescr.setText(descr);
TextViewEx inappDescr = (TextViewEx) view.findViewById(R.id.inapp_descr);
inappDescr.setText(Version.isHuawei(app) ? R.string.osm_live_payment_desc_hw : R.string.osm_live_payment_desc);
osmLiveButton = view.findViewById(R.id.card_button);
return view;
}
@Nullable
public MapActivity getMapActivity() {
Activity activity = getActivity();
if (activity instanceof MapActivity) {
return (MapActivity) activity;
}
return null;
}
@Override
public void onResume() {
super.onResume();
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.disableDrawer();
}
boolean requestingInventory = purchaseHelper != null && purchaseHelper.getActiveTask() == InAppPurchaseTaskType.REQUEST_INVENTORY;
setupOsmLiveButton(requestingInventory);
OsmandPreference<Boolean> firstTimeShown = app.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_FIRST_DLG_SHOWN;
OsmandPreference<Boolean> secondTimeShown = app.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_SECOND_DLG_SHOWN;
if (!firstTimeShown.get()) {
firstTimeShown.set(true);
} else if (!secondTimeShown.get()) {
secondTimeShown.set(true);
}
}
@Override
public void onPause() {
super.onPause();
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.enableDrawer();
}
}
@ColorRes
protected int getStatusBarColor() {
return nightMode ? R.color.status_bar_wikivoyage_dark : R.color.status_bar_wikivoyage_light;
}
@Override
public void onError(InAppPurchaseTaskType taskType, String error) {
if (taskType == InAppPurchaseTaskType.REQUEST_INVENTORY) {
setupOsmLiveButton(false);
}
}
@Override
public void onGetItems() {
}
@Override
public void onItemPurchased(String sku, boolean active) {
}
@Override
public void showProgress(InAppPurchaseTaskType taskType) {
if (taskType == InAppPurchaseTaskType.REQUEST_INVENTORY) {
setupOsmLiveButton(true);
}
}
@Override
public void dismissProgress(InAppPurchaseTaskType taskType) {
if (taskType == InAppPurchaseTaskType.REQUEST_INVENTORY) {
setupOsmLiveButton(false);
}
}
private void setupOsmLiveButton(boolean progress) {
if (osmLiveButton != null) {
ProgressBar progressBar = (ProgressBar) osmLiveButton.findViewById(R.id.card_button_progress);
TextViewEx buttonTitle = (TextViewEx) osmLiveButton.findViewById(R.id.card_button_title);
TextViewEx buttonSubtitle = (TextViewEx) osmLiveButton.findViewById(R.id.card_button_subtitle);
buttonTitle.setText(getString(R.string.osm_live_plan_pricing));
buttonSubtitle.setVisibility(View.GONE);
if (progress) {
buttonTitle.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
osmLiveButton.setOnClickListener(null);
} else {
buttonTitle.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
osmLiveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
FragmentActivity activity = getActivity();
if (activity != null) {
ChoosePlanDialogFragment.showOsmLiveInstance(activity.getSupportFragmentManager());
}
}
});
}
}
}
public static boolean shouldShowDialog(OsmandApplication app) {
OsmandSettings settings = app.getSettings();
long cancelledTime = settings.LIVE_UPDATES_PURCHASE_CANCELLED_TIME.get();
boolean firstTimeShown = settings.LIVE_UPDATES_PURCHASE_CANCELLED_FIRST_DLG_SHOWN.get();
boolean secondTimeShown = settings.LIVE_UPDATES_PURCHASE_CANCELLED_SECOND_DLG_SHOWN.get();
return cancelledTime > 0
&& (!firstTimeShown
|| (System.currentTimeMillis() - cancelledTime > SUBSCRIPTION_HOLDING_TIME_MSEC
&& !secondTimeShown));
}
public static void showInstance(@NonNull FragmentManager fm) {
try {
if (fm.findFragmentByTag(OsmLiveCancelledDialog.TAG) == null) {
OsmLiveCancelledDialog fragment = new OsmLiveCancelledDialog();
fragment.show(fm, OsmLiveCancelledDialog.TAG);
}
} catch (RuntimeException e) {
LOG.error("showInstance", e);
}
}
}

View file

@ -0,0 +1,334 @@
package net.osmand.plus.chooseplan;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import androidx.annotation.ColorRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import net.osmand.PlatformUtil;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.BaseOsmAndDialogFragment;
import net.osmand.plus.chooseplan.ChoosePlanDialogFragment.OsmAndFeature;
import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.inapp.InAppPurchases.InAppSubscription;
import net.osmand.plus.settings.backend.OsmandPreference;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.widgets.TextViewEx;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
public abstract class OsmLiveGoneDialog extends BaseOsmAndDialogFragment {
public static final String TAG = OsmLiveGoneDialog.class.getName();
private static final Log LOG = PlatformUtil.getLog(OsmLiveGoneDialog.class);
private static final long TIME_BETWEEN_DIALOGS_MSEC = 1000 * 60 * 60 * 24 * 3; // 3 days
private OsmandApplication app;
private boolean nightMode;
private View osmLiveButton;
private final OsmAndFeature[] osmLiveFeatures = {
OsmAndFeature.DAILY_MAP_UPDATES,
OsmAndFeature.UNLIMITED_DOWNLOADS,
OsmAndFeature.WIKIPEDIA_OFFLINE,
OsmAndFeature.WIKIVOYAGE_OFFLINE,
OsmAndFeature.CONTOUR_LINES_HILLSHADE_MAPS,
OsmAndFeature.SEA_DEPTH_MAPS,
OsmAndFeature.UNLOCK_ALL_FEATURES,
};
public static class OsmLiveOnHoldDialog extends OsmLiveGoneDialog {
public static final String TAG = OsmLiveOnHoldDialog.class.getSimpleName();
@Override
protected OsmLiveButtonType getOsmLiveButtonType() {
return OsmLiveButtonType.MANAGE_SUBSCRIPTION;
}
@Override
protected String getTitle() {
return getString(R.string.subscription_on_hold_title);
}
@Override
protected String getSubscriptionDescr() {
return getString(R.string.subscription_payment_issue_title);
}
}
public static class OsmLivePausedDialog extends OsmLiveGoneDialog {
public static final String TAG = OsmLivePausedDialog.class.getSimpleName();
@Override
protected OsmLiveButtonType getOsmLiveButtonType() {
return OsmLiveButtonType.MANAGE_SUBSCRIPTION;
}
@Override
protected String getTitle() {
return getString(R.string.subscription_paused_title);
}
}
public static class OsmLiveExpiredDialog extends OsmLiveGoneDialog {
public static final String TAG = OsmLiveExpiredDialog.class.getSimpleName();
@Override
protected String getTitle() {
return getString(R.string.subscription_expired_title);
}
}
protected enum OsmLiveButtonType {
PURCHASE_SUBSCRIPTION,
MANAGE_SUBSCRIPTION
}
protected OsmLiveButtonType getOsmLiveButtonType() {
return OsmLiveButtonType.PURCHASE_SUBSCRIPTION;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = getMyApplication();
nightMode = isNightMode(getMapActivity() != null);
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Activity ctx = requireActivity();
int themeId = nightMode ? R.style.OsmandDarkTheme_DarkActionbar : R.style.OsmandLightTheme_DarkActionbar_LightStatusBar;
Dialog dialog = new Dialog(ctx, themeId);
Window window = dialog.getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
if (!getSettings().DO_NOT_USE_ANIMATIONS.get()) {
window.getAttributes().windowAnimations = R.style.Animations_Alpha;
}
if (Build.VERSION.SDK_INT >= 21) {
window.setStatusBarColor(ContextCompat.getColor(ctx, getStatusBarColor()));
}
}
return dialog;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Context ctx = getContext();
if (ctx == null) {
return null;
}
int themeRes = nightMode ? R.style.OsmandDarkTheme_DarkActionbar : R.style.OsmandLightTheme_DarkActionbar_LightStatusBar;
View view = LayoutInflater.from(new ContextThemeWrapper(getContext(), themeRes))
.inflate(R.layout.osmlive_gone_dialog_fragment, container, false);
view.findViewById(R.id.button_close).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
TextViewEx title = (TextViewEx) view.findViewById(R.id.title);
title.setText(getTitle());
TextViewEx infoDescr = (TextViewEx) view.findViewById(R.id.info_description);
StringBuilder descr = new StringBuilder();
String subscriptionDescr = getSubscriptionDescr();
if (!Algorithms.isEmpty(subscriptionDescr)) {
descr.append(subscriptionDescr).append("\n\n");
}
descr.append(getString(R.string.purchase_cancelled_dialog_descr));
for (OsmAndFeature feature : osmLiveFeatures) {
descr.append("\n").append("").append(feature.toHumanString(ctx));
}
infoDescr.setText(descr);
osmLiveButton = view.findViewById(R.id.card_button);
return view;
}
protected abstract String getTitle();
protected String getSubscriptionDescr() {
return null;
}
@Nullable
public MapActivity getMapActivity() {
Activity activity = getActivity();
if (activity instanceof MapActivity) {
return (MapActivity) activity;
}
return null;
}
@Override
public void onResume() {
super.onResume();
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.disableDrawer();
}
setupOsmLiveButton();
OsmandPreference<Long> firstTimeShownTime = app.getSettings().LIVE_UPDATES_EXPIRED_FIRST_DLG_SHOWN_TIME;
OsmandPreference<Long> secondTimeShownTime = app.getSettings().LIVE_UPDATES_EXPIRED_SECOND_DLG_SHOWN_TIME;
if (firstTimeShownTime.get() == 0) {
firstTimeShownTime.set(System.currentTimeMillis());
} else if (secondTimeShownTime.get() == 0) {
secondTimeShownTime.set(System.currentTimeMillis());
}
}
@Override
public void onPause() {
super.onPause();
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.enableDrawer();
}
}
@ColorRes
protected int getStatusBarColor() {
return nightMode ? R.color.status_bar_wikivoyage_dark : R.color.status_bar_wikivoyage_light;
}
private void setupOsmLiveButton() {
if (osmLiveButton != null) {
TextViewEx buttonTitle = (TextViewEx) osmLiveButton.findViewById(R.id.card_button_title);
TextViewEx buttonSubtitle = (TextViewEx) osmLiveButton.findViewById(R.id.card_button_subtitle);
switch (getOsmLiveButtonType()) {
case PURCHASE_SUBSCRIPTION:
buttonTitle.setText(getString(R.string.osm_live_plan_pricing));
osmLiveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
FragmentActivity activity = getActivity();
if (activity != null) {
ChoosePlanDialogFragment.showOsmLiveInstance(activity.getSupportFragmentManager());
}
}
});
break;
case MANAGE_SUBSCRIPTION:
buttonTitle.setText(getString(R.string.manage_subscription));
osmLiveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
FragmentActivity activity = getActivity();
if (activity != null) {
InAppSubscription expiredSubscription = getExpiredSubscription((OsmandApplication) activity.getApplication());
if (expiredSubscription != null) {
manageSubscription(expiredSubscription.getSku());
}
}
}
});
break;
}
buttonSubtitle.setVisibility(View.GONE);
buttonTitle.setVisibility(View.VISIBLE);
osmLiveButton.findViewById(R.id.card_button_progress).setVisibility(View.GONE);
}
}
private void manageSubscription(@Nullable String sku) {
Context ctx = getContext();
if (ctx != null) {
String url = "https://play.google.com/store/account/subscriptions?package=" + ctx.getPackageName();
if (!Algorithms.isEmpty(sku)) {
url += "&sku=" + sku;
}
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
}
}
@Nullable
private static InAppSubscription getExpiredSubscription(@NonNull OsmandApplication app) {
if (!app.getSettings().LIVE_UPDATES_PURCHASED.get()) {
InAppPurchaseHelper purchaseHelper = app.getInAppPurchaseHelper();
return purchaseHelper.getLiveUpdates().getTopExpiredSubscription();
}
return null;
}
public static boolean shouldShowDialog(@NonNull OsmandApplication app) {
InAppSubscription expiredSubscription = getExpiredSubscription(app);
if (expiredSubscription == null) {
return false;
}
OsmandSettings settings = app.getSettings();
long firstTimeShownTime = settings.LIVE_UPDATES_EXPIRED_FIRST_DLG_SHOWN_TIME.get();
long secondTimeShownTime = settings.LIVE_UPDATES_EXPIRED_SECOND_DLG_SHOWN_TIME.get();
return firstTimeShownTime == 0
|| (System.currentTimeMillis() - firstTimeShownTime > TIME_BETWEEN_DIALOGS_MSEC && secondTimeShownTime == 0);
}
public static void showInstance(@NonNull OsmandApplication app, @NonNull FragmentManager fm) {
try {
InAppSubscription expiredSubscription = getExpiredSubscription(app);
if (expiredSubscription == null) {
return;
}
String tag = null;
DialogFragment fragment = null;
switch (expiredSubscription.getState()) {
case ON_HOLD:
tag = OsmLiveOnHoldDialog.TAG;
if (fm.findFragmentByTag(tag) == null) {
fragment = new OsmLiveOnHoldDialog();
}
break;
case PAUSED:
tag = OsmLivePausedDialog.TAG;
if (fm.findFragmentByTag(tag) == null) {
fragment = new OsmLivePausedDialog();
}
break;
case EXPIRED:
tag = OsmLiveExpiredDialog.TAG;
if (fm.findFragmentByTag(tag) == null) {
fragment = new OsmLiveExpiredDialog();
}
break;
}
if (fragment != null) {
fragment.show(fm, tag);
}
} catch (RuntimeException e) {
LOG.error("showInstance", e);
}
}
}

View file

@ -20,6 +20,7 @@ import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import net.osmand.AndroidUtils;
import net.osmand.data.FavouritePoint;
@ -32,6 +33,8 @@ import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.FavoritesListFragment.FavouritesAdapter;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.mapcontextmenu.editors.FavoritePointEditor;
import net.osmand.plus.mapcontextmenu.editors.FavoritePointEditorFragmentNew;
import java.text.MessageFormat;
import java.util.ArrayList;
@ -79,20 +82,24 @@ public class FavoriteDialogs {
@Override
public void onClick(DialogInterface dialog, int which) {
if(dlgHolder != null && dlgHolder.length > 0 && dlgHolder[0] != null) {
if (dlgHolder != null && dlgHolder.length > 0 && dlgHolder[0] != null) {
dlgHolder[0].dismiss();
}
FavouritePoint point = (FavouritePoint) args.getSerializable(KEY_FAVORITE);
if (helper.editFavourite(fp, point.getLatitude(), point.getLongitude())) {
if (point != null && helper.editFavourite(fp, point.getLatitude(), point.getLongitude())) {
helper.deleteFavourite(point);
if (activity instanceof MapActivity) {
((MapActivity) activity).getContextMenu()
MapActivity mapActivity = (MapActivity) activity;
Fragment fragment = mapActivity.getSupportFragmentManager()
.findFragmentByTag(FavoritePointEditor.TAG);
if (fragment instanceof FavoritePointEditorFragmentNew) {
((FavoritePointEditorFragmentNew) fragment).exitEditing();
}
mapActivity.getContextMenu()
.show(new LatLon(point.getLatitude(), point.getLongitude()), fp.getPointDescription(activity), fp);
mapActivity.getMapView().refreshMap();
}
}
if (activity instanceof MapActivity) {
((MapActivity) activity).getMapView().refreshMap();
}
}
});
builder.show();

View file

@ -342,7 +342,7 @@ public class DownloadActivityType {
return FileNameTranslationHelper.getFontName(ctx, getBasename(indexItem));
}
final String basename = getBasename(indexItem);
if (basename.endsWith(FileNameTranslationHelper.WIKI_NAME)){
if (basename.endsWith(FileNameTranslationHelper.WIKI_NAME)) {
return FileNameTranslationHelper.getWikiName(ctx, basename);
}
// if (this == HILLSHADE_FILE){
@ -357,7 +357,7 @@ public class DownloadActivityType {
final int ind = basename.indexOf("addresses-nationwide");
String downloadName = basename.substring(0, ind - 1) + basename.substring(ind + "addresses-nationwide".length());
return osmandRegions.getLocaleName(downloadName, includingParent) +
" "+ ctx.getString(R.string.index_item_nation_addresses);
" " + ctx.getString(R.string.index_item_nation_addresses);
} else if (basename.startsWith("Depth_")) {
final int extInd = basename.indexOf("osmand_ext");
String downloadName = extInd == -1 ? basename.substring(6, basename.length()).replace('_', ' ')
@ -438,11 +438,11 @@ public class DownloadActivityType {
}
if (this == HILLSHADE_FILE) {
return fileName.substring(0, fileName.length() - IndexConstants.SQLITE_EXT.length())
.replace(FileNameTranslationHelper.HILL_SHADE, "");
.replace(FileNameTranslationHelper.HILL_SHADE + "_", "");
}
if (this == SLOPE_FILE) {
return fileName.substring(0, fileName.length() - IndexConstants.SQLITE_EXT.length())
.replace(FileNameTranslationHelper.SLOPE, "");
.replace(FileNameTranslationHelper.SLOPE + "_", "");
}
if (fileName.endsWith(IndexConstants.SQLITE_EXT)) {
return fileName.substring(0, fileName.length() - IndexConstants.SQLITE_EXT.length());

View file

@ -138,10 +138,10 @@ public class DownloadIndexesThread {
String setTts = null;
for (String s : OsmandSettings.TTS_AVAILABLE_VOICES) {
if (lng.startsWith(s)) {
setTts = s + "-tts";
setTts = s + IndexConstants.VOICE_PROVIDER_SUFFIX;
break;
} else if (lng.contains("," + s)) {
setTts = s + "-tts";
setTts = s + IndexConstants.VOICE_PROVIDER_SUFFIX;
}
}
if (setTts != null) {
@ -544,7 +544,7 @@ public class DownloadIndexesThread {
// validate enough space
if (asz != -1 && cs > asz) {
String breakDownloadMessage = app.getString(R.string.download_files_not_enough_space,
cs, asz);
String.valueOf(cs), String.valueOf(asz));
publishProgress(breakDownloadMessage);
return false;
}

View file

@ -8,9 +8,7 @@ import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import net.osmand.AndroidUtils;
@ -159,10 +157,13 @@ public class DownloadOsmandIndexesHelper {
List<AssetEntry> mapping = getBundledAssets(amanager);
for (AssetEntry asset : mapping) {
String target = asset.destination;
if (target.endsWith(IndexConstants.TTSVOICE_INDEX_EXT_JS) && target.startsWith("voice/") && target.contains("-tts")) {
String lang = target.substring("voice/".length(), target.indexOf("-tts"));
File destFile = new File(voicePath, target.substring("voice/".length(),
target.indexOf("/", "voice/".length())) + "/" + lang + "_tts.js");
if (target.endsWith(IndexConstants.TTSVOICE_INDEX_EXT_JS)
&& target.startsWith(IndexConstants.VOICE_INDEX_DIR)
&& target.contains(IndexConstants.VOICE_PROVIDER_SUFFIX)) {
String lang = target.substring(IndexConstants.VOICE_INDEX_DIR.length(),
target.indexOf(IndexConstants.VOICE_PROVIDER_SUFFIX));
File destFile = new File(voicePath, target.substring(IndexConstants.VOICE_INDEX_DIR.length(),
target.indexOf("/", IndexConstants.VOICE_INDEX_DIR.length())) + "/" + lang + "_tts.js");
result.add(new AssetIndexItem(lang + "_" + IndexConstants.TTSVOICE_INDEX_EXT_JS,
"voice", date, dateModified, "0.1", destFile.length(), asset.source,
destFile.getPath(), DownloadActivityType.VOICE_FILE));

View file

@ -143,9 +143,9 @@ public class IndexItem implements Comparable<IndexItem> {
public String getTranslatedBasename() {
if (type == DownloadActivityType.HILLSHADE_FILE) {
return (FileNameTranslationHelper.HILL_SHADE + getBasename()).replace("_", " ");
return (FileNameTranslationHelper.HILL_SHADE + "_" + getBasename()).replace("_", " ");
} else if (type == DownloadActivityType.SLOPE_FILE) {
return (FileNameTranslationHelper.SLOPE + getBasename()).replace('_', ' ');
return (FileNameTranslationHelper.SLOPE + "_" + getBasename()).replace('_', ' ');
} else {
return getBasename();
}

View file

@ -7,8 +7,6 @@ import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@ -19,7 +17,6 @@ import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
@ -45,7 +42,6 @@ import net.osmand.plus.ContextMenuAdapter;
import net.osmand.plus.ContextMenuAdapter.ItemClickListener;
import net.osmand.plus.ContextMenuItem;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.SQLiteTileSource;
import net.osmand.plus.UiUtilities;
@ -127,19 +123,6 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
if (asyncLoader == null || asyncLoader.getResult() == null) {
reloadData();
}
getExpandableListView().setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
long packedPos = ((ExpandableListContextMenuInfo) menuInfo).packedPosition;
int group = ExpandableListView.getPackedPositionGroup(packedPos);
int child = ExpandableListView.getPackedPositionChild(packedPos);
if (child >= 0 && group >= 0) {
final LocalIndexInfo point = listAdapter.getChild(group, child);
showContextMenu(point);
}
}
});
}
public void reloadData() {
@ -156,62 +139,6 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
}
}
private void showContextMenu(final LocalIndexInfo info) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
final ContextMenuAdapter adapter = new ContextMenuAdapter(getMyApplication());
basicFileOperation(info, adapter);
OsmandPlugin.onContextMenuActivity(getActivity(), null, info, adapter);
String[] values = adapter.getItemNames();
builder.setItems(values, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ContextMenuItem item = adapter.getItem(which);
if (item.getItemClickListener() != null) {
item.getItemClickListener().onContextMenuClick(null,
item.getTitleId(), which, false, null);
}
}
});
builder.show();
}
private void basicFileOperation(final LocalIndexInfo info, ContextMenuAdapter adapter) {
ItemClickListener listener = new ItemClickListener() {
@Override
public boolean onContextMenuClick(ArrayAdapter<ContextMenuItem> adapter, int resId, int pos, boolean isChecked, int[] viewCoordinates) {
return performBasicOperation(resId, info);
}
};
if (info.getType() == LocalIndexType.MAP_DATA || info.getType() == LocalIndexType.SRTM_DATA ||
info.getType() == LocalIndexType.WIKI_DATA ) {
if (!info.isBackupedData()) {
adapter.addItem(new ContextMenuItem.ItemBuilder()
.setTitleId(R.string.local_index_mi_backup, getContext())
.setListener(listener)
.createItem());
}
}
if (info.isBackupedData()) {
adapter.addItem(new ContextMenuItem.ItemBuilder()
.setTitleId(R.string.local_index_mi_restore, getContext())
.setListener(listener)
.createItem());
}
if (info.getType() != LocalIndexType.TTS_VOICE_DATA && info.getType() != LocalIndexType.VOICE_DATA
&& info.getType() != LocalIndexType.FONT_DATA) {
adapter.addItem(new ContextMenuItem.ItemBuilder()
.setTitleId(R.string.shared_string_rename, getContext())
.setListener(listener)
.createItem());
}
adapter.addItem(new ContextMenuItem.ItemBuilder()
.setTitleId(R.string.shared_string_delete, getContext())
.setListener(listener)
.createItem());
}
private boolean performBasicOperation(int resId, final LocalIndexInfo info) {
if (resId == R.string.shared_string_rename) {
FileUtils.renameFile(getActivity(), new File(info.getPathToData()), new RenameCallback() {

View file

@ -0,0 +1,30 @@
package net.osmand.plus.helpers;
import android.graphics.RectF;
import androidx.annotation.NonNull;
import com.github.mikephil.charting.charts.BarChart;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.renderer.HorizontalBarChartRenderer;
import net.osmand.AndroidUtils;
public class CustomBarChartRenderer extends HorizontalBarChartRenderer {
private float highlightHalfWidth;
public CustomBarChartRenderer(@NonNull BarChart chart) {
this(chart, AndroidUtils.dpToPx(chart.getContext(), 1f) / 2f);
}
public CustomBarChartRenderer(@NonNull BarChart chart, float highlightHalfWidth) {
super(chart, chart.getAnimator(), chart.getViewPortHandler());
this.highlightHalfWidth = highlightHalfWidth;
}
@Override
protected void setHighlightDrawPos(Highlight high, RectF bar) {
bar.left = high.getDrawX() - highlightHalfWidth;
bar.right = high.getDrawX() + highlightHalfWidth;
}
}

View file

@ -4,6 +4,7 @@ import android.content.Context;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.map.OsmandRegions;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.download.DownloadResources;
@ -18,10 +19,14 @@ import java.lang.reflect.Field;
public class FileNameTranslationHelper {
private static final Log LOG = PlatformUtil.getLog(FileNameTranslationHelper.class);
public static final String WIKI_NAME = "_wiki";
public static final String HILL_SHADE = "Hillshade_";
public static final String SLOPE = "Slope_";
public static final String HILL_SHADE = "Hillshade";
public static final String SLOPE = "Slope";
public static final String SEA_DEPTH = "Depth_";
public static String getFileNameWithRegion(OsmandApplication app, String fileName) {
return getFileName(app, app.getResourceManager().getOsmandRegions(), fileName);
}
public static String getFileName(Context ctx, OsmandRegions regions, String fileName) {
String basename = getBasename(fileName);
if (basename.endsWith(WIKI_NAME)) { //wiki files
@ -30,13 +35,15 @@ public class FileNameTranslationHelper {
return getVoiceName(ctx, fileName);
} else if (fileName.endsWith(IndexConstants.FONT_INDEX_EXT)) { //otf files
return getFontName(ctx, basename);
} else if (fileName.startsWith(HILL_SHADE)){
} else if (fileName.startsWith(HILL_SHADE)) {
basename = basename.replace(HILL_SHADE + " ", "");
return getTerrainName(ctx, regions, basename, R.string.download_hillshade_maps);
} else if (fileName.startsWith(SLOPE)) {
basename = basename.replace(SLOPE + " ", "");
return getTerrainName(ctx, regions, basename, R.string.download_slope_maps);
} else if (fileName.length() == 2) { //voice recorded files
try {
Field f = R.string.class.getField("lang_"+fileName);
Field f = R.string.class.getField("lang_" + fileName);
if (f != null) {
Integer in = (Integer) f.get(null);
return ctx.getString(in);
@ -62,9 +69,10 @@ public class FileNameTranslationHelper {
public static String getTerrainName(Context ctx, OsmandRegions regions, String basename,
int terrainNameRes) {
String terrain = ctx.getString(terrainNameRes) + " ";
basename = basename.replace(" ", "_");
String terrain = ctx.getString(terrainNameRes);
String locName = regions.getLocaleName(basename.trim(), true);
return terrain + locName;
return ctx.getString(R.string.ltr_or_rtl_combine_via_space, locName, "(" + terrain + ")");
}
public static String getWikiName(Context ctx, String basename){
@ -85,10 +93,10 @@ public class FileNameTranslationHelper {
public static String getVoiceName(Context ctx, String fileName) {
try {
String nm = fileName.replace('-', '_').replace(' ', '_');
if (nm.endsWith("_tts") || nm.endsWith("-tts")) {
if (nm.endsWith("_tts") || nm.endsWith(IndexConstants.VOICE_PROVIDER_SUFFIX)) {
nm = nm.substring(0, nm.length() - 4);
}
Field f = R.string.class.getField("lang_"+nm);
Field f = R.string.class.getField("lang_" + nm);
if (f != null) {
Integer in = (Integer) f.get(null);
return ctx.getString(in);

View file

@ -76,6 +76,8 @@ import net.osmand.plus.ContextMenuAdapter;
import net.osmand.plus.ContextMenuItem;
import net.osmand.plus.GPXDatabase.GpxDataItem;
import net.osmand.plus.GpxDbHelper.GpxDataItemCallback;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayGroup;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.OsmAndConstants;
import net.osmand.plus.OsmAndFormatter;
@ -2045,6 +2047,91 @@ public class GpxUiHelper {
return gpx;
}
public enum LineGraphType {
ALTITUDE,
SLOPE,
SPEED;
}
public static List<ILineDataSet> getDataSets(LineChart chart,
OsmandApplication app,
GPXTrackAnalysis analysis,
@NonNull LineGraphType firstType,
@Nullable LineGraphType secondType,
boolean calcWithoutGaps) {
if (app == null || chart == null || analysis == null) {
return new ArrayList<>();
}
List<ILineDataSet> result = new ArrayList<>();
if (secondType == null) {
ILineDataSet dataSet = getDataSet(chart, app, analysis, calcWithoutGaps, false, firstType);
if (dataSet != null) {
result.add(dataSet);
}
} else {
OrderedLineDataSet dataSet1 = getDataSet(chart, app, analysis, calcWithoutGaps, false, firstType);
OrderedLineDataSet dataSet2 = getDataSet(chart, app, analysis, calcWithoutGaps, true, secondType);
if (dataSet1 == null && dataSet2 == null) {
return new ArrayList<>();
} else if (dataSet1 == null) {
result.add(dataSet2);
} else if (dataSet2 == null) {
result.add(dataSet1);
} else if (dataSet1.getPriority() < dataSet2.getPriority()) {
result.add(dataSet2);
result.add(dataSet1);
} else {
result.add(dataSet1);
result.add(dataSet2);
}
}
return result;
}
private static OrderedLineDataSet getDataSet(@NonNull LineChart chart,
@NonNull OsmandApplication app,
@NonNull GPXTrackAnalysis analysis,
boolean calcWithoutGaps,
boolean useRightAxis,
@NonNull LineGraphType type) {
OrderedLineDataSet dataSet = null;
switch (type) {
case ALTITUDE: {
if (analysis.hasElevationData) {
dataSet = GpxUiHelper.createGPXElevationDataSet(app, chart,
analysis, GPXDataSetAxisType.DISTANCE, useRightAxis, true, calcWithoutGaps);
}
break;
}
case SLOPE:
if (analysis.hasElevationData) {
dataSet = GpxUiHelper.createGPXSlopeDataSet(app, chart,
analysis, GPXDataSetAxisType.DISTANCE, null, useRightAxis, true, calcWithoutGaps);
}
break;
case SPEED: {
if (analysis.hasSpeedData) {
dataSet = GpxUiHelper.createGPXSpeedDataSet(app, chart,
analysis, GPXDataSetAxisType.DISTANCE, useRightAxis, true, calcWithoutGaps);
}
break;
}
}
return dataSet;
}
public static GpxDisplayItem makeGpxDisplayItem(OsmandApplication app, GPXUtilities.GPXFile gpx) {
GpxDisplayItem gpxItem = null;
String groupName = app.getString(R.string.current_route);
GpxDisplayGroup group = app.getSelectedGpxHelper().buildGpxDisplayGroup(gpx, 0, groupName);
if (group != null && group.getModifiableList().size() > 0) {
gpxItem = group.getModifiableList().get(0);
if (gpxItem != null) {
gpxItem.route = true;
}
}
return gpxItem;
}
public static class GPXInfo {

View file

@ -17,13 +17,12 @@ import net.osmand.AndroidNetworkUtils.OnRequestsResultListener;
import net.osmand.AndroidNetworkUtils.RequestResponse;
import net.osmand.PlatformUtil;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.settings.backend.OsmandPreference;
import net.osmand.plus.R;
import net.osmand.plus.Version;
import net.osmand.plus.inapp.InAppPurchases.InAppPurchase;
import net.osmand.plus.inapp.InAppPurchases.InAppPurchase.PurchaseState;
import net.osmand.plus.inapp.InAppPurchases.InAppSubscription;
import net.osmand.plus.inapp.InAppPurchases.InAppSubscription.SubscriptionState;
import net.osmand.plus.inapp.InAppPurchases.InAppSubscriptionList;
import net.osmand.plus.liveupdates.CountrySelectionFragment;
import net.osmand.plus.liveupdates.CountrySelectionFragment.CountryItem;
@ -50,11 +49,10 @@ public abstract class InAppPurchaseHelper {
private static final String TAG = InAppPurchaseHelper.class.getSimpleName();
private boolean mDebugLog = false;
public static final long SUBSCRIPTION_HOLDING_TIME_MSEC = 1000 * 60 * 60 * 24 * 3; // 3 days
protected InAppPurchases purchases;
protected long lastValidationCheckTime;
protected boolean inventoryRequested;
protected Map<String, SubscriptionState> subscriptionStateMap = new HashMap<>();
private static final long PURCHASE_VALIDATION_PERIOD_MSEC = 1000 * 60 * 60 * 24; // daily
@ -375,21 +373,33 @@ public abstract class InAppPurchaseHelper {
final String sku, final String payload) throws UnsupportedOperationException;
@SuppressLint("StaticFieldLeak")
private class RequestInventoryTask extends AsyncTask<Void, Void, String> {
private class RequestInventoryTask extends AsyncTask<Void, Void, String[]> {
RequestInventoryTask() {
}
@Override
protected String doInBackground(Void... params) {
protected String[] doInBackground(Void... params) {
try {
Map<String, String> parameters = new HashMap<>();
parameters.put("androidPackage", ctx.getPackageName());
addUserInfo(parameters);
return AndroidNetworkUtils.sendRequest(ctx,
String activeSubscriptionsIds = AndroidNetworkUtils.sendRequest(ctx,
"https://osmand.net/api/subscriptions/active",
parameters, "Requesting active subscriptions...", false, false);
String subscriptionsState = null;
String userId = ctx.getSettings().BILLING_USER_ID.get();
String userToken = ctx.getSettings().BILLING_USER_TOKEN.get();
if (!Algorithms.isEmpty(userId) && !Algorithms.isEmpty(userToken)) {
parameters.put("userId", userId);
parameters.put("userToken", userToken);
subscriptionsState = AndroidNetworkUtils.sendRequest(ctx,
"https://osmand.net/api/subscriptions/get",
parameters, "Requesting subscriptions state...", false, false);
}
return new String[] { activeSubscriptionsIds, subscriptionsState };
} catch (Exception e) {
logError("sendRequest Error", e);
}
@ -397,12 +407,14 @@ public abstract class InAppPurchaseHelper {
}
@Override
protected void onPostExecute(String response) {
logDebug("Response=" + response);
if (response != null) {
protected void onPostExecute(String[] response) {
logDebug("Response=" + Arrays.toString(response));
String activeSubscriptionsIdsJson = response[0];
String subscriptionsStateJson = response[1];
if (activeSubscriptionsIdsJson != null) {
inventoryRequested = true;
try {
JSONObject obj = new JSONObject(response);
JSONObject obj = new JSONObject(activeSubscriptionsIdsJson);
JSONArray names = obj.names();
if (names != null) {
for (int i = 0; i < names.length(); i++) {
@ -418,6 +430,24 @@ public abstract class InAppPurchaseHelper {
logError("Json parsing error", e);
}
}
if (subscriptionsStateJson != null) {
inventoryRequested = true;
Map<String, SubscriptionState> subscriptionStateMap = new HashMap<>();
try {
JSONArray subArrJson = new JSONArray(subscriptionsStateJson);
for (int i = 0; i < subArrJson.length(); i++) {
JSONObject subObj = subArrJson.getJSONObject(i);
String sku = subObj.getString("sku");
String state = subObj.getString("state");
if (!Algorithms.isEmpty(sku) && !Algorithms.isEmpty(state)) {
subscriptionStateMap.put(sku, SubscriptionState.getByStateStr(state));
}
}
} catch (JSONException e) {
logError("Json parsing error", e);
}
InAppPurchaseHelper.this.subscriptionStateMap = subscriptionStateMap;
}
exec(InAppPurchaseTaskType.REQUEST_INVENTORY, getRequestInventoryCommand());
}
}
@ -467,9 +497,8 @@ public abstract class InAppPurchaseHelper {
ctx.getSettings().LIVE_UPDATES_PURCHASED.set(true);
ctx.getSettings().getCustomRenderBooleanProperty("depthContours").set(true);
ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_TIME.set(0L);
ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_FIRST_DLG_SHOWN.set(false);
ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_SECOND_DLG_SHOWN.set(false);
ctx.getSettings().LIVE_UPDATES_EXPIRED_FIRST_DLG_SHOWN_TIME.set(0L);
ctx.getSettings().LIVE_UPDATES_EXPIRED_SECOND_DLG_SHOWN_TIME.set(0L);
notifyDismissProgress(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES);
notifyItemPurchased(sku, active);

View file

@ -24,6 +24,8 @@ import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Currency;
import java.util.List;
import java.util.Locale;
@ -190,6 +192,28 @@ public abstract class InAppPurchases {
}
return null;
}
@Nullable
public InAppSubscription getTopExpiredSubscription() {
List<InAppSubscription> expiredSubscriptions = new ArrayList<>();
for (InAppSubscription s : getAllSubscriptions()) {
if (s.getState().isGone()) {
expiredSubscriptions.add(s);
}
}
Collections.sort(expiredSubscriptions, new Comparator<InAppSubscription>() {
@Override
public int compare(InAppSubscription s1, InAppSubscription s2) {
int orderS1 = s1.getState().ordinal();
int orderS2 = s2.getState().ordinal();
if (orderS1 != orderS2) {
return (orderS1 < orderS2) ? -1 : ((orderS1 == orderS2) ? 0 : 1);
}
return Double.compare(s1.getMonthlyPriceValue(), s2.getMonthlyPriceValue());
}
});
return expiredSubscriptions.isEmpty() ? null : expiredSubscriptions.get(0);
}
}
public abstract static class InAppPurchase {
@ -554,9 +578,49 @@ public abstract class InAppPurchases {
private String subscriptionPeriodString;
private Period subscriptionPeriod;
private boolean upgrade = false;
private SubscriptionState state = SubscriptionState.UNDEFINED;
private SubscriptionState prevState = SubscriptionState.UNDEFINED;
private InAppSubscriptionIntroductoryInfo introductoryInfo;
public enum SubscriptionState {
UNDEFINED("undefined"),
ACTIVE("active"),
CANCELLED("cancelled"),
IN_GRACE_PERIOD("in_grace_period"),
ON_HOLD("on_hold"),
PAUSED("paused"),
EXPIRED("expired");
private final String stateStr;
SubscriptionState(@NonNull String stateStr) {
this.stateStr = stateStr;
}
public String getStateStr() {
return stateStr;
}
@NonNull
public static SubscriptionState getByStateStr(@NonNull String stateStr) {
for (SubscriptionState state : SubscriptionState.values()) {
if (state.stateStr.equals(stateStr)) {
return state;
}
}
return UNDEFINED;
}
public boolean isGone() {
return this == ON_HOLD || this == PAUSED || this == EXPIRED;
}
public boolean isActive() {
return this == ACTIVE || this == CANCELLED || this == IN_GRACE_PERIOD;
}
}
InAppSubscription(@NonNull String skuNoVersion, int version) {
super(skuNoVersion + "_v" + version);
this.skuNoVersion = skuNoVersion;
@ -592,6 +656,28 @@ public abstract class InAppPurchases {
return upgrade;
}
@NonNull
public SubscriptionState getState() {
return state;
}
public void setState(@NonNull SubscriptionState state) {
this.state = state;
}
@NonNull
public SubscriptionState getPrevState() {
return prevState;
}
public void setPrevState(@NonNull SubscriptionState prevState) {
this.prevState = prevState;
}
public boolean hasStateChanged() {
return state != prevState;
}
public boolean isAnyPurchased() {
if (isPurchased()) {
return true;

View file

@ -495,7 +495,7 @@ public abstract class ImageCard extends AbstractCard {
}
}
} catch (Exception e) {
e.printStackTrace();
LOG.error(e);
}
if (listener != null) {
listener.onPostProcess(result);

View file

@ -22,6 +22,7 @@ import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
@ -52,6 +53,10 @@ import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.ColorDialogs;
import net.osmand.plus.mapcontextmenu.MapContextMenu;
import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter;
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener;
import net.osmand.plus.track.ColorsCard;
import net.osmand.plus.track.CustomColorBottomSheet.ColorPickerListener;
import net.osmand.plus.widgets.FlowLayout;
import net.osmand.util.Algorithms;
@ -72,7 +77,7 @@ import static net.osmand.data.FavouritePoint.DEFAULT_UI_ICON_ID;
import static net.osmand.plus.FavouritesDbHelper.FavoriteGroup.PERSONAL_CATEGORY;
import static net.osmand.plus.FavouritesDbHelper.FavoriteGroup.isPersonalCategoryDisplayName;
public abstract class PointEditorFragmentNew extends BaseOsmAndFragment {
public abstract class PointEditorFragmentNew extends BaseOsmAndFragment implements ColorPickerListener, CardListener {
public static final String TAG = PointEditorFragmentNew.class.getSimpleName();
@ -101,6 +106,7 @@ public abstract class PointEditorFragmentNew extends BaseOsmAndFragment {
private EditText descriptionEdit;
private EditText addressEdit;
private int layoutHeightPrevious = 0;
private ColorsCard colorsCard;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@ -458,48 +464,49 @@ public abstract class PointEditorFragmentNew extends BaseOsmAndFragment {
}
private void createColorSelector() {
FlowLayout selectColor = view.findViewById(R.id.select_color);
for (int color : ColorDialogs.pallette) {
selectColor.addView(createColorItemView(color, selectColor), new FlowLayout.LayoutParams(0, 0));
}
int customColor = getPointColor();
if (!ColorDialogs.isPaletteColor(customColor)) {
selectColor.addView(createColorItemView(customColor, selectColor), new FlowLayout.LayoutParams(0, 0));
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
List<Integer> colors = new ArrayList<>();
for (int color : ColorDialogs.pallette) {
colors.add(color);
}
int customColor = getPointColor();
if (!ColorDialogs.isPaletteColor(customColor)) {
colors.add(customColor);
}
colorsCard = new ColorsCard(mapActivity, selectedColor, this, colors);
colorsCard.setListener(this);
LinearLayout selectColor = view.findViewById(R.id.select_color);
selectColor.addView(colorsCard.build(view.getContext()));
}
}
private View createColorItemView(@ColorInt final int color, final FlowLayout rootView) {
FrameLayout colorItemView = (FrameLayout) UiUtilities.getInflater(getContext(), nightMode)
.inflate(R.layout.point_editor_button, rootView, false);
ImageView outline = colorItemView.findViewById(R.id.outline);
outline.setImageDrawable(
UiUtilities.tintDrawable(AppCompatResources.getDrawable(app, R.drawable.bg_point_circle_contour),
ContextCompat.getColor(app,
nightMode ? R.color.stroked_buttons_and_links_outline_dark
: R.color.stroked_buttons_and_links_outline_light)));
ImageView backgroundCircle = colorItemView.findViewById(R.id.background);
backgroundCircle.setImageDrawable(UiUtilities.tintDrawable(AppCompatResources.getDrawable(app, R.drawable.bg_point_circle), color));
backgroundCircle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
updateColorSelector(color, rootView);
}
});
colorItemView.setTag(color);
return colorItemView;
@Override
public void onColorSelected(Integer prevColor, int newColor) {
colorsCard.onColorSelected(prevColor, newColor);
int color = colorsCard.getSelectedColor();
updateColorSelector(color, view);
}
@Override
public void onCardLayoutNeeded(@NonNull BaseCard card) {
}
@Override
public void onCardPressed(@NonNull BaseCard card) {
if (card instanceof ColorsCard) {
int color = ((ColorsCard) card).getSelectedColor();
updateColorSelector(color, view);
}
}
@Override
public void onCardButtonPressed(@NonNull BaseCard card, int buttonIndex) {
}
private void updateColorSelector(int color, View rootView) {
View oldColor = rootView.findViewWithTag(selectedColor);
if (oldColor != null) {
oldColor.findViewById(R.id.outline).setVisibility(View.INVISIBLE);
ImageView icon = oldColor.findViewById(R.id.icon);
icon.setImageDrawable(UiUtilities.tintDrawable(icon.getDrawable(), R.color.icon_color_default_light));
}
View newColor = rootView.findViewWithTag(color);
if (newColor != null) {
newColor.findViewById(R.id.outline).setVisibility(View.VISIBLE);
}
((TextView) view.findViewById(R.id.color_name)).setText(ColorDialogs.getColorName(color));
selectedColor = color;
setColor(color);
@ -935,7 +942,7 @@ public abstract class PointEditorFragmentNew extends BaseOsmAndFragment {
}
}
private void exitEditing() {
public void exitEditing() {
cancelled = true;
dismiss();
}

View file

@ -125,8 +125,7 @@ public class TrackDetailsMenu {
hidding = true;
fragment.dismiss(backPressed);
} else {
segment = null;
trackChartPoints = null;
reset();
}
}
@ -274,8 +273,7 @@ public class TrackDetailsMenu {
if (hidding) {
hidding = false;
visible = false;
segment = null;
trackChartPoints = null;
reset();
}
}
@ -532,6 +530,11 @@ public class TrackDetailsMenu {
fitTrackOnMap(chart, location, forceFit);
}
public void reset() {
segment = null;
trackChartPoints = null;
}
private List<LatLon> getXAxisPoints(LineChart chart) {
float[] entries = chart.getXAxis().mEntries;
LineData lineData = chart.getLineData();

View file

@ -1,11 +1,14 @@
package net.osmand.plus.measurementtool;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -16,15 +19,23 @@ import com.github.mikephil.charting.data.ChartData;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
import net.osmand.AndroidUtils;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetAxisType;
import net.osmand.plus.helpers.GpxUiHelper.OrderedLineDataSet;
import net.osmand.plus.helpers.GpxUiHelper.LineGraphType;
import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter;
import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter.HorizontalSelectionAdapterListener;
import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu;
import net.osmand.plus.measurementtool.MeasurementToolFragment.OnUpdateAdditionalInfoListener;
import net.osmand.plus.measurementtool.graph.CommonGraphAdapter;
import net.osmand.plus.measurementtool.graph.CustomGraphAdapter;
import net.osmand.plus.measurementtool.graph.CustomGraphAdapter.LegendViewType;
import net.osmand.plus.measurementtool.graph.BaseGraphAdapter;
import net.osmand.plus.measurementtool.graph.GraphAdapterHelper;
import net.osmand.plus.measurementtool.graph.GraphAdapterHelper.RefreshMapCallback;
import net.osmand.plus.routepreparationmenu.RouteDetailsFragment;
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
import net.osmand.router.RouteSegmentResult;
@ -32,48 +43,44 @@ import net.osmand.util.Algorithms;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static net.osmand.GPXUtilities.GPXFile;
import static net.osmand.GPXUtilities.GPXTrackAnalysis;
import static net.osmand.plus.helpers.GpxUiHelper.LineGraphType.ALTITUDE;
import static net.osmand.plus.helpers.GpxUiHelper.LineGraphType.SLOPE;
import static net.osmand.plus.helpers.GpxUiHelper.LineGraphType.SPEED;
import static net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter.HorizontalSelectionItem;
import static net.osmand.router.RouteStatisticsHelper.RouteStatistics;
public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListener {
private static String GRAPH_DATA_GPX_FILE_NAME = "graph_data_tmp";
private static int INVALID_ID = -1;
private MeasurementEditingContext editingCtx;
private MeasurementToolFragment fragment;
private GraphType visibleGraphType;
private List<GraphType> graphTypes = new ArrayList<>();
private TrackDetailsMenu trackDetailsMenu;
private RefreshMapCallback refreshMapCallback;
private GPXFile gpxFile;
private GPXTrackAnalysis analysis;
private GpxDisplayItem gpxItem;
private View commonGraphContainer;
private View customGraphContainer;
private View messageContainer;
private LineChart commonGraphChart;
private HorizontalBarChart customGraphChart;
private CommonGraphAdapter commonGraphAdapter;
private CustomGraphAdapter customGraphAdapter;
private RecyclerView graphTypesMenu;
private enum CommonGraphType {
OVERVIEW(R.string.shared_string_overview, false),
ALTITUDE(R.string.altitude, true),
SLOPE(R.string.shared_string_slope, true),
SPEED(R.string.map_widget_speed, false);
private GraphType visibleType;
private List<GraphType> graphTypes = new ArrayList<>();
CommonGraphType(int titleId, boolean canBeCalculated) {
this.titleId = titleId;
this.canBeCalculated = canBeCalculated;
}
final int titleId;
final boolean canBeCalculated;
}
public GraphsCard(@NonNull MapActivity mapActivity, MeasurementToolFragment fragment) {
public GraphsCard(@NonNull MapActivity mapActivity,
TrackDetailsMenu trackDetailsMenu,
MeasurementToolFragment fragment) {
super(mapActivity);
this.trackDetailsMenu = trackDetailsMenu;
this.fragment = fragment;
}
@ -82,19 +89,27 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen
if (mapActivity == null || fragment == null) return;
editingCtx = fragment.getEditingCtx();
graphTypesMenu = view.findViewById(R.id.graph_types_recycler_view);
graphTypesMenu.setLayoutManager(new LinearLayoutManager(mapActivity, RecyclerView.HORIZONTAL, false));
commonGraphContainer = view.findViewById(R.id.common_graphs_container);
customGraphContainer = view.findViewById(R.id.custom_graphs_container);
messageContainer = view.findViewById(R.id.message_container);
commonGraphChart = (LineChart) view.findViewById(R.id.line_chart);
customGraphChart = (HorizontalBarChart) view.findViewById(R.id.horizontal_chart);
updateGraphData();
LineChart lineChart = (LineChart) view.findViewById(R.id.line_chart);
HorizontalBarChart barChart = (HorizontalBarChart) view.findViewById(R.id.horizontal_chart);
commonGraphAdapter = new CommonGraphAdapter(lineChart, true);
customGraphAdapter = new CustomGraphAdapter(barChart, true);
graphTypesMenu = view.findViewById(R.id.graph_types_recycler_view);
graphTypesMenu.setLayoutManager(
new LinearLayoutManager(mapActivity, RecyclerView.HORIZONTAL, false));
customGraphAdapter.setLegendContainer((ViewGroup) view.findViewById(R.id.route_legend));
customGraphAdapter.setLayoutChangeListener(new BaseGraphAdapter.LayoutChangeListener() {
@Override
public void onLayoutChanged() {
setLayoutNeeded();
}
});
refreshGraphTypesSelectionMenu();
updateDataView();
GraphAdapterHelper.bindGraphAdapters(commonGraphAdapter, Collections.singletonList((BaseGraphAdapter) customGraphAdapter), (ViewGroup) view);
refreshMapCallback = GraphAdapterHelper.bindToMap(commonGraphAdapter, mapActivity, trackDetailsMenu);
fullUpdate();
}
@Override
@ -104,15 +119,32 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen
@Override
public void onUpdateAdditionalInfo() {
if (!isRouteCalculating()) {
updateGraphData();
refreshGraphTypesSelectionMenu();
if (editingCtx != null) {
fullUpdate();
}
updateDataView();
}
private void refreshGraphTypesSelectionMenu() {
graphTypesMenu.removeAllViews();
private void fullUpdate() {
if (!isRouteCalculating()) {
updateData();
setupVisibleType();
updateMenu();
}
updateView();
updateChartOnMap();
}
private void updateMenu() {
if (!editingCtx.isPointsEnoughToCalculateRoute()) {
graphTypesMenu.setVisibility(View.GONE);
} else {
graphTypesMenu.setVisibility(View.VISIBLE);
graphTypesMenu.removeAllViews();
fillInMenu();
}
}
private void fillInMenu() {
OsmandApplication app = getMyApplication();
int activeColorId = nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light;
final HorizontalSelectionAdapter adapter = new HorizontalSelectionAdapter(app, nightMode);
@ -127,16 +159,16 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen
}
}
adapter.setItems(items);
String selectedItemKey = visibleGraphType.getTitle();
String selectedItemKey = visibleType.getTitle();
adapter.setSelectedItemByTitle(selectedItemKey);
adapter.setListener(new HorizontalSelectionAdapter.HorizontalSelectionAdapterListener() {
adapter.setListener(new HorizontalSelectionAdapterListener() {
@Override
public void onItemSelected(HorizontalSelectionAdapter.HorizontalSelectionItem item) {
public void onItemSelected(HorizontalSelectionItem item) {
adapter.setItems(items);
adapter.setSelectedItem(item);
GraphType chosenGraphType = (GraphType) item.getObject();
if (!isCurrentVisibleType(chosenGraphType)) {
setupVisibleGraphType(chosenGraphType);
GraphType chosenType = (GraphType) item.getObject();
if (!isVisibleType(chosenType)) {
changeVisibleType(chosenType);
}
}
});
@ -144,19 +176,19 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen
adapter.notifyDataSetChanged();
}
private void setupVisibleGraphType(GraphType type) {
visibleGraphType = type;
updateDataView();
private void changeVisibleType(GraphType type) {
visibleType = type;
updateView();
}
private boolean isCurrentVisibleType(GraphType type) {
if (visibleGraphType != null && type != null) {
return Algorithms.objectEquals(visibleGraphType.getTitle(), type.getTitle());
private boolean isVisibleType(GraphType type) {
if (visibleType != null && type != null) {
return Algorithms.objectEquals(visibleType.getTitle(), type.getTitle());
}
return false;
}
private GraphType getFirstAvailableGraphType() {
private GraphType getFirstAvailableType() {
for (GraphType type : graphTypes) {
if (type.isAvailable()) {
return type;
@ -165,208 +197,181 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen
return null;
}
private void updateDataView() {
if (isRouteCalculating()) {
showProgressMessage();
} else if (visibleGraphType.hasData()) {
private void updateView() {
hideAll();
if (!editingCtx.isPointsEnoughToCalculateRoute()) {
showMessage(app.getString(R.string.message_you_need_add_two_points_to_show_graphs));
} else if (isRouteCalculating()) {
showMessage(app.getString(R.string.message_graph_will_be_available_after_recalculation), true);
} else if (visibleType.hasData()) {
showGraph();
} else if (visibleGraphType.canBeCalculated()) {
showMessage();
} else if (visibleType.canBeCalculated()) {
showMessage(app.getString(R.string.message_need_calculate_route_before_show_graph,
visibleType.getTitle()), R.drawable.ic_action_altitude_average,
app.getString(R.string.route_between_points), new View.OnClickListener() {
@Override
public void onClick(View v) {
fragment.startSnapToRoad(false);
}
});
}
}
private void showProgressMessage() {
private void hideAll() {
commonGraphContainer.setVisibility(View.GONE);
customGraphContainer.setVisibility(View.GONE);
messageContainer.setVisibility(View.GONE);
}
private void showMessage(String text) {
showMessage(text, INVALID_ID, false, null, null);
}
private void showMessage(String text, @DrawableRes int iconResId, String btnTitle, View.OnClickListener btnListener) {
showMessage(text, iconResId, false, btnTitle, btnListener);
}
private void showMessage(String text, boolean showProgressBar) {
showMessage(text, INVALID_ID, showProgressBar, null, null);
}
private void showMessage(@NonNull String text,
@DrawableRes int iconResId,
boolean showProgressBar,
String btnTitle,
View.OnClickListener btnListener) {
messageContainer.setVisibility(View.VISIBLE);
TextView tvMessage = messageContainer.findViewById(R.id.message_text);
tvMessage.setText(text);
ImageView icon = messageContainer.findViewById(R.id.message_icon);
if (iconResId != INVALID_ID) {
icon.setVisibility(View.VISIBLE);
icon.setImageResource(iconResId);
} else {
icon.setVisibility(View.GONE);
}
ProgressBar pb = messageContainer.findViewById(R.id.progress_bar);
pb.setVisibility(View.VISIBLE);
icon.setVisibility(View.GONE);
tvMessage.setText(R.string.message_graph_will_be_available_after_recalculation);
pb.setVisibility(showProgressBar ? View.VISIBLE : View.GONE);
View btnContainer = messageContainer.findViewById(R.id.btn_container);
if (btnTitle != null) {
TextView tvBtnTitle = btnContainer.findViewById(R.id.btn_text);
tvBtnTitle.setText(btnTitle);
btnContainer.setVisibility(View.VISIBLE);
} else {
btnContainer.setVisibility(View.GONE);
}
if (btnListener != null) {
btnContainer.setOnClickListener(btnListener);
}
}
private void showGraph() {
if (visibleGraphType.isCustom()) {
customGraphChart.clear();
commonGraphContainer.setVisibility(View.GONE);
if (visibleType.isCustom()) {
CustomGraphType customGraphType = (CustomGraphType) visibleType;
customGraphContainer.setVisibility(View.VISIBLE);
messageContainer.setVisibility(View.GONE);
prepareCustomGraphView((BarData) visibleGraphType.getGraphData());
customGraphAdapter.setLegendViewType(LegendViewType.ONE_ELEMENT);
customGraphAdapter.updateContent(customGraphType.getChartData(), customGraphType.getStatistics());
} else {
commonGraphChart.clear();
CommonGraphType commonGraphType = (CommonGraphType) visibleType;
commonGraphContainer.setVisibility(View.VISIBLE);
customGraphContainer.setVisibility(View.GONE);
messageContainer.setVisibility(View.GONE);
prepareCommonGraphView((LineData) visibleGraphType.getGraphData());
customGraphAdapter.setLegendViewType(LegendViewType.GONE);
commonGraphAdapter.updateContent(commonGraphType.getChartData(), gpxItem);
}
}
private void showMessage() {
commonGraphContainer.setVisibility(View.GONE);
customGraphContainer.setVisibility(View.GONE);
messageContainer.setVisibility(View.VISIBLE);
TextView tvMessage = messageContainer.findViewById(R.id.message_text);
ImageView icon = messageContainer.findViewById(R.id.message_icon);
ProgressBar pb = messageContainer.findViewById(R.id.progress_bar);
pb.setVisibility(View.GONE);
icon.setVisibility(View.VISIBLE);
tvMessage.setText(app.getString(
R.string.message_need_calculate_route_before_show_graph,
visibleGraphType.getTitle()));
icon.setImageResource(R.drawable.ic_action_altitude_average);
}
private void prepareCommonGraphView(LineData data) {
GpxUiHelper.setupGPXChart(commonGraphChart, 4, 24f, 16f, !nightMode, true);
commonGraphChart.setData(data);
}
private void prepareCustomGraphView(BarData data) {
OsmandApplication app = getMyApplication();
if (app == null) return;
GpxUiHelper.setupHorizontalGPXChart(app, customGraphChart, 5, 9, 24, true, nightMode);
customGraphChart.setExtraRightOffset(16);
customGraphChart.setExtraLeftOffset(16);
customGraphChart.setData(data);
}
private void updateGraphData() {
private void updateData() {
graphTypes.clear();
OsmandApplication app = getMyApplication();
GPXTrackAnalysis analysis = createGpxTrackAnalysis();
gpxFile = getGpxFile();
analysis = gpxFile != null ? gpxFile.getAnalysis(0) : null;
gpxItem = gpxFile != null ? GpxUiHelper.makeGpxDisplayItem(app, gpxFile) : null;
if (gpxItem != null) {
trackDetailsMenu.setGpxItem(gpxItem);
}
if (analysis == null) return;
// update common graph data
for (CommonGraphType commonType : CommonGraphType.values()) {
List<ILineDataSet> dataSets = getDataSets(commonType, commonGraphChart, analysis);
LineData data = null;
if (!Algorithms.isEmpty(dataSets)) {
data = new LineData(dataSets);
}
String title = app.getString(commonType.titleId);
graphTypes.add(new GraphType(title, false, commonType.canBeCalculated, data));
}
boolean hasElevationData = analysis.hasElevationData;
boolean hasSpeedData = analysis.isSpeedSpecified();
addCommonType(R.string.shared_string_overview, true, hasElevationData, ALTITUDE, SLOPE);
addCommonType(R.string.altitude, true, hasElevationData, ALTITUDE, null);
addCommonType(R.string.shared_string_slope, true, hasElevationData, SLOPE, null);
addCommonType(R.string.map_widget_speed, false, hasSpeedData, SPEED, null);
// update custom graph data
List<RouteSegmentResult> routeSegments = editingCtx.getAllRouteSegments();
List<RouteStatistics> routeStatistics = calculateRouteStatistics(routeSegments);
List<RouteStatistics> routeStatistics = calculateRouteStatistics();
if (analysis != null && routeStatistics != null) {
for (RouteStatistics statistics : routeStatistics) {
String title = AndroidUtils.getStringRouteInfoPropertyValue(app, statistics.name);
BarData data = null;
if (!Algorithms.isEmpty(statistics.elements)) {
data = GpxUiHelper.buildStatisticChart(
app, customGraphChart, statistics, analysis, true, nightMode);
}
graphTypes.add(new GraphType(title, true, false, data));
graphTypes.add(new CustomGraphType(title, statistics));
}
}
}
// update current visible graph type
if (visibleGraphType == null) {
visibleGraphType = getFirstAvailableGraphType();
private void updateChartOnMap() {
if (hasVisibleGraph()) {
trackDetailsMenu.reset();
refreshMapCallback.refreshMap(false);
}
}
private void addCommonType(int titleId,
boolean canBeCalculated,
boolean hasData,
LineGraphType firstType,
LineGraphType secondType) {
OsmandApplication app = getMyApplication();
String title = app.getString(titleId);
graphTypes.add(new CommonGraphType(title, canBeCalculated, hasData, firstType, secondType));
}
private void setupVisibleType() {
if (visibleType == null) {
visibleType = getFirstAvailableType();
} else {
for (GraphType type : graphTypes) {
if (isCurrentVisibleType(type)) {
visibleGraphType = type.isAvailable() ? type : getFirstAvailableGraphType();
if (isVisibleType(type)) {
visibleType = type.isAvailable() ? type : getFirstAvailableType();
break;
}
}
}
}
private List<ILineDataSet> getDataSets(CommonGraphType type, LineChart chart, GPXTrackAnalysis analysis) {
List<ILineDataSet> dataSets = new ArrayList<>();
if (chart != null && analysis != null) {
OsmandApplication app = getMyApplication();
switch (type) {
case OVERVIEW: {
List<OrderedLineDataSet> dataList = new ArrayList<>();
if (analysis.hasSpeedData) {
OrderedLineDataSet speedDataSet = GpxUiHelper.createGPXSpeedDataSet(app, chart,
analysis, GPXDataSetAxisType.DISTANCE, true, true, false);
dataList.add(speedDataSet);
}
if (analysis.hasElevationData) {
OrderedLineDataSet elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, chart,
analysis, GPXDataSetAxisType.DISTANCE, false, true, false);
dataList.add(elevationDataSet);
OrderedLineDataSet slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, chart,
analysis, GPXDataSetAxisType.DISTANCE, null, true, true, false);
dataList.add(slopeDataSet);
}
if (dataList.size() > 0) {
Collections.sort(dataList, new Comparator<OrderedLineDataSet>() {
@Override
public int compare(OrderedLineDataSet o1, OrderedLineDataSet o2) {
return Float.compare(o1.getPriority(), o2.getPriority());
}
});
}
dataSets.addAll(dataList);
break;
}
case ALTITUDE: {
if (analysis.hasElevationData) {
OrderedLineDataSet elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, chart,
analysis, GPXDataSetAxisType.DISTANCE, false, true, false);//calcWithoutGaps);
dataSets.add(elevationDataSet);
}
break;
}
case SLOPE:
if (analysis.hasElevationData) {
OrderedLineDataSet slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, chart,
analysis, GPXDataSetAxisType.DISTANCE, null, true, true, false);
dataSets.add(slopeDataSet);
}
break;
case SPEED: {
if (analysis.hasSpeedData) {
OrderedLineDataSet speedDataSet = GpxUiHelper.createGPXSpeedDataSet(app, chart,
analysis, GPXDataSetAxisType.DISTANCE, false, true, false);//calcWithoutGaps);
dataSets.add(speedDataSet);
}
break;
}
}
}
return dataSets;
}
private GPXTrackAnalysis createGpxTrackAnalysis() {
GPXFile gpx;
if (editingCtx.getGpxData() != null) {
gpx = editingCtx.getGpxData().getGpxFile();
private GPXFile getGpxFile() {
if (fragment.isTrackReadyToCalculate()) {
return editingCtx.exportGpx(GRAPH_DATA_GPX_FILE_NAME);
} else {
gpx = editingCtx.exportGpx(GRAPH_DATA_GPX_FILE_NAME);
GpxData gpxData = editingCtx.getGpxData();
return gpxData != null ? gpxData.getGpxFile() : null;
}
return gpx != null ? gpx.getAnalysis(0) : null;
}
private List<RouteStatistics> calculateRouteStatistics(List<RouteSegmentResult> route) {
private List<RouteStatistics> calculateRouteStatistics() {
OsmandApplication app = getMyApplication();
if (route == null || app == null) return null;
return RouteDetailsFragment.calculateRouteStatistics(app, route, nightMode);
List<RouteSegmentResult> route = editingCtx.getAllRouteSegments();
if (route != null && app != null) {
return RouteDetailsFragment.calculateRouteStatistics(app, route, nightMode);
}
return null;
}
private boolean isRouteCalculating() {
return fragment.isProgressBarVisible();
}
private static class GraphType {
private String title;
private boolean isCustom;
private boolean canBeCalculated;
private ChartData graphData;
public boolean hasVisibleGraph() {
return (commonGraphContainer != null && commonGraphContainer.getVisibility() == View.VISIBLE)
|| (customGraphContainer != null && customGraphContainer.getVisibility() == View.VISIBLE);
}
public GraphType(String title, boolean isCustom, boolean canBeCalculated, ChartData graphData) {
private abstract class GraphType<T extends ChartData> {
private String title;
private boolean canBeCalculated;
public GraphType(String title, boolean canBeCalculated) {
this.title = title;
this.isCustom = isCustom;
this.canBeCalculated = canBeCalculated;
this.graphData = graphData;
}
public String getTitle() {
@ -374,23 +379,80 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen
}
public boolean isCustom() {
return isCustom;
return this instanceof CustomGraphType;
}
public boolean isAvailable() {
return hasData() || canBeCalculated();
return isPointsCountEnoughToCalculateRoute() && (hasData() || canBeCalculated());
}
private boolean isPointsCountEnoughToCalculateRoute() {
return editingCtx.getPointsCount() >= 2;
}
public boolean canBeCalculated() {
return canBeCalculated;
}
public boolean hasData() {
return getGraphData() != null;
public abstract boolean hasData();
public abstract T getChartData();
}
private class CommonGraphType extends GraphType<LineData> {
private boolean hasData;
private LineGraphType firstType;
private LineGraphType secondType;
public CommonGraphType(String title, boolean canBeCalculated, boolean hasData, @NonNull LineGraphType firstType, @Nullable LineGraphType secondType) {
super(title, canBeCalculated);
this.hasData = hasData;
this.firstType = firstType;
this.secondType = secondType;
}
public ChartData getGraphData() {
return graphData;
@Override
public boolean hasData() {
return hasData;
}
@Override
public LineData getChartData() {
GpxUiHelper.setupGPXChart(commonGraphAdapter.getChart(), 4, 24f, 16f, !nightMode, true);
List<ILineDataSet> dataSets = GpxUiHelper.getDataSets(commonGraphAdapter.getChart(),
app, analysis, firstType, secondType, false);
return !Algorithms.isEmpty(dataSets) ? new LineData(dataSets) : null;
}
}
private class CustomGraphType extends GraphType<BarData> {
private RouteStatistics statistics;
public CustomGraphType(String title, RouteStatistics statistics) {
super(title, false);
this.statistics = statistics;
}
public RouteStatistics getStatistics() {
return statistics;
}
@Override
public boolean hasData() {
return !Algorithms.isEmpty(statistics.elements);
}
@Override
public BarData getChartData() {
GpxUiHelper.setupHorizontalGPXChart(app, customGraphAdapter.getChart(), 5, 9, 24, true, nightMode);
BarData data = null;
if (!Algorithms.isEmpty(statistics.elements)) {
data = GpxUiHelper.buildStatisticChart(app, customGraphAdapter.getChart(),
statistics, analysis, true, nightMode);
}
return data;
}
}
}

View file

@ -398,6 +398,10 @@ public class MeasurementEditingContext {
return before.points.size();
}
public boolean isPointsEnoughToCalculateRoute() {
return getPointsCount() >= 2;
}
public List<RouteSegmentResult> getAllRouteSegments() {
List<RouteSegmentResult> allSegments = new ArrayList<>();
for (Pair<WptPt, WptPt> key : getOrderedRoadSegmentDataKeys()) {

View file

@ -50,6 +50,7 @@ import net.osmand.plus.activities.TrackActivity;
import net.osmand.plus.base.BaseOsmAndFragment;
import net.osmand.plus.base.ContextMenuFragment.MenuState;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu;
import net.osmand.plus.measurementtool.GpxApproximationFragment.GpxApproximationFragmentListener;
import net.osmand.plus.measurementtool.OptionsBottomSheetDialogFragment.OptionsFragmentListener;
import net.osmand.plus.measurementtool.RouteBetweenPointsBottomSheetDialogFragment.RouteBetweenPointsDialogMode;
@ -113,8 +114,10 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
private TextView distanceToCenterTv;
private String pointsSt;
private View additionalInfoContainer;
private ViewGroup additionalInfoCardsContainer;
private BaseCard visibleAdditionalInfoCard;
private ViewGroup cardsContainer;
private BaseCard visibleCard;
private PointsCard pointsCard;
private GraphsCard graphsCard;
private LinearLayout customRadioButton;
private View mainView;
private ImageView upDownBtn;
@ -141,6 +144,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
private int cachedMapPosition;
private MeasurementEditingContext editingCtx = new MeasurementEditingContext();
private GraphDetailsMenu detailsMenu;
private LatLon initialPoint;
@ -160,6 +164,19 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
GRAPH
}
private class GraphDetailsMenu extends TrackDetailsMenu {
@Override
protected int getFragmentWidth() {
return mainView.getWidth();
}
@Override
protected int getFragmentHeight() {
return mainView.getHeight();
}
}
private void setEditingCtx(MeasurementEditingContext editingCtx) {
this.editingCtx = editingCtx;
}
@ -253,8 +270,9 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
mainView = view.findViewById(R.id.main_view);
AndroidUtils.setBackground(mapActivity, mainView, nightMode, R.drawable.bg_bottom_menu_light, R.drawable.bg_bottom_menu_dark);
detailsMenu = new GraphDetailsMenu();
additionalInfoContainer = mainView.findViewById(R.id.additional_info_container);
additionalInfoCardsContainer = mainView.findViewById(R.id.cards_container);
cardsContainer = mainView.findViewById(R.id.cards_container);
if (portrait) {
customRadioButton = mainView.findViewById(R.id.custom_radio_buttons);
@ -278,6 +296,8 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
}
});
}
pointsCard = new PointsCard(mapActivity, this);
graphsCard = new GraphsCard(mapActivity, detailsMenu, this);
if (progressBarVisible) {
showProgressBar();
@ -513,29 +533,33 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
if (!additionalInfoExpanded || !isCurrentAdditionalInfoType(type)) {
MapActivity ma = getMapActivity();
if (ma == null) return;
currentAdditionalInfoType = type;
updateUpDownBtn();
OsmandApplication app = ma.getMyApplication();
BaseCard additionalInfoCard = null;
if (AdditionalInfoType.POINTS == type) {
additionalInfoCard = new PointsCard(ma, this);
visibleCard = pointsCard;
UiUtilities.updateCustomRadioButtons(app, customRadioButton, nightMode, START);
} else if (AdditionalInfoType.GRAPH == type) {
additionalInfoCard = new GraphsCard(ma, this);
visibleCard = graphsCard;
UiUtilities.updateCustomRadioButtons(app, customRadioButton, nightMode, END);
}
if (additionalInfoCard != null) {
visibleAdditionalInfoCard = additionalInfoCard;
additionalInfoCardsContainer.removeAllViews();
additionalInfoCardsContainer.addView(additionalInfoCard.build(ma));
additionalInfoExpanded = true;
}
cardsContainer.removeAllViews();
View cardView = visibleCard.getView() != null ? visibleCard.getView() : visibleCard.build(ma);
cardsContainer.addView(cardView);
currentAdditionalInfoType = type;
additionalInfoExpanded = true;
updateUpDownBtn();
}
}
private void updateAdditionalInfoView() {
if (visibleAdditionalInfoCard instanceof OnUpdateAdditionalInfoListener) {
((OnUpdateAdditionalInfoListener) visibleAdditionalInfoCard).onUpdateAdditionalInfo();
updateAdditionalInfoView(pointsCard);
updateAdditionalInfoView(graphsCard);
}
private void updateAdditionalInfoView(OnUpdateAdditionalInfoListener listener) {
if (listener != null) {
listener.onUpdateAdditionalInfo();
}
}
@ -588,6 +612,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
super.onResume();
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
detailsMenu.setMapActivity(mapActivity);
mapActivity.getMapLayers().getMapControlsLayer().addThemeInfoProviderTag(TAG);
mapActivity.getMapLayers().getMapControlsLayer().showMapControlsIfHidden();
cachedMapPosition = mapActivity.getMapView().getMapPosition();
@ -603,6 +628,8 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
if (mapActivity != null) {
mapActivity.getMapLayers().getMapControlsLayer().removeThemeInfoProviderTag(TAG);
}
detailsMenu.onDismiss();
detailsMenu.setMapActivity(null);
setMapPosition(cachedMapPosition);
}
@ -669,7 +696,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
mainIcon.setImageDrawable(getActiveIcon(gpxData != null ? R.drawable.ic_action_polygom_dark : R.drawable.ic_action_ruler));
}
private void startSnapToRoad(boolean rememberPreviousTitle) {
public void startSnapToRoad(boolean rememberPreviousTitle) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
if (rememberPreviousTitle) {
@ -1189,7 +1216,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
final ApplicationMode appMode = editingCtx.getAppMode();
if (mapActivity != null) {
Drawable icon;
if (!editingCtx.isApproximationNeeded() || editingCtx.isNewData()) {
if (isTrackReadyToCalculate()) {
if (appMode == MeasurementEditingContext.DEFAULT_APP_MODE) {
icon = getActiveIcon(R.drawable.ic_action_split_interval);
} else {
@ -1204,6 +1231,10 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
}
}
public boolean isTrackReadyToCalculate() {
return !editingCtx.isApproximationNeeded() || editingCtx.isNewData();
}
private void hideSnapToRoadIcon() {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
@ -1488,6 +1519,10 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
return type.equals(currentAdditionalInfoType);
}
public boolean hasVisibleGraph() {
return graphsCard != null && graphsCard.hasVisibleGraph();
}
private String getSuggestedFileName() {
GpxData gpxData = editingCtx.getGpxData();
String displayedName = null;

View file

@ -24,7 +24,9 @@ public class PointsCard extends BaseCard implements OnUpdateAdditionalInfoListen
@Override
public void onUpdateAdditionalInfo() {
adapter.notifyDataSetChanged();
if (adapter != null) {
adapter.notifyDataSetChanged();
}
}
@Override

View file

@ -0,0 +1,82 @@
package net.osmand.plus.measurementtool.graph;
import android.view.MotionEvent;
import com.github.mikephil.charting.charts.Chart;
import com.github.mikephil.charting.data.ChartData;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.listener.ChartTouchListener;
import net.osmand.plus.OsmandApplication;
public abstract class BaseGraphAdapter<_Chart extends Chart, _ChartData extends ChartData, _Data> {
private Highlight lastKnownHighlight;
protected _Chart chart;
protected _ChartData chartData;
protected _Data additionalData;
protected boolean usedOnMap;
public BaseGraphAdapter(_Chart chart, boolean usedOnMap) {
this.chart = chart;
this.usedOnMap = usedOnMap;
prepareChartView();
}
protected void prepareChartView() {
chart.setExtraRightOffset(16);
chart.setExtraLeftOffset(16);
}
public _Chart getChart() {
return chart;
}
protected void updateHighlight() {
highlight(lastKnownHighlight);
}
public void highlight(Highlight h) {
this.lastKnownHighlight = h;
}
public void updateContent(_ChartData chartData, _Data data) {
updateData(chartData, data);
updateView();
}
public void updateData(_ChartData chartData, _Data data) {
this.chartData = chartData;
this.additionalData = data;
}
public abstract void updateView();
protected boolean isNightMode() {
OsmandApplication app = getMyApplication();
if (app != null) {
return usedOnMap ? app.getDaynightHelper().isNightModeForMapControls()
: !app.getSettings().isLightContent();
}
return false;
}
protected OsmandApplication getMyApplication() {
return (OsmandApplication) chart.getContext().getApplicationContext();
}
public interface ExternalValueSelectedListener {
void onValueSelected(Entry e, Highlight h);
void onNothingSelected();
}
public interface ExternalGestureListener {
void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture);
void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture, boolean hasTranslated);
}
public interface LayoutChangeListener {
void onLayoutChanged();
}
}

View file

@ -0,0 +1,138 @@
package net.osmand.plus.measurementtool.graph;
import android.graphics.Matrix;
import android.view.MotionEvent;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.listener.ChartTouchListener;
import com.github.mikephil.charting.listener.OnChartGestureListener;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
import java.util.HashMap;
import java.util.Map;
public class CommonGraphAdapter extends BaseGraphAdapter<LineChart, LineData, GpxDisplayItem> {
private Highlight highlight;
private Map<String, ExternalValueSelectedListener> externalValueSelectedListeners = new HashMap<>();
private ExternalGestureListener externalGestureListener;
public CommonGraphAdapter(LineChart chart, boolean usedOnMap) {
super(chart, usedOnMap);
}
@Override
protected void prepareChartView() {
super.prepareChartView();
chart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
@Override
public void onValueSelected(Entry e, Highlight h) {
highlight = h;
for (ExternalValueSelectedListener listener : externalValueSelectedListeners.values()) {
listener.onValueSelected(e, h);
}
}
@Override
public void onNothingSelected() {
for (ExternalValueSelectedListener listener : externalValueSelectedListeners.values()) {
listener.onNothingSelected();
}
}
});
chart.setOnChartGestureListener(new OnChartGestureListener() {
boolean hasTranslated = false;
float highlightDrawX = -1;
@Override
public void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
hasTranslated = false;
if (chart.getHighlighted() != null && chart.getHighlighted().length > 0) {
highlightDrawX = chart.getHighlighted()[0].getDrawX();
} else {
highlightDrawX = -1;
}
if (externalGestureListener != null) {
externalGestureListener.onChartGestureStart(me, lastPerformedGesture);
}
}
@Override
public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
GpxDisplayItem gpxItem = getGpxItem();
gpxItem.chartMatrix = new Matrix(chart.getViewPortHandler().getMatrixTouch());
Highlight[] highlights = chart.getHighlighted();
if (highlights != null && highlights.length > 0) {
gpxItem.chartHighlightPos = highlights[0].getX();
} else {
gpxItem.chartHighlightPos = -1;
}
if (externalGestureListener != null) {
externalGestureListener.onChartGestureEnd(me, lastPerformedGesture, hasTranslated);
}
}
@Override
public void onChartLongPressed(MotionEvent me) {
}
@Override
public void onChartDoubleTapped(MotionEvent me) {
}
@Override
public void onChartSingleTapped(MotionEvent me) {
}
@Override
public void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) {
}
@Override
public void onChartScale(MotionEvent me, float scaleX, float scaleY) {
}
@Override
public void onChartTranslate(MotionEvent me, float dX, float dY) {
hasTranslated = true;
if (highlightDrawX != -1) {
Highlight h = chart.getHighlightByTouchPoint(highlightDrawX, 0f);
if (h != null) {
chart.highlightValue(h, true);
}
}
}
});
}
public void addValueSelectedListener(String key, ExternalValueSelectedListener listener) {
this.externalValueSelectedListeners.put(key, listener);
}
public void setExternalGestureListener(ExternalGestureListener listener) {
this.externalGestureListener = listener;
}
@Override
public void updateView() {
chart.setData(chartData);
updateHighlight();
}
@Override
public void highlight(Highlight h) {
super.highlight(h);
chart.highlightValue(highlight);
}
public GpxDisplayItem getGpxItem() {
return additionalData;
}
}

View file

@ -0,0 +1,183 @@
package net.osmand.plus.measurementtool.graph;
import android.graphics.drawable.Drawable;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.StyleSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.core.graphics.ColorUtils;
import com.github.mikephil.charting.charts.HorizontalBarChart;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
import net.osmand.AndroidUtils;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.helpers.CustomBarChartRenderer;
import net.osmand.router.RouteStatisticsHelper;
import net.osmand.router.RouteStatisticsHelper.RouteStatistics;
import net.osmand.router.RouteStatisticsHelper.RouteSegmentAttribute;
import net.osmand.util.Algorithms;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static net.osmand.plus.track.ColorsCard.MINIMUM_CONTRAST_RATIO;
public class CustomGraphAdapter extends BaseGraphAdapter<HorizontalBarChart, BarData, RouteStatistics> {
private String selectedPropertyName;
private ViewGroup legendContainer;
private LegendViewType legendViewType;
private LayoutChangeListener layoutChangeListener;
public enum LegendViewType {
ONE_ELEMENT,
ALL_AS_LIST,
GONE
}
public CustomGraphAdapter(HorizontalBarChart chart, boolean usedOnMap) {
super(chart, usedOnMap);
}
@Override
protected void prepareChartView() {
super.prepareChartView();
legendViewType = LegendViewType.GONE;
chart.setRenderer(new CustomBarChartRenderer(chart));
chart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
@Override
public void onValueSelected(Entry e, Highlight h) {
if (getStatistics() == null) return;
List<RouteStatisticsHelper.RouteSegmentAttribute> elems = getStatistics().elements;
int i = h.getStackIndex();
if (i >= 0 && elems.size() > i) {
selectedPropertyName = elems.get(i).getPropertyName();
updateLegend();
}
}
@Override
public void onNothingSelected() {
selectedPropertyName = null;
updateLegend();
}
});
}
@Override
public void updateView() {
chart.setData(chartData);
updateHighlight();
updateLegend();
}
public void setLegendContainer(ViewGroup legendContainer) {
this.legendContainer = legendContainer;
}
public void setLegendViewType(LegendViewType legendViewType) {
this.legendViewType = legendViewType;
}
public void setLayoutChangeListener(LayoutChangeListener layoutChangeListener) {
this.layoutChangeListener = layoutChangeListener;
}
public void highlight(Highlight h) {
super.highlight(h);
Highlight bh = h != null ? chart.getHighlighter().getHighlight(1, h.getXPx()) : null;
if (bh != null) {
bh.setDraw(h.getXPx(), 0);
}
chart.highlightValue(bh, true);
}
private void updateLegend() {
if (legendContainer != null) {
legendContainer.removeAllViews();
attachLegend();
if (layoutChangeListener != null) {
layoutChangeListener.onLayoutChanged();
}
}
}
private void attachLegend() {
if (getSegmentsList() == null) return;
switch (legendViewType) {
case ONE_ELEMENT:
for (RouteSegmentAttribute segment : getSegmentsList()) {
if (segment.getPropertyName().equals(selectedPropertyName)) {
attachLegend(Collections.singletonList(segment), null);
break;
}
}
break;
case ALL_AS_LIST:
attachLegend(getSegmentsList(), selectedPropertyName);
break;
}
}
private void attachLegend(List<RouteSegmentAttribute> list,
String propertyNameToFullSpan) {
OsmandApplication app = getMyApplication();
LayoutInflater inflater = LayoutInflater.from(app);
for (RouteStatisticsHelper.RouteSegmentAttribute segment : list) {
View view = inflater.inflate(R.layout.route_details_legend, legendContainer, false);
int segmentColor = segment.getColor();
Drawable circle = app.getUIUtilities().getPaintedIcon(R.drawable.ic_action_circle, segmentColor);
ImageView legendIcon = (ImageView) view.findViewById(R.id.legend_icon_color);
legendIcon.setImageDrawable(circle);
double contrastRatio = ColorUtils.calculateContrast(segmentColor,
AndroidUtils.getColorFromAttr(app, R.attr.card_and_list_background_basic));
if (contrastRatio < MINIMUM_CONTRAST_RATIO) {
legendIcon.setBackgroundResource(AndroidUtils.resolveAttribute(app, R.attr.bg_circle_contour));
}
String propertyName = segment.getUserPropertyName();
String name = AndroidUtils.getRenderingStringPropertyName(app, propertyName, propertyName.replaceAll("_", " "));
boolean selected = segment.getPropertyName().equals(propertyNameToFullSpan);
Spannable text = getSpanLegend(name, segment, selected);
TextView legend = (TextView) view.findViewById(R.id.legend_text);
legend.setText(text);
legendContainer.addView(view);
}
}
private Spannable getSpanLegend(String title,
RouteSegmentAttribute segment,
boolean fullSpan) {
String formattedDistance = OsmAndFormatter.getFormattedDistance(segment.getDistance(), getMyApplication());
title = Algorithms.capitalizeFirstLetter(title);
SpannableStringBuilder spannable = new SpannableStringBuilder(title);
spannable.append(": ");
int startIndex = fullSpan ? -0 : spannable.length();
spannable.append(formattedDistance);
spannable.setSpan(new StyleSpan(android.graphics.Typeface.BOLD),
startIndex, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return spannable;
}
private List<RouteSegmentAttribute> getSegmentsList() {
return getStatistics() != null ? new ArrayList<>(getStatistics().partition.values()) : null;
}
private RouteStatistics getStatistics() {
return additionalData;
}
}

View file

@ -0,0 +1,155 @@
package net.osmand.plus.measurementtool.graph;
import android.annotation.SuppressLint;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import com.github.mikephil.charting.charts.BarChart;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.listener.ChartTouchListener;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu;
import net.osmand.plus.measurementtool.graph.BaseGraphAdapter.ExternalValueSelectedListener;
import net.osmand.plus.measurementtool.graph.BaseGraphAdapter.ExternalGestureListener;
import java.util.List;
public class GraphAdapterHelper {
public static final String BIND_GRAPH_ADAPTERS_KEY = "bind_graph_adapters_key";
public static final String BIND_TO_MAP_KEY = "bind_to_map_key";
public static void bindGraphAdapters(final CommonGraphAdapter mainGraphAdapter,
final List<BaseGraphAdapter> otherGraphAdapters,
final ViewGroup mainView) {
if (mainGraphAdapter == null || mainGraphAdapter.getChart() == null
|| otherGraphAdapters == null || otherGraphAdapters.size() == 0) {
return;
}
final LineChart mainChart = mainGraphAdapter.getChart();
View.OnTouchListener mainChartTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent ev) {
if (mainView != null) {
mainView.requestDisallowInterceptTouchEvent(true);
}
for (BaseGraphAdapter adapter : otherGraphAdapters) {
if (adapter.getChart() != null) {
MotionEvent event = MotionEvent.obtainNoHistory(ev);
event.setSource(0);
adapter.getChart().dispatchTouchEvent(event);
}
}
return false;
}
};
mainChart.setOnTouchListener(mainChartTouchListener);
mainGraphAdapter.addValueSelectedListener(BIND_GRAPH_ADAPTERS_KEY,
new ExternalValueSelectedListener() {
@Override
public void onValueSelected(Entry e, Highlight h) {
for (BaseGraphAdapter adapter : otherGraphAdapters) {
adapter.highlight(h);
}
}
@Override
public void onNothingSelected() {
for (BaseGraphAdapter adapter : otherGraphAdapters) {
adapter.highlight(null);
}
}
}
);
View.OnTouchListener otherChartsTouchListener = new View.OnTouchListener() {
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent ev) {
if (ev.getSource() != 0) {
final MotionEvent event = MotionEvent.obtainNoHistory(ev);
event.setSource(0);
mainChart.dispatchTouchEvent(event);
return true;
}
return false;
}
};
for (BaseGraphAdapter adapter : otherGraphAdapters) {
if (adapter.getChart() != null) {
if (adapter.getChart() instanceof BarChart) {
// maybe we should find min and max axis from all charters
BarChart barChart = (BarChart) adapter.getChart();
barChart.getAxisRight().setAxisMinimum(mainChart.getXChartMin());
barChart.getAxisRight().setAxisMaximum(mainChart.getXChartMax());
barChart.setHighlightPerDragEnabled(false);
barChart.setHighlightPerTapEnabled(false);
}
adapter.getChart().setOnTouchListener(otherChartsTouchListener);
}
}
}
public static RefreshMapCallback bindToMap(@NonNull final CommonGraphAdapter graphAdapter,
@NonNull final MapActivity mapActivity,
@NonNull final TrackDetailsMenu detailsMenu) {
final RefreshMapCallback refreshMapCallback = new RefreshMapCallback() {
@Override
public void refreshMap(boolean forceFit) {
LineChart chart = graphAdapter.getChart();
OsmandApplication app = mapActivity.getMyApplication();
if (!app.getRoutingHelper().isFollowingMode()) {
detailsMenu.refreshChart(chart, forceFit);
mapActivity.refreshMap();
}
}
};
graphAdapter.addValueSelectedListener(BIND_TO_MAP_KEY,
new CommonGraphAdapter.ExternalValueSelectedListener() {
@Override
public void onValueSelected(Entry e, Highlight h) {
refreshMapCallback.refreshMap(false);
}
@Override
public void onNothingSelected() {
}
});
graphAdapter.setExternalGestureListener(new ExternalGestureListener() {
@Override
public void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
}
@Override
public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture, boolean hasTranslated) {
if ((lastPerformedGesture == ChartTouchListener.ChartGesture.DRAG && hasTranslated) ||
lastPerformedGesture == ChartTouchListener.ChartGesture.X_ZOOM ||
lastPerformedGesture == ChartTouchListener.ChartGesture.Y_ZOOM ||
lastPerformedGesture == ChartTouchListener.ChartGesture.PINCH_ZOOM ||
lastPerformedGesture == ChartTouchListener.ChartGesture.DOUBLE_TAP ||
lastPerformedGesture == ChartTouchListener.ChartGesture.ROTATE) {
refreshMapCallback.refreshMap(true);
}
}
});
return refreshMapCallback;
}
public interface RefreshMapCallback {
void refreshMap(boolean forceFit);
}
}

View file

@ -62,6 +62,7 @@ import net.osmand.plus.activities.TrackActivity;
import net.osmand.plus.base.OsmAndListFragment;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.plus.helpers.GpxUiHelper.LineGraphType;
import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetAxisType;
import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetType;
import net.osmand.plus.helpers.GpxUiHelper.OrderedLineDataSet;
@ -86,6 +87,10 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static net.osmand.plus.helpers.GpxUiHelper.LineGraphType.ALTITUDE;
import static net.osmand.plus.helpers.GpxUiHelper.LineGraphType.SLOPE;
import static net.osmand.plus.helpers.GpxUiHelper.LineGraphType.SPEED;
public class TrackSegmentFragment extends OsmAndListFragment implements TrackBitmapDrawerListener {
private OsmandApplication app;
@ -424,64 +429,17 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit
}
}
private List<ILineDataSet> getDataSets(GPXTabItemType tabType, LineChart chart) {
private List<ILineDataSet> getDataSets(LineChart chart,
GPXTabItemType tabType,
LineGraphType firstType,
LineGraphType secondType) {
List<ILineDataSet> dataSets = dataSetsMap.get(tabType);
if (dataSets == null && chart != null) {
dataSets = new ArrayList<>();
GPXTrackAnalysis analysis = gpxItem.analysis;
GpxDataItem gpxDataItem = getGpxDataItem();
boolean calcWithoutGaps = gpxItem.isGeneralTrack() && gpxDataItem != null && !gpxDataItem.isJoinSegments();
switch (tabType) {
case GPX_TAB_ITEM_GENERAL: {
OrderedLineDataSet speedDataSet = null;
OrderedLineDataSet elevationDataSet = null;
if (analysis.hasSpeedData) {
speedDataSet = GpxUiHelper.createGPXSpeedDataSet(app, chart,
analysis, GPXDataSetAxisType.DISTANCE, true, true, calcWithoutGaps);
}
if (analysis.hasElevationData) {
elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, chart,
analysis, GPXDataSetAxisType.DISTANCE, false, true, calcWithoutGaps);
}
if (speedDataSet != null) {
dataSets.add(speedDataSet);
if (elevationDataSet != null) {
dataSets.add(elevationDataSet.getPriority() < speedDataSet.getPriority()
? 1 : 0, elevationDataSet);
}
} else if (elevationDataSet != null) {
dataSets.add(elevationDataSet);
}
dataSetsMap.put(GPXTabItemType.GPX_TAB_ITEM_GENERAL, dataSets);
break;
}
case GPX_TAB_ITEM_ALTITUDE: {
OrderedLineDataSet elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, chart,
analysis, GPXDataSetAxisType.DISTANCE, false, true, calcWithoutGaps);
if (elevationDataSet != null) {
dataSets.add(elevationDataSet);
}
if (analysis.hasElevationData) {
List<Entry> eleValues = elevationDataSet != null && !gpxItem.isGeneralTrack() ? elevationDataSet.getValues() : null;
OrderedLineDataSet slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, chart,
analysis, GPXDataSetAxisType.DISTANCE, eleValues, true, true, calcWithoutGaps);
if (slopeDataSet != null) {
dataSets.add(slopeDataSet);
}
}
dataSetsMap.put(GPXTabItemType.GPX_TAB_ITEM_ALTITUDE, dataSets);
break;
}
case GPX_TAB_ITEM_SPEED: {
OrderedLineDataSet speedDataSet = GpxUiHelper.createGPXSpeedDataSet(app, chart,
analysis, GPXDataSetAxisType.DISTANCE, false, true, calcWithoutGaps);
if (speedDataSet != null) {
dataSets.add(speedDataSet);
}
dataSetsMap.put(GPXTabItemType.GPX_TAB_ITEM_SPEED, dataSets);
break;
}
}
dataSets = GpxUiHelper.getDataSets(chart, app, analysis, firstType, secondType, calcWithoutGaps);
dataSetsMap.put(tabType, dataSets);
}
return dataSets;
}
@ -702,7 +660,7 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit
if (analysis != null) {
if (analysis.hasElevationData || analysis.hasSpeedData) {
GpxUiHelper.setupGPXChart(app, chart, 4);
chart.setData(new LineData(getDataSets(GPXTabItemType.GPX_TAB_ITEM_GENERAL, chart)));
chart.setData(new LineData(getDataSets(chart, GPXTabItemType.GPX_TAB_ITEM_GENERAL, ALTITUDE, SPEED)));
updateChart(chart);
chart.setVisibility(View.VISIBLE);
} else {
@ -820,7 +778,7 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit
if (analysis != null) {
if (analysis.hasElevationData) {
GpxUiHelper.setupGPXChart(app, chart, 4);
chart.setData(new LineData(getDataSets(GPXTabItemType.GPX_TAB_ITEM_ALTITUDE, chart)));
chart.setData(new LineData(getDataSets(chart, GPXTabItemType.GPX_TAB_ITEM_ALTITUDE, ALTITUDE, SLOPE)));
updateChart(chart);
chart.setVisibility(View.VISIBLE);
} else {
@ -922,7 +880,7 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit
if (analysis != null && analysis.isSpeedSpecified()) {
if (analysis.hasSpeedData) {
GpxUiHelper.setupGPXChart(app, chart, 4);
chart.setData(new LineData(getDataSets(GPXTabItemType.GPX_TAB_ITEM_SPEED, chart)));
chart.setData(new LineData(getDataSets(chart, GPXTabItemType.GPX_TAB_ITEM_SPEED, SPEED, null)));
updateChart(chart);
chart.setVisibility(View.VISIBLE);
} else {
@ -1188,7 +1146,7 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit
LatLon location = null;
WptPt wpt = null;
gpxItem.chartTypes = null;
List<ILineDataSet> ds = getDataSets(tabType, null);
List<ILineDataSet> ds = getDataSets(null, tabType, null, null);
if (ds != null && ds.size() > 0) {
gpxItem.chartTypes = new GPXDataSetType[ds.size()];
for (int i = 0; i < ds.size(); i++) {

View file

@ -413,7 +413,7 @@ public class ResourceManager {
java.text.DateFormat dateFormat = getDateFormat();
for (File f : lf) {
if (f.isDirectory()) {
String lang = f.getName().replace("-tts", "");
String lang = f.getName().replace(IndexConstants.VOICE_PROVIDER_SUFFIX, "");
File conf = new File(f, lang + "_" + IndexConstants.TTSVOICE_INDEX_EXT_JS);
if (!conf.exists()) {
conf = new File(f, "_config.p");
@ -454,9 +454,10 @@ public class ResourceManager {
if (appPath.canWrite()) {
for (AssetEntry asset : assets) {
File jsFile = new File(appPath, asset.destination);
if (asset.destination.contains("-tts") && asset.destination
if (asset.destination.contains(IndexConstants.VOICE_PROVIDER_SUFFIX) && asset.destination
.endsWith(IndexConstants.TTSVOICE_INDEX_EXT_JS)) {
File oggFile = new File(appPath, asset.destination.replace("-tts", ""));
File oggFile = new File(appPath, asset.destination.replace(
IndexConstants.VOICE_PROVIDER_SUFFIX, ""));
if (oggFile.getParentFile().exists() && !oggFile.exists()) {
copyAssets(context.getAssets(), asset.source, oggFile);
}

View file

@ -2,7 +2,6 @@ package net.osmand.plus.routepreparationmenu;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
@ -14,11 +13,9 @@ import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
@ -30,15 +27,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import com.github.mikephil.charting.animation.ChartAnimator;
import com.github.mikephil.charting.charts.HorizontalBarChart;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.dataprovider.BarDataProvider;
import com.github.mikephil.charting.listener.ChartTouchListener.ChartGesture;
import com.github.mikephil.charting.renderer.HorizontalBarChartRenderer;
import com.github.mikephil.charting.utils.ViewPortHandler;
import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities.GPXFile;
@ -68,10 +57,13 @@ import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetType;
import net.osmand.plus.helpers.GpxUiHelper.OrderedLineDataSet;
import net.osmand.plus.mapcontextmenu.CollapsableView;
import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu;
import net.osmand.plus.measurementtool.graph.BaseGraphAdapter;
import net.osmand.plus.measurementtool.graph.CommonGraphAdapter;
import net.osmand.plus.measurementtool.graph.GraphAdapterHelper;
import net.osmand.plus.measurementtool.graph.GraphAdapterHelper.RefreshMapCallback;
import net.osmand.plus.render.MapRenderRepositories;
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener;
import net.osmand.plus.routepreparationmenu.cards.CardChartListener;
import net.osmand.plus.routepreparationmenu.cards.PublicTransportCard;
import net.osmand.plus.routepreparationmenu.cards.PublicTransportCard.PublicTransportCardListener;
import net.osmand.plus.routepreparationmenu.cards.RouteDirectionsCard;
@ -98,8 +90,8 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
public class RouteDetailsFragment extends ContextMenuFragment implements PublicTransportCardListener,
CardListener, CardChartListener {
public class RouteDetailsFragment extends ContextMenuFragment
implements PublicTransportCardListener, CardListener {
public static final String ROUTE_ID_KEY = "route_id_key";
private static final float PAGE_MARGIN = 5f;
@ -122,6 +114,7 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
private RouteStatisticCard statisticCard;
private List<RouteInfoCard> routeInfoCards = new ArrayList<>();
private RouteDetailsMenu routeDetailsMenu;
private RefreshMapCallback refreshMapCallback;
public interface RouteDetailsFragmentListener {
void onNavigationRequested();
@ -311,24 +304,7 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
return;
}
OsmandApplication app = mapActivity.getMyApplication();
statisticCard = new RouteStatisticCard(mapActivity, gpx, new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent ev) {
LinearLayout mainView = getMainView();
if (mainView != null) {
mainView.requestDisallowInterceptTouchEvent(true);
}
for (RouteInfoCard card : routeInfoCards) {
final HorizontalBarChart ch = card.getChart();
if (ch != null) {
final MotionEvent event = MotionEvent.obtainNoHistory(ev);
event.setSource(0);
ch.dispatchTouchEvent(event);
}
}
return false;
}
}, new OnClickListener() {
statisticCard = new RouteStatisticCard(mapActivity, gpx, new OnClickListener() {
@Override
public void onClick(View v) {
openDetails();
@ -336,7 +312,6 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
});
statisticCard.setTransparentBackground(true);
statisticCard.setListener(this);
statisticCard.setChartListener(this);
menuCards.add(statisticCard);
cardsContainer.addView(statisticCard.build(mapActivity));
buildRowDivider(cardsContainer, false);
@ -359,13 +334,25 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
routeDetailsMenu.setGpxItem(gpxItem);
}
routeDetailsMenu.setMapActivity(mapActivity);
LineChart chart = statisticCard.getChart();
if (chart != null) {
chart.setExtraRightOffset(16);
chart.setExtraLeftOffset(16);
CommonGraphAdapter mainGraphAdapter = statisticCard.getGraphAdapter();
if (mainGraphAdapter != null) {
GraphAdapterHelper.bindGraphAdapters(mainGraphAdapter, getRouteInfoCardsGraphAdapters(), getMainView());
refreshMapCallback = GraphAdapterHelper.bindToMap(mainGraphAdapter, mapActivity, routeDetailsMenu);
}
}
private List<BaseGraphAdapter> getRouteInfoCardsGraphAdapters() {
List<BaseGraphAdapter> adapters = new ArrayList<>();
for (RouteInfoCard card : routeInfoCards) {
BaseGraphAdapter adapter = card.getGraphAdapter();
if (adapter != null) {
adapters.add(adapter);
}
}
return adapters;
}
public static List<RouteStatistics> calculateRouteStatistics(OsmandApplication app,
List<RouteSegmentResult> route,
boolean nightMode) {
@ -384,7 +371,7 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
protected void calculateLayout(View view, boolean initLayout) {
super.calculateLayout(view, initLayout);
if (!initLayout && getCurrentMenuState() != MenuState.FULL_SCREEN) {
refreshChart(false);
refreshMapCallback.refreshMap(false);
}
}
@ -401,48 +388,15 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
buildRowDivider(cardsContainer, false);
}
private OnTouchListener getChartTouchListener() {
return new OnTouchListener() {
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent ev) {
if (ev.getSource() != 0 && v instanceof HorizontalBarChart) {
if (statisticCard != null) {
LineChart ch = statisticCard.getChart();
if (ch != null) {
final MotionEvent event = MotionEvent.obtainNoHistory(ev);
event.setSource(0);
ch.dispatchTouchEvent(event);
}
}
return true;
}
return false;
}
};
}
@SuppressLint("ClickableViewAccessibility")
private void addRouteCard(final LinearLayout cardsContainer, RouteInfoCard routeInfoCard) {
private void addRouteCard(LinearLayout cardsContainer,
RouteInfoCard routeInfoCard) {
OsmandApplication app = requireMyApplication();
menuCards.add(routeInfoCard);
routeInfoCard.setListener(this);
cardsContainer.addView(routeInfoCard.build(app));
buildRowDivider(cardsContainer, false);
routeInfoCards.add(routeInfoCard);
HorizontalBarChart chart = routeInfoCard.getChart();
if (chart != null) {
LineChart mainChart = statisticCard.getChart();
if (mainChart != null) {
chart.getAxisRight().setAxisMinimum(mainChart.getXChartMin());
chart.getAxisRight().setAxisMaximum(mainChart.getXChartMax());
}
chart.setRenderer(new CustomBarChartRenderer(chart, chart.getAnimator(), chart.getViewPortHandler(), AndroidUtils.dpToPx(app, 1f) / 2f));
chart.setHighlightPerDragEnabled(false);
chart.setHighlightPerTapEnabled(false);
chart.setOnTouchListener(getChartTouchListener());
}
}
public Drawable getCollapseIcon(boolean collapsed) {
@ -1487,14 +1441,7 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
private void makeGpx() {
OsmandApplication app = requireMyApplication();
gpx = GpxUiHelper.makeGpxFromRoute(app.getRoutingHelper().getRoute(), app);
String groupName = getString(R.string.current_route);
GpxDisplayGroup group = app.getSelectedGpxHelper().buildGpxDisplayGroup(gpx, 0, groupName);
if (group != null && group.getModifiableList().size() > 0) {
gpxItem = group.getModifiableList().get(0);
if (gpxItem != null) {
gpxItem.route = true;
}
}
gpxItem = GpxUiHelper.makeGpxDisplayItem(app, gpx);
}
void openDetails() {
@ -1615,59 +1562,6 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
}
}
private void refreshChart(boolean forceFit) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null && routeDetailsMenu != null && statisticCard != null &&
!mapActivity.getMyApplication().getRoutingHelper().isFollowingMode()) {
LineChart chart = statisticCard.getChart();
if (chart != null) {
routeDetailsMenu.refreshChart(chart, forceFit);
mapActivity.refreshMap();
}
}
}
private void highlightRouteInfoCharts(@Nullable Highlight h) {
for (RouteInfoCard rc : routeInfoCards) {
HorizontalBarChart chart = rc.getChart();
if (chart != null) {
Highlight bh = h != null ? chart.getHighlighter().getHighlight(1, h.getXPx()) : null;
if (bh != null) {
bh.setDraw(h.getXPx(), 0);
}
chart.highlightValue(bh, true);
}
}
}
@Override
public void onValueSelected(BaseCard card, Entry e, Highlight h) {
refreshChart(false);
highlightRouteInfoCharts(h);
}
@Override
public void onNothingSelected(BaseCard card) {
highlightRouteInfoCharts(null);
}
@Override
public void onChartGestureStart(BaseCard card, MotionEvent me, ChartGesture lastPerformedGesture) {
}
@Override
public void onChartGestureEnd(BaseCard card, MotionEvent me, ChartGesture lastPerformedGesture, boolean hasTranslated) {
if ((lastPerformedGesture == ChartGesture.DRAG && hasTranslated) ||
lastPerformedGesture == ChartGesture.X_ZOOM ||
lastPerformedGesture == ChartGesture.Y_ZOOM ||
lastPerformedGesture == ChartGesture.PINCH_ZOOM ||
lastPerformedGesture == ChartGesture.DOUBLE_TAP ||
lastPerformedGesture == ChartGesture.ROTATE) {
refreshChart(true);
}
}
public static class CumulativeInfo {
public int distance;
public int time;
@ -1696,20 +1590,4 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
final int timeInSeconds = model.getExpectedTime();
return Algorithms.formatDuration(timeInSeconds, app.accessibilityEnabled());
}
private static class CustomBarChartRenderer extends HorizontalBarChartRenderer {
private float highlightHalfWidth;
CustomBarChartRenderer(BarDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler, float highlightHalfWidth) {
super(chart, animator, viewPortHandler);
this.highlightHalfWidth = highlightHalfWidth;
}
@Override
protected void setHighlightDrawPos(Highlight high, RectF bar) {
bar.left = high.getDrawX() - highlightHalfWidth;
bar.right = high.getDrawX() + highlightHalfWidth;
}
}
}

View file

@ -31,7 +31,6 @@ public abstract class BaseCard {
protected boolean nightMode;
private CardListener listener;
private CardChartListener chartListener;
public interface CardListener {
void onCardLayoutNeeded(@NonNull BaseCard card);
@ -78,14 +77,6 @@ public abstract class BaseCard {
this.listener = listener;
}
public CardChartListener getChartListener() {
return chartListener;
}
public void setChartListener(CardChartListener chartListener) {
this.chartListener = chartListener;
}
public void setLayoutNeeded() {
CardListener listener = this.listener;
if (listener != null) {

View file

@ -1,54 +1,33 @@
package net.osmand.plus.routepreparationmenu.cards;
import android.graphics.drawable.Drawable;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.StyleSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.ColorUtils;
import com.github.mikephil.charting.charts.HorizontalBarChart;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities.GPXTrackAnalysis;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.router.RouteStatisticsHelper.RouteSegmentAttribute;
import net.osmand.plus.measurementtool.graph.CustomGraphAdapter;
import net.osmand.plus.measurementtool.graph.CustomGraphAdapter.LegendViewType;
import net.osmand.router.RouteStatisticsHelper.RouteStatistics;
import net.osmand.util.Algorithms;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class RouteInfoCard extends BaseCard {
private static final int MINIMUM_CONTRAST_RATIO = 3;
private RouteStatistics routeStatistics;
private RouteStatistics statistics;
private GPXTrackAnalysis analysis;
private String selectedPropertyName;
private CustomGraphAdapter graphAdapter;
private boolean showLegend;
public RouteInfoCard(MapActivity mapActivity, RouteStatistics routeStatistics, GPXTrackAnalysis analysis) {
public RouteInfoCard(MapActivity mapActivity, RouteStatistics statistics, GPXTrackAnalysis analysis) {
super(mapActivity);
this.routeStatistics = routeStatistics;
this.statistics = statistics;
this.analysis = analysis;
}
@ -59,112 +38,47 @@ public class RouteInfoCard extends BaseCard {
@Override
protected void updateContent() {
updateContent(routeStatistics);
}
@Nullable
public HorizontalBarChart getChart() {
return (HorizontalBarChart) view.findViewById(R.id.chart);
}
private void updateContent(final RouteStatistics routeStatistics) {
updateHeader();
final HorizontalBarChart chart = (HorizontalBarChart) view.findViewById(R.id.chart);
GpxUiHelper.setupHorizontalGPXChart(app, chart, 5, 9, 24, true, nightMode);
chart.setExtraRightOffset(16);
chart.setExtraLeftOffset(16);
BarData barData = GpxUiHelper.buildStatisticChart(app, chart, routeStatistics, analysis, true, nightMode);
chart.setData(barData);
chart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
@Override
public void onValueSelected(Entry e, Highlight h) {
List<RouteSegmentAttribute> elems = routeStatistics.elements;
int i = h.getStackIndex();
if (i >= 0 && elems.size() > i) {
selectedPropertyName = elems.get(i).getPropertyName();
if (showLegend) {
updateLegend(routeStatistics);
}
}
}
@Override
public void onNothingSelected() {
selectedPropertyName = null;
if (showLegend) {
updateLegend(routeStatistics);
}
}
});
LinearLayout container = (LinearLayout) view.findViewById(R.id.route_items);
container.removeAllViews();
if (showLegend) {
attachLegend(container, routeStatistics);
}
final ImageView iconViewCollapse = (ImageView) view.findViewById(R.id.up_down_icon);
iconViewCollapse.setImageDrawable(getCollapseIcon(!showLegend));
HorizontalBarChart chart = (HorizontalBarChart) view.findViewById(R.id.chart);
GpxUiHelper.setupHorizontalGPXChart(getMyApplication(), chart, 5, 9, 24, true, nightMode);
BarData barData = GpxUiHelper.buildStatisticChart(app, chart, statistics, analysis, true, nightMode);
graphAdapter = new CustomGraphAdapter(chart, true);
graphAdapter.setLegendContainer(container);
graphAdapter.updateData(barData, statistics);
updateView();
view.findViewById(R.id.info_type_details_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showLegend = !showLegend;
updateContent();
updateView();
setLayoutNeeded();
}
});
}
protected void updateLegend(RouteStatistics routeStatistics) {
LinearLayout container = (LinearLayout) view.findViewById(R.id.route_items);
container.removeAllViews();
attachLegend(container, routeStatistics);
setLayoutNeeded();
}
private Drawable getCollapseIcon(boolean collapsed) {
return collapsed ? getContentIcon(R.drawable.ic_action_arrow_down) : getActiveIcon(R.drawable.ic_action_arrow_up);
private void updateView() {
updateCollapseIcon();
graphAdapter.setLegendViewType(showLegend ? LegendViewType.ALL_AS_LIST : LegendViewType.GONE);
graphAdapter.updateView();
}
private void updateHeader() {
TextView title = (TextView) view.findViewById(R.id.info_type_title);
String name = AndroidUtils.getStringRouteInfoPropertyValue(app, routeStatistics.name);
String name = AndroidUtils.getStringRouteInfoPropertyValue(app, statistics.name);
title.setText(name);
}
private void attachLegend(ViewGroup container, RouteStatistics routeStatistics) {
Map<String, RouteSegmentAttribute> partition = routeStatistics.partition;
List<Map.Entry<String, RouteSegmentAttribute>> list = new ArrayList<>(partition.entrySet());
ContextThemeWrapper ctx = new ContextThemeWrapper(mapActivity, !nightMode ? R.style.OsmandLightTheme : R.style.OsmandDarkTheme);
LayoutInflater inflater = LayoutInflater.from(ctx);
for (Map.Entry<String, RouteSegmentAttribute> entry : list) {
RouteSegmentAttribute segment = entry.getValue();
View view = inflater.inflate(R.layout.route_details_legend, container, false);
int segmentColor = segment.getColor();
Drawable circle = app.getUIUtilities().getPaintedIcon(R.drawable.ic_action_circle, segmentColor);
ImageView legendIcon = (ImageView) view.findViewById(R.id.legend_icon_color);
legendIcon.setImageDrawable(circle);
double contrastRatio = ColorUtils.calculateContrast(segmentColor, ContextCompat.getColor(app, nightMode ? R.color.card_and_list_background_dark : R.color.card_and_list_background_light));
if (contrastRatio < MINIMUM_CONTRAST_RATIO) {
legendIcon.setBackgroundResource(nightMode ? R.drawable.circle_contour_bg_dark : R.drawable.circle_contour_bg_light);
}
String propertyName = segment.getUserPropertyName();
String name = AndroidUtils.getRenderingStringPropertyName(app, propertyName, propertyName.replaceAll("_", " "));
Spannable text = getSpanLegend(name, segment, segment.getUserPropertyName().equals(selectedPropertyName));
TextView legend = (TextView) view.findViewById(R.id.legend_text);
legend.setText(text);
container.addView(view);
}
private void updateCollapseIcon() {
ImageView ivCollapse = (ImageView) view.findViewById(R.id.up_down_icon);
Drawable drawable = showLegend ?
getContentIcon(R.drawable.ic_action_arrow_down) :
getActiveIcon(R.drawable.ic_action_arrow_up);
ivCollapse.setImageDrawable(drawable);
}
private Spannable getSpanLegend(String title, RouteSegmentAttribute segment, boolean selected) {
String formattedDistance = OsmAndFormatter.getFormattedDistance(segment.getDistance(), getMyApplication());
title = Algorithms.capitalizeFirstLetter(title);
SpannableStringBuilder spannable = new SpannableStringBuilder(title);
spannable.append(": ");
int startIndex = selected ? -0 : spannable.length();
spannable.append(formattedDistance);
spannable.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), startIndex, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return spannable;
public CustomGraphAdapter getGraphAdapter() {
return graphAdapter;
}
}

View file

@ -1,13 +1,10 @@
package net.osmand.plus.routepreparationmenu.cards;
import android.graphics.Matrix;
import android.os.Build;
import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
@ -16,18 +13,12 @@ import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import com.github.mikephil.charting.listener.ChartTouchListener.ChartGesture;
import com.github.mikephil.charting.listener.OnChartGestureListener;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.GPXTrackAnalysis;
import net.osmand.plus.GpxSelectionHelper;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
@ -36,6 +27,7 @@ import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetAxisType;
import net.osmand.plus.helpers.GpxUiHelper.OrderedLineDataSet;
import net.osmand.plus.measurementtool.graph.CommonGraphAdapter;
import net.osmand.plus.routing.RoutingHelper;
import java.util.ArrayList;
@ -52,16 +44,15 @@ public class RouteStatisticCard extends BaseCard {
private OrderedLineDataSet slopeDataSet;
@Nullable
private OrderedLineDataSet elevationDataSet;
private OnTouchListener onTouchListener;
private OnClickListener onAnalyseClickListener;
private CommonGraphAdapter graphAdapter;
public RouteStatisticCard(MapActivity mapActivity, GPXFile gpx, OnTouchListener onTouchListener,
public RouteStatisticCard(MapActivity mapActivity, GPXFile gpx,
OnClickListener onAnalyseClickListener) {
super(mapActivity);
this.gpx = gpx;
this.onTouchListener = onTouchListener;
this.onAnalyseClickListener = onAnalyseClickListener;
makeGpxDisplayItem();
this.gpxItem = GpxUiHelper.makeGpxDisplayItem(app, gpx);
}
@Nullable
@ -219,26 +210,15 @@ public class RouteStatisticCard extends BaseCard {
return elevationDataSet;
}
private void makeGpxDisplayItem() {
String groupName = getMyApplication().getString(R.string.current_route);
GpxSelectionHelper.GpxDisplayGroup group = getMyApplication().getSelectedGpxHelper().buildGpxDisplayGroup(gpx, 0, groupName);
if (group != null && group.getModifiableList().size() > 0) {
gpxItem = group.getModifiableList().get(0);
if (gpxItem != null) {
gpxItem.route = true;
}
}
}
@Nullable
public LineChart getChart() {
return (LineChart) view.findViewById(R.id.chart);
public CommonGraphAdapter getGraphAdapter() {
return graphAdapter;
}
private void buildHeader(GPXTrackAnalysis analysis) {
final LineChart mChart = (LineChart) view.findViewById(R.id.chart);
LineChart mChart = (LineChart) view.findViewById(R.id.chart);
GpxUiHelper.setupGPXChart(mChart, 4, 24f, 16f, !nightMode, true);
mChart.setOnTouchListener(onTouchListener);
graphAdapter = new CommonGraphAdapter(mChart, true);
if (analysis.hasElevationData) {
List<ILineDataSet> dataSets = new ArrayList<>();
@ -256,99 +236,7 @@ public class RouteStatisticCard extends BaseCard {
this.elevationDataSet = elevationDataSet;
this.slopeDataSet = slopeDataSet;
LineData data = new LineData(dataSets);
mChart.setData(data);
mChart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
@Override
public void onValueSelected(Entry e, Highlight h) {
CardChartListener chartListener = getChartListener();
if (chartListener != null) {
chartListener.onValueSelected(RouteStatisticCard.this, e, h);
}
}
@Override
public void onNothingSelected() {
CardChartListener chartListener = getChartListener();
if (chartListener != null) {
chartListener.onNothingSelected(RouteStatisticCard.this);
}
}
});
mChart.setOnChartGestureListener(new OnChartGestureListener() {
boolean hasTranslated = false;
float highlightDrawX = -1;
@Override
public void onChartGestureStart(MotionEvent me, ChartGesture lastPerformedGesture) {
hasTranslated = false;
if (mChart.getHighlighted() != null && mChart.getHighlighted().length > 0) {
highlightDrawX = mChart.getHighlighted()[0].getDrawX();
} else {
highlightDrawX = -1;
}
CardChartListener chartListener = getChartListener();
if (chartListener != null) {
chartListener.onChartGestureStart(RouteStatisticCard.this, me, lastPerformedGesture);
}
}
@Override
public void onChartGestureEnd(MotionEvent me, ChartGesture lastPerformedGesture) {
gpxItem.chartMatrix = new Matrix(mChart.getViewPortHandler().getMatrixTouch());
Highlight[] highlights = mChart.getHighlighted();
if (highlights != null && highlights.length > 0) {
gpxItem.chartHighlightPos = highlights[0].getX();
} else {
gpxItem.chartHighlightPos = -1;
}
CardChartListener chartListener = getChartListener();
if (chartListener != null) {
chartListener.onChartGestureEnd(RouteStatisticCard.this, me, lastPerformedGesture, hasTranslated);
}
}
@Override
public void onChartLongPressed(MotionEvent me) {
}
@Override
public void onChartDoubleTapped(MotionEvent me) {
}
@Override
public void onChartSingleTapped(MotionEvent me) {
}
@Override
public void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) {
}
@Override
public void onChartScale(MotionEvent me, float scaleX, float scaleY) {
}
@Override
public void onChartTranslate(MotionEvent me, float dX, float dY) {
hasTranslated = true;
if (highlightDrawX != -1) {
Highlight h = mChart.getHighlightByTouchPoint(highlightDrawX, 0f);
if (h != null) {
/*
ILineDataSet set = mChart.getLineData().getDataSetByIndex(h.getDataSetIndex());
if (set != null && set.isHighlightEnabled()) {
Entry e = set.getEntryForXValue(h.getX(), h.getY());
MPPointD pix = mChart.getTransformer(set.getAxisDependency()).getPixelForValues(e.getX(), e.getY());
h.setDraw((float) pix.x, (float) pix.y);
}
*/
mChart.highlightValue(h, true);
}
}
}
});
graphAdapter.updateContent(new LineData(dataSets), gpxItem);
mChart.setVisibility(View.VISIBLE);
} else {
mChart.setVisibility(View.GONE);

View file

@ -14,5 +14,7 @@ public enum ExportSettingsType {
OSM_NOTES,
OSM_EDITS,
OFFLINE_MAPS,
FAVORITES
FAVORITES,
TTS_VOICE,
VOICE
}

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