commit
7d5c0daa77
131 changed files with 9095 additions and 2695 deletions
|
@ -16,13 +16,11 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
|
||||
|
@ -183,7 +181,9 @@ public abstract class MapObject implements Comparable<MapObject> {
|
|||
public String getName(String lang, boolean transliterate) {
|
||||
if (lang != null && lang.length() > 0) {
|
||||
if (lang.equals("en")) {
|
||||
return getEnName(transliterate);
|
||||
// for some objects like wikipedia, english name is stored 'name' tag
|
||||
String enName = getEnName(transliterate);
|
||||
return !Algorithms.isEmpty(enName) ? enName : getName();
|
||||
} else {
|
||||
// get name
|
||||
if (names != null) {
|
||||
|
|
|
@ -5,8 +5,11 @@ import net.osmand.data.QuadRect;
|
|||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class WorldRegion implements Serializable {
|
||||
|
||||
|
@ -212,4 +215,22 @@ public class WorldRegion implements Serializable {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static List<WorldRegion> removeDuplicates(List<WorldRegion> regions) {
|
||||
List<WorldRegion> copy = new ArrayList<>(regions);
|
||||
Set<WorldRegion> duplicates = new HashSet<>();
|
||||
for (int i = 0; i < copy.size() - 1; i++) {
|
||||
WorldRegion r1 = copy.get(i);
|
||||
for (int j = i + 1; j < copy.size(); j++) {
|
||||
WorldRegion r2 = copy.get(j);
|
||||
if (r1.containsRegion(r2)) {
|
||||
duplicates.add(r2);
|
||||
} else if (r2.containsRegion(r1)) {
|
||||
duplicates.add(r1);
|
||||
}
|
||||
}
|
||||
}
|
||||
copy.removeAll(duplicates);
|
||||
return copy;
|
||||
}
|
||||
}
|
|
@ -55,7 +55,9 @@ public class SearchResult {
|
|||
|
||||
public double getSumPhraseMatchWeight() {
|
||||
// if result is a complete match in the search we prioritize it higher
|
||||
boolean match = requiredSearchPhrase.countWords(localeName) <= getSelfWordCount();
|
||||
int localWordsMatched = alternateName != null ?
|
||||
requiredSearchPhrase.countWords(alternateName) : requiredSearchPhrase.countWords(localeName) ;
|
||||
boolean match = localWordsMatched <= getSelfWordCount();
|
||||
double res = ObjectType.getTypeWeight(match ? objectType : null);
|
||||
if (parentSearchResult != null) {
|
||||
res = res + parentSearchResult.getSumPhraseMatchWeight() / MAX_TYPE_WEIGHT;
|
||||
|
|
|
@ -191,10 +191,10 @@ public class SearchUICoreTest {
|
|||
if (!Algorithms.stringsEqual(expected, present)) {
|
||||
System.out.println(String.format("Phrase: %s", phrase));
|
||||
System.out.println(String.format("Mismatch for '%s' != '%s'. Result: ", expected, present));
|
||||
}
|
||||
for (SearchResult r : searchResults) {
|
||||
System.out.println(String.format("\t\"%s\",", formatResult(false, r, phrase)));
|
||||
}
|
||||
}
|
||||
Assert.assertEquals(expected, present);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,4 +119,28 @@
|
|||
<string name="connecting_to_the_internet">Konektante al Interreto</string>
|
||||
<string name="initializing">Komencante</string>
|
||||
<string name="sending_location_messages">Sendante lokon</string>
|
||||
<string name="password_descr">Pasvorto de Telegram</string>
|
||||
<string name="enter_password">Tajpu pasvorton</string>
|
||||
<string name="show_on_map">Montri sur mapo</string>
|
||||
<string name="hours_format">%1$d h</string>
|
||||
<string name="minutes_format">%1$d min</string>
|
||||
<string name="hours_and_minutes_format">%1$d h %2$d min</string>
|
||||
<string name="shared_string_sent">Sendita</string>
|
||||
<string name="not_logged_in">Vi ne estas salutinta</string>
|
||||
<string name="closing">Fermante</string>
|
||||
<string name="logging_out">Adiaŭante</string>
|
||||
<string name="initialization">Lanĉante</string>
|
||||
<string name="shared_string_logout">Adiaŭi</string>
|
||||
<string name="shared_string_login">Saluti</string>
|
||||
<string name="osmand_service">Fona reĝimo</string>
|
||||
<string name="shared_string_off">Malaktiva</string>
|
||||
<string name="shared_string_all">Ĉiuj</string>
|
||||
<string name="shared_string_close">Fermi</string>
|
||||
<string name="shared_string_exit">Eliri</string>
|
||||
<string name="shared_string_save">Konservi</string>
|
||||
<string name="shared_string_disable">Malaktivigi</string>
|
||||
<string name="shared_string_apply">Apliki</string>
|
||||
<string name="unit_of_length_descr">Ŝanĝi unuojn por reprezenti distancoj.</string>
|
||||
<string name="logcat_buffer">Bufro logcat</string>
|
||||
<string name="logcat_buffer_descr">Legi kaj kunhavigi detalajn protokolojn de la aplikaĵo</string>
|
||||
</resources>
|
|
@ -22,7 +22,7 @@
|
|||
<string name="proxy_port">ポート</string>
|
||||
<string name="proxy_server">サーバー</string>
|
||||
<string name="shared_string_connection">接続</string>
|
||||
<string name="shared_string_enable">有効</string>
|
||||
<string name="shared_string_enable">有効化</string>
|
||||
<string name="proxy_type">プロキシタイプ</string>
|
||||
<string name="proxy_connected">接続しました</string>
|
||||
<string name="proxy_disconnected">切断しました</string>
|
||||
|
|
|
@ -16,7 +16,16 @@
|
|||
android:focusable="true"
|
||||
android:orientation="vertical"
|
||||
android:clickable="true"
|
||||
tools:background="@drawable/bg_bottom_menu_dark">
|
||||
tools:ignore="UselessParent">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:background="@drawable/bg_contextmenu_shadow_top_light" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/snap_to_road_progress_bar"
|
||||
|
@ -24,12 +33,17 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="0dp"
|
||||
android:visibility="gone"
|
||||
android:background="?attr/list_background_color"
|
||||
android:visibility="invisible"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/main_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/list_background_color">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/up_down_row"
|
||||
|
@ -53,6 +67,19 @@
|
|||
android:background="@null"
|
||||
tools:src="@drawable/ic_action_ruler"/>
|
||||
|
||||
<include
|
||||
layout="@layout/custom_icon_radio_buttons"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginEnd="@dimen/content_padding_half"
|
||||
android:layout_marginLeft="@dimen/bottom_sheet_content_margin"
|
||||
android:layout_marginRight="@dimen/content_padding_half"
|
||||
android:layout_marginStart="@dimen/bottom_sheet_content_margin"
|
||||
android:background="@null" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/up_down_button"
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -65,6 +92,7 @@
|
|||
android:layout_marginRight="@dimen/bottom_sheet_content_margin"
|
||||
android:layout_marginStart="@dimen/bottom_sheet_content_margin"
|
||||
android:background="@null"
|
||||
android:visibility="gone"
|
||||
tools:src="@drawable/ic_action_arrow_down"/>
|
||||
|
||||
<TextView
|
||||
|
|
|
@ -659,6 +659,7 @@
|
|||
<!-- CENTER -->
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/top_controls_container"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
|
|
23
OsmAnd/res/layout/custom_icon_radio_buttons.xml
Normal file
23
OsmAnd/res/layout/custom_icon_radio_buttons.xml
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/custom_radio_buttons"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/btn_bg_border_inactive"
|
||||
android:baselineAligned="false"
|
||||
android:minHeight="@dimen/dialog_button_height"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<include
|
||||
layout="@layout/custom_radio_btn_icon_item"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<include
|
||||
layout="@layout/custom_radio_btn_icon_item"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
20
OsmAnd/res/layout/custom_radio_btn_icon_item.xml
Normal file
20
OsmAnd/res/layout/custom_radio_btn_icon_item.xml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="@dimen/content_padding_small_half"
|
||||
android:paddingBottom="@dimen/content_padding_small_half"
|
||||
android:paddingLeft="@dimen/content_padding_small"
|
||||
android:paddingRight="@dimen/content_padding_small">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="@dimen/standard_icon_size"
|
||||
android:layout_height="@dimen/standard_icon_size"
|
||||
android:layout_gravity="center"
|
||||
tools:src="@drawable/ic_action_info_dark"/>
|
||||
|
||||
</FrameLayout>
|
|
@ -13,10 +13,19 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="@drawable/bg_bottom_menu_dark"
|
||||
android:orientation="vertical"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
android:focusable="true"
|
||||
tools:ignore="UselessParent">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:background="@drawable/bg_contextmenu_shadow_top_light" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/snap_to_road_progress_bar"
|
||||
|
@ -24,9 +33,19 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="0dp"
|
||||
android:visibility="gone"
|
||||
android:background="?attr/list_background_color"
|
||||
android:visibility="invisible"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/main_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/list_background_color"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/up_down_row"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -305,4 +324,6 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
|
@ -4,6 +4,9 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/list_background_color"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
tools:text="Some title" />
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/description"
|
||||
android:id="@+id/title_description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/title"
|
||||
|
@ -60,6 +60,54 @@
|
|||
|
||||
</RelativeLayout>
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/primary_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/dialog_content_margin"
|
||||
android:letterSpacing="@dimen/description_letter_spacing"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="@dimen/content_padding"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingEnd="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/default_list_text_size"
|
||||
android:visibility="gone"
|
||||
app:typeface="@string/font_roboto_regular"
|
||||
tools:text="@string/srtm_download_single_help_message"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/secondary_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/content_padding_small"
|
||||
android:letterSpacing="@dimen/description_letter_spacing"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="@dimen/content_padding"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingEnd="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
android:visibility="gone"
|
||||
app:typeface="@string/font_roboto_regular"
|
||||
tools:text="@string/srtm_download_list_help_message"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<include
|
||||
layout="@layout/custom_radio_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/content_padding"
|
||||
android:layout_marginLeft="@dimen/content_padding"
|
||||
android:layout_marginEnd="@dimen/content_padding"
|
||||
android:layout_marginRight="@dimen/content_padding"
|
||||
android:layout_marginBottom="@dimen/content_padding_half"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/select_all_button"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -67,12 +115,12 @@
|
|||
android:background="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="@dimen/bottom_sheet_list_item_height"
|
||||
android:paddingStart="@dimen/content_padding"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingTop="@dimen/content_padding_small"
|
||||
android:paddingEnd="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding"
|
||||
android:paddingBottom="@dimen/content_padding_small"
|
||||
android:paddingStart="@dimen/content_padding"
|
||||
android:paddingEnd="@dimen/content_padding">
|
||||
android:paddingBottom="@dimen/content_padding_small">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/check_box_title"
|
||||
|
|
|
@ -64,7 +64,6 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/content_padding_small"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingStart="@dimen/content_padding_small"
|
||||
android:paddingLeft="@dimen/content_padding_small"
|
||||
android:paddingTop="@dimen/content_padding_small_half"
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:osmand="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/bg_color"
|
||||
|
@ -13,78 +11,13 @@
|
|||
android:layout_height="@dimen/list_content_padding"
|
||||
android:background="?attr/activity_background_color" />
|
||||
|
||||
<include
|
||||
layout="@layout/divider" />
|
||||
<include layout="@layout/divider" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/subscriptions_list_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/support_region_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:paddingStart="@dimen/content_padding"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding"
|
||||
android:paddingEnd="@dimen/content_padding">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/setting_list_item_group_height"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="@dimen/map_widget_height"
|
||||
android:layout_marginRight="@dimen/map_widget_height"
|
||||
app:srcCompat="@drawable/ic_world_globe_dark"
|
||||
app:tint="?attr/default_icon_color" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginTop="@dimen/content_padding_small"
|
||||
android:layout_marginBottom="@dimen/content_padding_small"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/support_region_header"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/default_list_text_size"
|
||||
osmand:typeface="@string/font_roboto_regular"
|
||||
tools:text="@string/osm_live_support_region"/>
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/support_region"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/content_padding"
|
||||
android:layout_marginRight="@dimen/content_padding"
|
||||
android:text="@string/osm_live_support_region"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
osmand:typeface="@string/font_roboto_regular"
|
||||
tools:text="@string/clear_updates_proposition_message"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
app:srcCompat="@drawable/ic_action_settings"
|
||||
app:tint="?attr/default_icon_color" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<include layout="@layout/simple_divider_item" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/report_container"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -206,8 +139,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:background="?attr/activity_background_color">
|
||||
|
||||
<include
|
||||
layout="@layout/card_bottom_divider" />
|
||||
<include layout="@layout/card_bottom_divider" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/main_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
@ -121,6 +122,13 @@
|
|||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/default_list_text_size" />
|
||||
|
||||
<include
|
||||
android:id="@+id/btn_refresh"
|
||||
layout="@layout/bottom_sheet_dialog_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dialog_button_height"
|
||||
android:layout_marginTop="@dimen/content_padding_half" />
|
||||
|
||||
<include
|
||||
android:id="@+id/btn_backup"
|
||||
layout="@layout/bottom_sheet_dialog_button"
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
android:id="@+id/troubleshooting_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="@dimen/map_widget_height"
|
||||
android:layout_marginRight="@dimen/map_widget_height"
|
||||
android:paddingBottom="@dimen/dialog_content_bottom_margin"
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3837,4 +3837,8 @@
|
|||
<string name="track_has_no_altitude">Sporet indeholder ikke højdedata.</string>
|
||||
<string name="track_has_no_speed">Sporet indeholder ikke hastighedsdata.</string>
|
||||
<string name="select_another_colorization">Vælg en anden type farvelægning.</string>
|
||||
<string name="exit_number">Udgangsnummer</string>
|
||||
<string name="announce_when_exceeded">Meddelelse ved overskridelse</string>
|
||||
<string name="user_points">Bruger points</string>
|
||||
<string name="output">Resultat</string>
|
||||
</resources>
|
|
@ -3926,4 +3926,6 @@
|
|||
<string name="poi_karate">Karate</string>
|
||||
<string name="poi_office_diplomatic">Diplomatische Vertretung</string>
|
||||
<string name="poi_bay_filter">Art der Bucht</string>
|
||||
<string name="poi_plateau">Plateau</string>
|
||||
<string name="poi_club_social">Freizeitclub</string>
|
||||
</resources>
|
|
@ -3856,7 +3856,7 @@
|
|||
\nSie können sich mit der sicheren OAuth-Methode anmelden oder Ihren Benutzernamen und Ihr Passwort verwenden.</string>
|
||||
<string name="use_login_password">Benutzername und Passwort verwenden</string>
|
||||
<string name="login_account">Konto</string>
|
||||
<string name="user_login">Benutzername</string>
|
||||
<string name="user_login">Anmelden</string>
|
||||
<string name="markers_history">Historie der Marker</string>
|
||||
<string name="send_files_to_openstreetmap">GPX-Datei an OpenStreetMap senden</string>
|
||||
<string name="enter_text_separated">Geben Sie durch Komma getrennte Tags ein.</string>
|
||||
|
|
|
@ -3926,4 +3926,6 @@
|
|||
<string name="poi_hoops">Korboj</string>
|
||||
<string name="poi_bay_filter">Tipo de golfo</string>
|
||||
<string name="poi_office_diplomatic">Diplomatia oficejo</string>
|
||||
<string name="poi_plateau">Altebenaĵo</string>
|
||||
<string name="poi_club_social">Socia klubejo</string>
|
||||
</resources>
|
|
@ -3926,4 +3926,6 @@
|
|||
<string name="poi_hoops">Aros</string>
|
||||
<string name="poi_office_diplomatic">Oficina diplomática</string>
|
||||
<string name="poi_bay_filter">Tipo de bahía</string>
|
||||
<string name="poi_plateau">Meseta (altiplano)</string>
|
||||
<string name="poi_club_social">Club social</string>
|
||||
</resources>
|
|
@ -1460,4 +1460,5 @@
|
|||
<string name="poi_shoes_women">بانوان</string>
|
||||
<string name="poi_clothes_women">بانوان</string>
|
||||
<string name="poi_clothes_workwear">لباس کار</string>
|
||||
<string name="poi_greenhouse_horticulture">باغداری گلخانهای</string>
|
||||
</resources>
|
|
@ -3924,4 +3924,5 @@
|
|||
<string name="poi_hoops">Kosárlabdapalánkok</string>
|
||||
<string name="poi_office_diplomatic">Diplomáciai iroda</string>
|
||||
<string name="poi_bay_filter">Öböl típusa</string>
|
||||
<string name="poi_plateau">Fennsík</string>
|
||||
</resources>
|
|
@ -3926,4 +3926,5 @@
|
|||
<string name="poi_karate">Karate</string>
|
||||
<string name="poi_office_diplomatic">Sendiskrifstofa</string>
|
||||
<string name="poi_bay_filter">Gerð flóa</string>
|
||||
<string name="poi_plateau">Háslétta</string>
|
||||
</resources>
|
|
@ -1173,7 +1173,7 @@ POIの更新は利用できません</string>
|
|||
<string name="save_as_favorites_points">お気に入りのグループとして保存</string>
|
||||
<string name="select_destination_and_intermediate_points">目的地の設定</string>
|
||||
<string name="layer_amenity_label">施設の名称</string>
|
||||
<string name="loading_smth">ロード中 %1$s …</string>
|
||||
<string name="loading_smth">%1$sをロード中…</string>
|
||||
<string name="map_widget_plain_time">現在時刻</string>
|
||||
<string name="shared_string_waypoint">経由地点</string>
|
||||
<string name="selected_gpx_info_show">"
|
||||
|
@ -1446,7 +1446,7 @@ POIの更新は利用できません</string>
|
|||
<string name="routing_settings_2">ナビゲーション設定</string>
|
||||
<string name="general_settings_2">全般設定</string>
|
||||
<string name="shared_string_ellipsis">…</string>
|
||||
<string name="shared_string_enable">有効</string>
|
||||
<string name="shared_string_enable">有効化</string>
|
||||
<string name="shared_string_disable">無効化</string>
|
||||
<string name="shared_string_selected">選択済み</string>
|
||||
<string name="shared_string_deselect">選択解除</string>
|
||||
|
@ -2818,9 +2818,9 @@ POIの更新は利用できません</string>
|
|||
<string name="osm_live_subscriptions">サブスクリプション</string>
|
||||
<string name="powered_by_osmand">By OsmAnd</string>
|
||||
<string name="osm_live_plan_pricing">プランと料金</string>
|
||||
<string name="osm_live_payment_monthly_title">月間</string>
|
||||
<string name="osm_live_payment_monthly_title">月毎</string>
|
||||
<string name="osm_live_payment_3_months_title">3ヶ月毎</string>
|
||||
<string name="osm_live_payment_annual_title">年間</string>
|
||||
<string name="osm_live_payment_annual_title">年毎</string>
|
||||
<string name="osm_live_payment_month_cost_descr">%1$s / 月</string>
|
||||
<string name="osm_live_payment_month_cost_descr_ex">%1$.2f %2$s / 月</string>
|
||||
<string name="osm_live_payment_discount_descr">%1$s割引</string>
|
||||
|
@ -3172,7 +3172,7 @@ POIの更新は利用できません</string>
|
|||
<string name="app_mode_utv">横並び(サイドバイサイド)形式</string>
|
||||
<string name="rendering_attr_piste_difficulty_aerialway_name">索道(リフトやロープウェイなど)</string>
|
||||
<string name="rendering_attr_piste_difficulty_connection_name">リフト間接続</string>
|
||||
<string name="shared_string_calculate">計算</string>
|
||||
<string name="shared_string_calculate">計算する</string>
|
||||
<string name="shared_string_osmand_usage">OsmAndの合計使用容量</string>
|
||||
<string name="shared_sting_tiles">タイル</string>
|
||||
<string name="shared_string_maps">マップ</string>
|
||||
|
@ -3703,9 +3703,9 @@ POIの更新は利用できません</string>
|
|||
\n
|
||||
\n国の法律に基づいて、使用を望むかどうかを決定する必要があります。
|
||||
\n
|
||||
\n%1$sを選択すると、スピードカメラに関するアラートと警告機能を使用できます。
|
||||
\n『%1$s』を選択すると、スピードカメラに関するアラートと警告機能を使用できます。
|
||||
\n
|
||||
\n%2$sを選択すると、スピードカメラに関するすべてのデータ(警告、通知、POI)が、OsmAndの再インストールを行うまで削除されます。</string>
|
||||
\n『%2$s』を選択すると、スピードカメラに関するすべてのデータ(警告、通知、POI)が、OsmAndの再インストールを行うまで削除されます。</string>
|
||||
<string name="keep_active">機能を維持</string>
|
||||
<string name="shared_string_uninstall">アンインストール</string>
|
||||
<string name="speed_cameras_alert">一部の国では、スピードカメラの事前警告は法律で禁止されています。</string>
|
||||
|
@ -4078,4 +4078,26 @@ POIの更新は利用できません</string>
|
|||
<string name="app_mode_wheelchair_forward">基本前進のみの車椅子</string>
|
||||
<string name="track_coloring_solid">通常色</string>
|
||||
<string name="in_case_of_reverse_direction">逆方向の場合</string>
|
||||
<string name="no_purchases">購入済みの品目はありません</string>
|
||||
<string name="new_device_account">新しい端末 / 新規アカウント</string>
|
||||
<string name="contact_support_description">ご不明な点がございましたら、%1$sまでお問い合わせください。</string>
|
||||
<string name="empty_purchases_description">購入した品目がここに表示されない場合は、\"%1$s\"をタップするか、サポートチームにお問い合わせください。</string>
|
||||
<string name="contact_support">サポート問い合わせ先</string>
|
||||
<string name="troubleshooting">トラブルシューティング</string>
|
||||
<string name="troubleshooting_description">購入に関して問題が発生した場合は、このリンクを参照してください。</string>
|
||||
<string name="osmand_live">OsmAnd Live</string>
|
||||
<string name="next_billing_date">次回請求日: %1$s</string>
|
||||
<string name="osmand_live_cancelled">キャンセル済み</string>
|
||||
<string name="in_grace_period">猶予期間中</string>
|
||||
<string name="on_hold">保留中</string>
|
||||
<string name="expired">期限切れ</string>
|
||||
<string name="update_all_maps_added">%1$sに追加された全マップを更新しますか?</string>
|
||||
<string name="user_points">ユーザーポイント</string>
|
||||
<string name="exit_number">出口番号</string>
|
||||
<string name="announce_when_exceeded">超過した場合の通知</string>
|
||||
<string name="output">出力</string>
|
||||
<string name="annual_subscription">年毎のサブスクリプション</string>
|
||||
<string name="monthly_subscription">月毎のサブスクリプション</string>
|
||||
<string name="three_months_subscription">3ヶ月毎のサブスクリプション</string>
|
||||
<string name="renew_subscription">サブスクリプションの更新</string>
|
||||
</resources>
|
|
@ -1802,7 +1802,7 @@ failu(s)?
|
|||
<string name="first_usage_item">Sākt lietot</string>
|
||||
<string name="first_usage_item_description">Kā lejupielādēt kartes un pamatiestatījumu lietošana</string>
|
||||
<string name="navigation_item_description">Navigācija</string>
|
||||
<string name="planning_trip_item">Ceļa plānošana</string>
|
||||
<string name="planning_trip_item">Ceļojuma plānošana</string>
|
||||
<string name="faq_item">BUJ</string>
|
||||
<string name="faq_item_description">Biežāk uzdotie jautājumi</string>
|
||||
<string name="map_viewing_item">Kartes skatīšana</string>
|
||||
|
@ -2162,7 +2162,6 @@ Apraksta laukumu: %1$s x %2$s</string>
|
|||
<string name="shared_string_time">Laiks</string>
|
||||
<string name="total_distance">Maršruta garums</string>
|
||||
<string name="routing_attr_height_obstacles_name">Lietot elevācijas datus</string>
|
||||
|
||||
<string name="relief_smoothness_factor_descr">Ieteicamais reljefs: līdzens vai kalnains.</string>
|
||||
<string name="shared_string_slope">Slīpums</string>
|
||||
<string name="lang_ber">Berberu</string>
|
||||
|
@ -2415,7 +2414,7 @@ No Afganistānas līdz Zimbabvei, no Austrālijas līdz ASV, Argentīna, Brazīl
|
|||
<string name="show_map">Rādīt karti</string>
|
||||
<string name="route_is_calculated">Maršruts aprēķināts</string>
|
||||
<string name="round_trip">Turp un atpakaļ</string>
|
||||
<string name="plan_route_no_markers_toast">Jums vajag pievienot vismaz vienu marķieri, lai lietotu šo funkciju.</string>
|
||||
<string name="plan_route_no_markers_toast">Lai lietotu šo funkciju, vajag pievienot vismaz vienu marķieri.</string>
|
||||
<string name="osn_modify_dialog_error">Piezīmei nevarēja veikt izmaiņas</string>
|
||||
<string name="osn_modify_dialog_title">Labot piezīmi</string>
|
||||
<string name="context_menu_item_modify_note">!abot OSM piezīmi</string>
|
||||
|
@ -2429,7 +2428,7 @@ No Afganistānas līdz Zimbabvei, no Austrālijas līdz ASV, Argentīna, Brazīl
|
|||
<string name="routing_attr_avoid_ice_roads_fords_name">No ledus ceļiem un brasla</string>
|
||||
<string name="routing_attr_avoid_ice_roads_fords_description">Izvairīties no ledus ceļiem un brasliem.</string>
|
||||
<string name="use_location">Lietot pozīciju</string>
|
||||
<string name="add_location_as_first_point_descr">Pievienot jūsu atrašanās vietu kā sākuma punktu maršrutam.</string>
|
||||
<string name="add_location_as_first_point_descr">Pievienot patreizējo atrašanās vietu kā sākuma punktu ideālā maršruta izveidei.</string>
|
||||
<string name="my_location">Mana pozīcija</string>
|
||||
<string name="shared_string_finish">Finišs</string>
|
||||
<string name="plan_route">Plānot maršrutu</string>
|
||||
|
@ -3333,4 +3332,19 @@ No Afganistānas līdz Zimbabvei, no Austrālijas līdz ASV, Argentīna, Brazīl
|
|||
<string name="select_items_for_import">Izvēlieties lietas, ko importēt.</string>
|
||||
<string name="use_dev_url_descr">Lietot dev.openstreetmap.org nevis openstreetmap.org OSM piezīmju/ POI / GPX augšuielādei un testēšanai.</string>
|
||||
<string name="use_dev_url">Lietot dev.openstreetmap.org</string>
|
||||
<string name="plan_a_route">Plānot maršrutu</string>
|
||||
<string name="plan_route_last_edited">Pēdējo reizi labots</string>
|
||||
<string name="plan_route_import_track">Importēt treku</string>
|
||||
<string name="plan_route_open_existing_track">Atvērt saglabāto treku</string>
|
||||
<string name="plan_route_create_new_route">Veidot jaunu maršrutu</string>
|
||||
<string name="plan_route_select_track_file_for_open">Izvēlieties treka failu atvēršanai.</string>
|
||||
<string name="plan_route_exit_dialog_descr">Vai tiešām gribat atmest visas izmaiņas ieplānotajā maršrutā\?</string>
|
||||
<string name="plan_route_trim_before">Griezt pirms</string>
|
||||
<string name="plan_route_trim_after">Griezt pēc</string>
|
||||
<string name="plan_route_change_route_type_before">Mainīt maršruta veidu pirms</string>
|
||||
<string name="plan_route_change_route_type_after">Mainīt maršruta veidu pēc</string>
|
||||
<string name="plan_route_join_segments">Pievienot segmentus</string>
|
||||
<string name="plan_route_split_before">Sadalīt pirms</string>
|
||||
<string name="plan_route_split_after">Sadalīt pēc</string>
|
||||
<string name="plan_route_add_new_segment">Pievienot jaunu segmentu</string>
|
||||
</resources>
|
|
@ -4056,13 +4056,13 @@
|
|||
<string name="customize_route_line">Zmień trasę nawigacji</string>
|
||||
<string name="shared_string_route_line">Trasa nawigacji</string>
|
||||
<string name="expired">Wygasł</string>
|
||||
<string name="release_4_0_beta">• OsmAnd Live aktualizacje przeniesiono do \"Pobrane > Aktualizacje\"
|
||||
<string name="release_4_0_beta">• Aktualizacje OsmAnd Live przeniesiono do \"Pobrane > Aktualizacje\"
|
||||
\n
|
||||
\n •Ślady mogą być pokolorowane względem wysokości, prędkości, wzniesień.
|
||||
\n
|
||||
\n • Dodano opcję zmiany wyglądu trasy nawigacji
|
||||
\n
|
||||
\n • zaktualizowano okno \"Nagrywanie Trasy\"
|
||||
\n • Zaktualizowano okno \"Nagrywanie Trasy\"
|
||||
\n
|
||||
\n</string>
|
||||
<string name="map_quick_action_pattern">%1$s → …</string>
|
||||
|
|
|
@ -3918,4 +3918,13 @@
|
|||
<string name="poi_jiu_jitsu">Jiu-jitsu</string>
|
||||
<string name="poi_karate">Karatê</string>
|
||||
<string name="poi_hoops">Aros</string>
|
||||
<string name="poi_club_social">Clube social</string>
|
||||
<string name="poi_plateau">Planalto</string>
|
||||
<string name="poi_office_diplomatic">Escritório diplomático</string>
|
||||
<string name="poi_kickboxing">Kickboxe</string>
|
||||
<string name="poi_cycle_polo">Polo de bicicleta</string>
|
||||
<string name="poi_curling">Curling</string>
|
||||
<string name="poi_cliff_diving">Mergulho de falésia</string>
|
||||
<string name="poi_zurkhaneh_sport">Zurkhaneh</string>
|
||||
<string name="poi_bay_filter">Tipo de baía</string>
|
||||
</resources>
|
|
@ -3758,7 +3758,7 @@
|
|||
<string name="shared_string_file_name">Nome do arquivo</string>
|
||||
<string name="number_of_gpx_files_selected_pattern">%s arquivos de trilha selecionados</string>
|
||||
<string name="disable_recording_once_app_killed_descrp">O registro de trilhas fará uma pausa quando o aplicativo for encerrado (por meio de aplicativos recentes). (A indicação de segundo plano do OsmAnd desaparece da barra de notificação do Android.)</string>
|
||||
<string name="save_global_track_interval_descr">Especifique o intervalo de registro para a gravação geral da trilha (ligado por meio do widget de \'gravação de viagem\' no mapa).</string>
|
||||
<string name="save_global_track_interval_descr">Especifique o intervalo de registro para o registro geral da trilha (ativado por meio do widget de \'gravação de viagem\' no mapa).</string>
|
||||
<string name="gpx_monitoring_stop">Pausar gravação de viagem</string>
|
||||
<string name="gpx_monitoring_start">Retomar a gravação da viagem</string>
|
||||
<string name="system_default_theme">Padrão do sistema</string>
|
||||
|
@ -4049,7 +4049,7 @@
|
|||
<string name="shared_string_route_line">Linha de rota</string>
|
||||
<string name="route_line_use_map_style_appearance">A linha de rota seria usada %1$s especificado no estilo de mapa selecionado: %2$s.</string>
|
||||
<string name="specify_color_for_map_mode">Especifique a cor para o modo de mapa: %1$s.</string>
|
||||
<string name="release_4_0_beta">"• As atualizações do OsmAnd Live foram movidas para \"Downloads > Atualizações\"
|
||||
<string name="release_4_0_beta">• As atualizações do OsmAnd Live foram movidas para \"Downloads > Atualizações\"
|
||||
\n
|
||||
\n• As trilhas agora podem ser coloridas por altitude, velocidade ou inclinação.
|
||||
\n
|
||||
|
@ -4057,7 +4057,7 @@
|
|||
\n
|
||||
\n• Caixa de diálogo \"Gravação de viagem\" atualizada
|
||||
\n
|
||||
\n"</string>
|
||||
\n</string>
|
||||
<string name="no_purchases">Você não tem nenhuma compra</string>
|
||||
<string name="new_device_account">Novo dispositivo / nova conta</string>
|
||||
<string name="contact_support_description">Se você tiver alguma dúvida, entre em contato conosco em %1$s.</string>
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
<string name="poi_greengrocer">Loja de frutas e verduras</string>
|
||||
<string name="poi_seafood">Peixaria</string>
|
||||
<string name="poi_confectionery">Confeitaria</string>
|
||||
<string name="poi_ice_cream">Geladaria</string>
|
||||
<string name="poi_ice_cream">Gelataria</string>
|
||||
<string name="poi_supermarket">Supermercado</string>
|
||||
<string name="poi_tea">Loja de chás</string>
|
||||
<string name="poi_pasta">Loja de massas</string>
|
||||
|
@ -80,7 +80,7 @@
|
|||
<string name="poi_carpet">Loja de tapetes</string>
|
||||
<string name="poi_charity">Loja de caridade</string>
|
||||
<string name="poi_chemist">Loja de produtos de higiene pessoal</string>
|
||||
<string name="poi_clothes">Pronto a vestir</string>
|
||||
<string name="poi_clothes">Pronto-a-vestir</string>
|
||||
<string name="poi_clothes_children">Vestuário infantil</string>
|
||||
<string name="poi_shoes">Sapataria</string>
|
||||
<string name="poi_candles">Loja de velas</string>
|
||||
|
@ -248,7 +248,7 @@
|
|||
<string name="poi_shoes_type">Tipo</string>
|
||||
<string name="poi_fire_hydrant_type">Tipo</string>
|
||||
<string name="poi_fire_hydrant_position">Localização</string>
|
||||
<string name="poi_water_source">Fonte de água</string>
|
||||
<string name="poi_water_source">Origem da água</string>
|
||||
<string name="poi_payment_toll_type">Forma de pagamento</string>
|
||||
<string name="poi_traffic_signals_sound">Som</string>
|
||||
<string name="poi_highway_crossing_type">Tipo</string>
|
||||
|
@ -296,7 +296,7 @@
|
|||
<string name="poi_fireplace">Lareira</string>
|
||||
<string name="poi_beach_surface_type">Superfície</string>
|
||||
<string name="poi_nudism">Nudismo</string>
|
||||
<string name="poi_diet">Dieta</string>
|
||||
<string name="poi_diet">Pratos</string>
|
||||
<string name="poi_massage_type">Tipo de massagem</string>
|
||||
<string name="poi_tents">Tendas</string>
|
||||
<string name="poi_washing_machine">Máquina de lavar roupa</string>
|
||||
|
@ -411,10 +411,10 @@
|
|||
<string name="poi_water_tower">Reservatório elevado</string>
|
||||
<string name="poi_lock_gate">Comporta de eclusa</string>
|
||||
<string name="poi_waterway_turning_point">Ponto de viragem fluvial</string>
|
||||
<string name="poi_weir">Represa;Açude</string>
|
||||
<string name="poi_weir">Represa/açude;Represa;Açude</string>
|
||||
<string name="poi_dam">Barragem</string>
|
||||
<string name="poi_watermill">Moinho de água</string>
|
||||
<string name="poi_breakwater">Quebra-mar;Molhe</string>
|
||||
<string name="poi_breakwater">Quebra-mar/molhe;Quebra-mar;Molhe</string>
|
||||
<string name="poi_groyne">Espigão marítimo</string>
|
||||
<string name="poi_power_substation">Subestação</string>
|
||||
<string name="poi_power_transformer">Transformador</string>
|
||||
|
@ -565,18 +565,18 @@
|
|||
<string name="poi_capital">Sim</string>
|
||||
<string name="poi_town">Sede de concelho</string>
|
||||
<string name="poi_village">Sede de freguesia</string>
|
||||
<string name="poi_hamlet">Aldeia;Lugar</string>
|
||||
<string name="poi_hamlet">Aldeia/lugar;Aldeia;Lugar</string>
|
||||
<string name="poi_isolated_dwelling">Moradia isolada</string>
|
||||
<string name="poi_suburb">Subúrbio</string>
|
||||
<string name="poi_quarter">Zona de cidade</string>
|
||||
<string name="poi_neighbourhood">Bairro</string>
|
||||
<string name="poi_locality">Localidade</string>
|
||||
<string name="poi_place_allotments">Horta comunitária</string>
|
||||
<string name="poi_place_farm">Quinta;Fazenda</string>
|
||||
<string name="poi_place_farm">Quinta/fazenda;Quinta;Fazenda</string>
|
||||
<string name="poi_pharmacy">Farmácia</string>
|
||||
<string name="poi_hospital">Hospital</string>
|
||||
<string name="poi_doctors">Consultório médico</string>
|
||||
<string name="poi_clinic">Clínica;Centro de saúde;Unidade de Saúde;Posto Médico</string>
|
||||
<string name="poi_clinic">Clínica/centro de saúde/USF/posto médico</string>
|
||||
<string name="poi_first_aid">Primeiros socorros</string>
|
||||
<string name="poi_dentist">Dentista</string>
|
||||
<string name="poi_nursing_home">Clínica geriátrica</string>
|
||||
|
@ -694,7 +694,7 @@
|
|||
<string name="poi_boundary_stone">Marco de fronteira</string>
|
||||
<string name="poi_historic_cannon">Canhão histórico</string>
|
||||
<string name="poi_castle">Castelo</string>
|
||||
<string name="poi_city_gate">Portão da cidade</string>
|
||||
<string name="poi_city_gate">Portão/arco de cidade</string>
|
||||
<string name="poi_fort">Forte</string>
|
||||
<string name="poi_fountain">Chafariz</string>
|
||||
<string name="poi_historic_ruins">Ruínas históricas</string>
|
||||
|
@ -721,7 +721,7 @@
|
|||
<string name="poi_attraction_water_slide">Tobogã aquático</string>
|
||||
<string name="poi_lodging">Alojamento</string>
|
||||
<string name="poi_hotel">Hotel</string>
|
||||
<string name="poi_guest_house">Pensão;Albergaria;Hospedaria;Estalagem;Residencial</string>
|
||||
<string name="poi_guest_house">Pensão/albergaria/residenial;Estalagem;Residencial;Albergaria;Hospedaria;Casa de hóspedes</string>
|
||||
<string name="poi_hostel">Hostel</string>
|
||||
<string name="poi_motel">Hotel estrada</string>
|
||||
<string name="poi_alpine_hut">Abrigo de montanha</string>
|
||||
|
@ -732,24 +732,24 @@
|
|||
<string name="poi_lean_to">Galpão</string>
|
||||
<string name="poi_hunting_lodge">Cabana de caça</string>
|
||||
<string name="poi_place_of_worship">Local de culto</string>
|
||||
<string name="poi_religion_christian">Cristianismo</string>
|
||||
<string name="poi_religion_jewish">Judaísmo</string>
|
||||
<string name="poi_religion_muslim">Islamismo</string>
|
||||
<string name="poi_religion_sikh">Sikhismo</string>
|
||||
<string name="poi_religion_buddhist">Budismo</string>
|
||||
<string name="poi_religion_hindu">Hinduísmo</string>
|
||||
<string name="poi_religion_shinto">Xintoísmo</string>
|
||||
<string name="poi_religion_taoist">Taoísmo</string>
|
||||
<string name="poi_religion_christian">Cristã</string>
|
||||
<string name="poi_religion_jewish">Judaica</string>
|
||||
<string name="poi_religion_muslim">Islâmica</string>
|
||||
<string name="poi_religion_sikh">Siquista</string>
|
||||
<string name="poi_religion_buddhist">Budista</string>
|
||||
<string name="poi_religion_hindu">Hinduísta</string>
|
||||
<string name="poi_religion_shinto">Xintoísma</string>
|
||||
<string name="poi_religion_taoist">Taoísma</string>
|
||||
<string name="poi_religion_voodoo">Vodu</string>
|
||||
<string name="poi_religion_unitarian_universalist">Unitário-Universalismo</string>
|
||||
<string name="poi_religion_unitarian_universalist">Unitário-universalista</string>
|
||||
<string name="poi_religion_multifaith">Multirreligiosa</string>
|
||||
<string name="poi_religion_jain">Jainismo</string>
|
||||
<string name="poi_religion_spiritualist">Espiritualismo</string>
|
||||
<string name="poi_religion_bahai">Bahaísmo</string>
|
||||
<string name="poi_religion_scientologist">Cientologismo</string>
|
||||
<string name="poi_religion_pagan">Paganismo</string>
|
||||
<string name="poi_religion_jain">Jainista</string>
|
||||
<string name="poi_religion_spiritualist">Espiritualista</string>
|
||||
<string name="poi_religion_bahai">Bahaísta</string>
|
||||
<string name="poi_religion_scientologist">Cientologista</string>
|
||||
<string name="poi_religion_pagan">Paganista</string>
|
||||
<string name="poi_religion_tenrikyo">Tenrikyo</string>
|
||||
<string name="poi_religion_zoroastrian">Zoroastrismo</string>
|
||||
<string name="poi_religion_zoroastrian">Zoroastrista</string>
|
||||
<string name="poi_denomination_catholic">Católica</string>
|
||||
<string name="poi_denomination_baptist">Batista</string>
|
||||
<string name="poi_denomination_roman_catholic">Católica romana</string>
|
||||
|
@ -828,7 +828,7 @@
|
|||
<string name="poi_travel_agent">Agência de viagens</string>
|
||||
<string name="poi_viewpoint">Miradouro</string>
|
||||
<string name="poi_camp_site">Local de acampamento</string>
|
||||
<string name="poi_caravan_site">Local de caravanas</string>
|
||||
<string name="poi_caravan_site">Parque de caravanas</string>
|
||||
<string name="poi_picnic_table">Mesa de piquenique</string>
|
||||
<string name="poi_spring">Nascente</string>
|
||||
<string name="poi_hot_spring">Fonte termal</string>
|
||||
|
@ -890,7 +890,7 @@
|
|||
<string name="poi_theatre_genre_circus">Circo</string>
|
||||
<string name="poi_gallery">Galeria de arte</string>
|
||||
<string name="poi_dance_floor">Pista de dança</string>
|
||||
<string name="poi_nightclub">Discoteca;Danceteria</string>
|
||||
<string name="poi_nightclub">Discoteca/danceteria;Discoteca;Danceteria</string>
|
||||
<string name="poi_stripclub">Clube de striptease</string>
|
||||
<string name="poi_ski_resort">Resort de esqui</string>
|
||||
<string name="poi_beach_resort">Resort de praia</string>
|
||||
|
@ -912,9 +912,9 @@
|
|||
<string name="poi_restaurant">Restaurante</string>
|
||||
<string name="poi_fast_food">Comida rápida</string>
|
||||
<string name="poi_bar">Bar</string>
|
||||
<string name="poi_pub">Taberna</string>
|
||||
<string name="poi_pub">Taberna/pub/tasca;Taberna;Tasco;Tasca;Pub;Boteco;Buteco;Botequim</string>
|
||||
<string name="poi_food_court">Praça de alimentação</string>
|
||||
<string name="poi_drinking_water">Fonte de água potável</string>
|
||||
<string name="poi_drinking_water">Bebedouro (água potável)</string>
|
||||
<string name="poi_barbecue">Churrasqueira</string>
|
||||
<string name="poi_craft_agricultural_engines">Máquinas agrícolas</string>
|
||||
<string name="poi_craft_basket_maker">Cesteiro</string>
|
||||
|
@ -977,8 +977,8 @@
|
|||
<string name="poi_car_pooling">Ponto de boleia solidária de carro</string>
|
||||
<string name="poi_boat_sharing">Ponto de barcos partilhados</string>
|
||||
<string name="poi_dock">Doca</string>
|
||||
<string name="poi_cutline">Linha de corte florestal;Atalhada;Linha corta-fogo</string>
|
||||
<string name="poi_toilets">Casa de banho;Banheiros</string>
|
||||
<string name="poi_cutline">Linha de corte florestal/atalhada;Atalhada;Linha corta-fogo;Linha de corte florestal</string>
|
||||
<string name="poi_toilets">Casa de banho;Banheiros;WC</string>
|
||||
<string name="poi_shower">Chuveiros públicos</string>
|
||||
<string name="poi_sauna">Sauna</string>
|
||||
<string name="poi_brothel">Bordel</string>
|
||||
|
@ -1002,9 +1002,9 @@
|
|||
<string name="poi_ridge">Cumeeira</string>
|
||||
<string name="poi_glacier">Glaciar</string>
|
||||
<string name="poi_sinkhole">Sumidouro</string>
|
||||
<string name="poi_waterfall">Queda de água;Cascata;Salto;Catarata</string>
|
||||
<string name="poi_waterfall">Queda de água/cascata/catarata/salto;Cascata;Salto;Catarata;Queda de água</string>
|
||||
<string name="poi_river">Rio</string>
|
||||
<string name="poi_stream">Ribeiro;Ribeira;Córrego</string>
|
||||
<string name="poi_stream">Ribeiro(a)</string>
|
||||
<string name="poi_rapids">Rápidos</string>
|
||||
<string name="poi_cape">Cabo</string>
|
||||
<string name="poi_beach">Praia</string>
|
||||
|
@ -1122,7 +1122,7 @@
|
|||
<string name="poi_wiki_lang_zh">Wiki em chinês</string>
|
||||
<string name="poi_wiki_lang_af">Wiki em africâner</string>
|
||||
<string name="poi_wiki_lang_als">Wiki em alsaciano</string>
|
||||
<string name="poi_wiki_lang_az">Wiki em azeri</string>
|
||||
<string name="poi_wiki_lang_az">Wiki em azerbaijanês</string>
|
||||
<string name="poi_wiki_lang_bn">Wiki em bengali</string>
|
||||
<string name="poi_wiki_lang_bpy">Wiki em bishnupriya</string>
|
||||
<string name="poi_wiki_lang_br">Wiki em bretão</string>
|
||||
|
@ -1246,8 +1246,8 @@
|
|||
<string name="poi_fee_no">Não</string>
|
||||
<string name="poi_drinking_water_yes">Sim</string>
|
||||
<string name="poi_drinking_water_no">Não</string>
|
||||
<string name="poi_supervised_yes">Vigiado</string>
|
||||
<string name="poi_supervised_no">Não vigiado</string>
|
||||
<string name="poi_supervised_yes">Vigiado: sim</string>
|
||||
<string name="poi_supervised_no">Vigiado: não</string>
|
||||
<string name="poi_seasonal_yes">Sim</string>
|
||||
<string name="poi_seasonal_no">Não</string>
|
||||
<string name="poi_seasonal_dry_season">Estação seca</string>
|
||||
|
@ -1384,7 +1384,7 @@
|
|||
<string name="poi_water_characteristic_mineral">Mineral</string>
|
||||
<string name="poi_water_characteristic_mud">Lama</string>
|
||||
<string name="poi_water_characteristic_sulfuric">Sulfurosa</string>
|
||||
<string name="poi_water_point">Ponto de água</string>
|
||||
<string name="poi_water_point">Ponto de água em grande quantidade (para caravanas ou garrafões)</string>
|
||||
<string name="poi_information_guidepost">Poste com direções</string>
|
||||
<string name="poi_information_board">Painel</string>
|
||||
<string name="poi_information_map">Mapa</string>
|
||||
|
@ -1433,7 +1433,7 @@
|
|||
<string name="poi_horse_riding">Centro equestre</string>
|
||||
<string name="poi_leisure_common">Área de lazer comum</string>
|
||||
<string name="poi_garden">Jardim</string>
|
||||
<string name="poi_heath">Charneca;Mato de vegetação rasteira</string>
|
||||
<string name="poi_heath">Charneca/mato de vegetação rasteira;Charneca;Mato de vegetação rasteira</string>
|
||||
<string name="poi_grass">Relvado</string>
|
||||
<string name="poi_grassland">Pradaria</string>
|
||||
<string name="poi_scrub">Matagal</string>
|
||||
|
@ -1650,32 +1650,32 @@
|
|||
<string name="poi_payment_yandexmoney_no">Não aceita Yandex.Money</string>
|
||||
<string name="poi_description_payment">Detalhes de pagamento</string>
|
||||
<string name="poi_events_venue">Salão de eventos</string>
|
||||
<string name="poi_diet_vegetarian_filter_yes">Vegetariana</string>
|
||||
<string name="poi_diet_vegetarian_few">Vegetariana (alguns)</string>
|
||||
<string name="poi_diet_vegetarian_only">Apenas vegetariana</string>
|
||||
<string name="poi_diet_vegetarian_yes">Vegetariana</string>
|
||||
<string name="poi_diet_vegetarian_no">Dieta vegetariana: não</string>
|
||||
<string name="poi_diet_vegan_filter_yes">Vegana</string>
|
||||
<string name="poi_diet_vegan_only">Apenas vegana</string>
|
||||
<string name="poi_diet_vegan_yes">Vegana</string>
|
||||
<string name="poi_diet_vegan_no">Dieta vegana: não</string>
|
||||
<string name="poi_diet_gluten_free_filter_yes">Livre de glúten</string>
|
||||
<string name="poi_diet_gluten_free_only">Apenas livre de glúten</string>
|
||||
<string name="poi_diet_gluten_free_yes">Livre de glúten</string>
|
||||
<string name="poi_diet_gluten_free_no">Dieta livre de glúten: não</string>
|
||||
<string name="poi_diet_kosher_filter_yes">Kosher (judaica)</string>
|
||||
<string name="poi_diet_kosher_only">Apenas kosher</string>
|
||||
<string name="poi_diet_kosher_yes">Kosher</string>
|
||||
<string name="poi_diet_kosher_no">Dieta kosher: não</string>
|
||||
<string name="poi_diet_halal_filter_yes">Halal (árabe)</string>
|
||||
<string name="poi_diet_halal_only">Apenas halal</string>
|
||||
<string name="poi_diet_halal_yes">Halal</string>
|
||||
<string name="poi_diet_halal_no">Dieta halal: não</string>
|
||||
<string name="poi_diet_lactose_free_filter_yes">Livre de lactose</string>
|
||||
<string name="poi_diet_lactose_free_only">Apenas livre de lactose</string>
|
||||
<string name="poi_diet_lactose_free_yes">Livre de lactose</string>
|
||||
<string name="poi_diet_lactose_free_no">Dieta livre de lactose: não</string>
|
||||
<string name="poi_diet_pescetarian_yes">Piscitariana (peixes e vegetais)</string>
|
||||
<string name="poi_diet_vegetarian_filter_yes">Pratos vegetarianos: sim</string>
|
||||
<string name="poi_diet_vegetarian_few">Pratos vegetarianos: alguns</string>
|
||||
<string name="poi_diet_vegetarian_only">Pratos vegetarianos: só vegetarianos</string>
|
||||
<string name="poi_diet_vegetarian_yes">Pratos vegetarianos: sim</string>
|
||||
<string name="poi_diet_vegetarian_no">Pratos vegetarianos: não</string>
|
||||
<string name="poi_diet_vegan_filter_yes">Pratos veganos: sim</string>
|
||||
<string name="poi_diet_vegan_only">Pratos veganos: só veganos</string>
|
||||
<string name="poi_diet_vegan_yes">Pratos veganos: sim</string>
|
||||
<string name="poi_diet_vegan_no">Pratos veganos: não</string>
|
||||
<string name="poi_diet_gluten_free_filter_yes">Pratos livres de glúten: sim</string>
|
||||
<string name="poi_diet_gluten_free_only">Pratos livres de glúten: unicamente</string>
|
||||
<string name="poi_diet_gluten_free_yes">Pratos livres de glúten: sim</string>
|
||||
<string name="poi_diet_gluten_free_no">Pratos livres de glúten: não</string>
|
||||
<string name="poi_diet_kosher_filter_yes">Pratos kosher (judaica): sim</string>
|
||||
<string name="poi_diet_kosher_only">Pratos kosher (judaica): unicamente</string>
|
||||
<string name="poi_diet_kosher_yes">Pratos kosher (judaica): sim</string>
|
||||
<string name="poi_diet_kosher_no">Pratos kosher (judaica): não</string>
|
||||
<string name="poi_diet_halal_filter_yes">Pratos halal (árabe): sim</string>
|
||||
<string name="poi_diet_halal_only">Pratos halal (árabe): apenas</string>
|
||||
<string name="poi_diet_halal_yes">Pratos halal (árabe): sim</string>
|
||||
<string name="poi_diet_halal_no">Pratos halal (árabe): não</string>
|
||||
<string name="poi_diet_lactose_free_filter_yes">Pratos sem lactose: sim</string>
|
||||
<string name="poi_diet_lactose_free_only">Pratos sem lactose: unicamente</string>
|
||||
<string name="poi_diet_lactose_free_yes">Pratos sem lactose: sim</string>
|
||||
<string name="poi_diet_lactose_free_no">Pratos sem lactose: não</string>
|
||||
<string name="poi_diet_pescetarian_yes">Pratos piscitariana (peixes e vegetais): sim</string>
|
||||
<string name="poi_drive_in_yes">Sim</string>
|
||||
<string name="poi_drive_in_no">Serviço a conduzir: não</string>
|
||||
<string name="poi_drive_through_yes">Sim</string>
|
||||
|
@ -1771,7 +1771,7 @@
|
|||
<string name="poi_vending_toys">Brinquedos</string>
|
||||
<string name="poi_vending_ice_cream">Gelados</string>
|
||||
<string name="poi_vending_sim_cards">Cartões de telemóvel (SIM)</string>
|
||||
<string name="poi_branch">Filial;Sucursal</string>
|
||||
<string name="poi_branch">Filial/sucursal;Filial;Sucursal</string>
|
||||
<string name="poi_memorial_war">Memorial de guerra</string>
|
||||
<string name="poi_memorial_plaque">Placa comemorativa</string>
|
||||
<string name="poi_memorial_statue">Estátua</string>
|
||||
|
@ -2242,7 +2242,7 @@
|
|||
<string name="poi_step_condition_even">Condição dos degraus: regular</string>
|
||||
<string name="poi_step_condition_uneven">Condição dos degraus: irregular</string>
|
||||
<string name="poi_step_condition_rough">Condição dos degraus: acidentada</string>
|
||||
<string name="poi_cairn">Moledro;Moledo;Melédro;Mariola</string>
|
||||
<string name="poi_cairn">Moledro/mariola;Moledo;Melédro;Mariola;Moledro</string>
|
||||
<string name="poi_defibrillator">Desfibrilhador</string>
|
||||
<string name="poi_defibrillator_yes">Desfibrilhador: sim</string>
|
||||
<string name="poi_tomb_war_grave">Tipo: túmulo de guerra</string>
|
||||
|
@ -2360,12 +2360,12 @@
|
|||
<string name="poi_fortification_type_sconce">Tipo de fortificação: arandela</string>
|
||||
<string name="poi_fortification_type_ring_ditch">Tipo de fortificação: vala circular</string>
|
||||
<string name="poi_pa">Pa (assentamento fortificado maori)</string>
|
||||
<string name="poi_historic_farm">Quinta histórica;Fazenda histórica</string>
|
||||
<string name="poi_historic_farm">Quinta/fazenda histórica;Quinta histórica;Fazenda histórica</string>
|
||||
<string name="poi_historic_railway_station">Estação ferroviária histórica</string>
|
||||
<string name="poi_historic_threshing_floor">Eira histórica</string>
|
||||
<string name="poi_historic_gallows">Forca histórica</string>
|
||||
<string name="poi_historic_railway">Ferrovia histórica</string>
|
||||
<string name="poi_square">Praça;Praceta</string>
|
||||
<string name="poi_square">Praça/praceta/largo</string>
|
||||
<string name="poi_artist_name">Artista</string>
|
||||
<string name="poi_sculptor">Escultor</string>
|
||||
<string name="poi_building_type_church">Tipo de edifício: igreja</string>
|
||||
|
@ -2476,7 +2476,7 @@
|
|||
<string name="poi_health_specialty_behavior_yes">Comportamental</string>
|
||||
<string name="poi_health_specialty_palliative_medicine_yes">Medicina paliativa</string>
|
||||
<string name="poi_building_type_pyramid">Tipo de edifício: pirâmide</string>
|
||||
<string name="poi_fitness_centre">Ginásio;Academia desportiva</string>
|
||||
<string name="poi_fitness_centre">Ginásio/academia desportiva;Ginásio;Academia desportiva</string>
|
||||
<string name="poi_fitness">Exercício físico</string>
|
||||
<string name="poi_billiards">Bilhar</string>
|
||||
<string name="poi_microwave_oven_yes">Forno microondas: sim</string>
|
||||
|
@ -3082,7 +3082,7 @@
|
|||
<string name="poi_nutrition_supplements">Suplementos alimentares</string>
|
||||
<string name="poi_photo_studio">Estúdio de fotografia</string>
|
||||
<string name="poi_cliff">Penhasco</string>
|
||||
<string name="poi_animal_keeping">Cativeiro de animais;Refúgio de animais</string>
|
||||
<string name="poi_animal_keeping">Refúgio de animais;Cativeiro de animais</string>
|
||||
<string name="poi_animal_keeping_horse">Cativeiro de animais: cavalos</string>
|
||||
<string name="poi_animal_keeping_sheep">Cativeiro de animais: ovelhas</string>
|
||||
<string name="poi_animal_keeping_type_paddock">Tipo: cercado</string>
|
||||
|
@ -3118,7 +3118,7 @@
|
|||
<string name="poi_stands">Estandes</string>
|
||||
<string name="poi_motorcycle_sales_yes">Vendas</string>
|
||||
<string name="poi_motorcycle_sales_no">Vendas: não</string>
|
||||
<string name="poi_motorcycle_sales_yes_used">Vendas: sim; usados</string>
|
||||
<string name="poi_motorcycle_sales_yes_used">Vendas: sim, usados</string>
|
||||
<string name="poi_motorcycle_sales_used">Vendas: usados</string>
|
||||
<string name="poi_motorcycle_rental_yes">Aluguer</string>
|
||||
<string name="poi_motorcycle_rental_no">Aluguer: não</string>
|
||||
|
@ -3203,7 +3203,7 @@
|
|||
<string name="poi_government_transportation">Instituição governamental de transportes</string>
|
||||
<string name="poi_government_legislative">Instituição legislativa governamental</string>
|
||||
<string name="poi_vhf">Canal VHF</string>
|
||||
<string name="poi_gorge">Desfiladeiro;Canhão</string>
|
||||
<string name="poi_gorge">Desfiladeiro/canhão;Desfiladeiro;Canhão</string>
|
||||
<string name="poi_couloir">Ravina</string>
|
||||
<string name="poi_mountain_area">Área montanhosa</string>
|
||||
<string name="poi_surface_clay">Argila</string>
|
||||
|
@ -3572,7 +3572,7 @@
|
|||
<string name="poi_changing_table_yes">Mesa muda-fraldas: sim</string>
|
||||
<string name="poi_changing_table_no">Mesa muda-fraldas: não</string>
|
||||
<string name="poi_changing_table_limited">Mesa muda-fraldas: limitada</string>
|
||||
<string name="poi_changing_table_location_room">Mesa muda-fraldas; sala</string>
|
||||
<string name="poi_changing_table_location_room">Mesa muda-fraldas: sala</string>
|
||||
<string name="poi_changing_table_location_male_toilet">Local da mesa muda-fraldas: WC masculino</string>
|
||||
<string name="poi_changing_table_location_female_toilet">Local da mesa muda-fraldas: WC feminino</string>
|
||||
<string name="poi_changing_table_location_unisex_toilet">Local da mesa muda-fraldas: WC unissexo</string>
|
||||
|
@ -3810,7 +3810,7 @@
|
|||
<string name="poi_traffic_signals_vibration">Vibração</string>
|
||||
<string name="poi_city_block">Quarteirão</string>
|
||||
<string name="poi_borough">Município</string>
|
||||
<string name="poi_give_box">Caixa livre;Caixa de donativos;Give-box</string>
|
||||
<string name="poi_give_box">Caixa livre/de donativos;Give-box;Caixa livre;Caixa de donativos</string>
|
||||
<string name="poi_traffic_signals_arrow_no">Seta: não</string>
|
||||
<string name="poi_elevator">Elevador</string>
|
||||
<string name="poi_departures_board_timetable">Horário</string>
|
||||
|
@ -3917,8 +3917,8 @@
|
|||
<string name="poi_mobile_library">Posição de paragem da biblioteca itinerante</string>
|
||||
<string name="poi_piste_status_closed">Estado da pista: fechada</string>
|
||||
<string name="poi_piste_status_open">Estado da pista: aberta</string>
|
||||
<string name="poi_patrolled_no">Vigiado: não</string>
|
||||
<string name="poi_patrolled_yes">Vigiado: sim</string>
|
||||
<string name="poi_patrolled_no">Supervisionado: não</string>
|
||||
<string name="poi_patrolled_yes">Supervisionado: sim</string>
|
||||
<string name="poi_piste_name">Nome da pista</string>
|
||||
<string name="poi_piste_ski_jump">Salto com esqui</string>
|
||||
<string name="poi_wildlife_crossing">Passagem de vida selvagem</string>
|
||||
|
@ -3926,4 +3926,6 @@
|
|||
<string name="poi_water_source_well">Poço</string>
|
||||
<string name="poi_office_diplomatic">Gabinete diplomático</string>
|
||||
<string name="poi_bay_filter">Tipo de baía</string>
|
||||
<string name="poi_plateau">Planalto</string>
|
||||
<string name="poi_club_social">Clube social</string>
|
||||
</resources>
|
|
@ -37,7 +37,7 @@
|
|||
<string name="poi_filter_food_shop">Supermercado</string>
|
||||
<string name="poi_filter_for_tourists">Para turistas</string>
|
||||
<string name="poi_filter_fuel">Combustível</string>
|
||||
<string name="poi_filter_namefinder">Pesquisar nome on-line</string>
|
||||
<string name="poi_filter_namefinder">Pesquisar nome online</string>
|
||||
<string name="reading_cached_tiles">A ler mosaicos temporários…</string>
|
||||
<string name="version_index_is_big_for_memory">O índice \'\'{0}\'\' não coube na memória</string>
|
||||
<string name="version_index_is_not_supported">A versão do índice \'\'{0}\'\' não é suportada</string>
|
||||
|
@ -159,12 +159,12 @@
|
|||
\nAgora só é possível ver o mapa pré-carregado, não descarregar novas áreas.</string>
|
||||
<string name="unzipping_file">A descomprimir o ficheiro…</string>
|
||||
<string name="route_tr">Vire à direita e continue em</string>
|
||||
<string name="route_tshr">Vire fortemente à direita e continue em</string>
|
||||
<string name="route_tshr">Vire acentuadamente à direita e continue em</string>
|
||||
<string name="route_tslr">Vire ligeiramente à direita e continue em</string>
|
||||
<string name="route_tl">Vire à esquerda e continue em</string>
|
||||
<string name="route_tshl">Vire fortemente à esquerda e continue em</string>
|
||||
<string name="route_tshl">Vire acentuadamente à esquerda e continue em</string>
|
||||
<string name="route_tsll">Vire ligeiramente à esquerda e continue em</string>
|
||||
<string name="route_tu">Inverta o sentido da marcha e continue em</string>
|
||||
<string name="route_tu">Faça inversão de marcha e continue em</string>
|
||||
<string name="route_head">Comece em</string>
|
||||
<string name="first_time_continue">Continuar</string>
|
||||
<string name="first_time_download">Descarregar regiões</string>
|
||||
|
@ -214,14 +214,14 @@
|
|||
<string name="search_nothing_found">Não foi encontrado nada</string>
|
||||
<string name="searching">A pesquisar…</string>
|
||||
<string name="searching_address">A pesquisar o endereço …</string>
|
||||
<string name="search_osm_nominatim">Pesquisa on-line usando OSM Nominatim</string>
|
||||
<string name="search_osm_nominatim">Pesquisa na Internet usando OSM Nominatim</string>
|
||||
<string name="hint_search_online">Pesquisa online: número da casa, rua, cidade</string>
|
||||
<string name="search_offline_address">Pesquisa offline</string>
|
||||
<string name="search_online_address">Pesquisa online</string>
|
||||
<string name="max_level_download_tile">Nível máximo de zoom</string>
|
||||
<string name="max_level_download_tile_descr">Não navegar em mapas on-line para níveis de ampliação além deste.</string>
|
||||
<string name="max_level_download_tile_descr">Não navegar em mapas online para níveis de ampliação além deste.</string>
|
||||
<string name="route_general_information">Distância total %1$s, tempo de viagem %2$d h %3$d min.</string>
|
||||
<string name="router_service_descr">Serviço de navegação on-line ou off-line.</string>
|
||||
<string name="router_service_descr">Serviço de navegação online ou offline.</string>
|
||||
<string name="router_service">Serviço de navegação</string>
|
||||
<string name="sd_dir_not_accessible">A pasta de armazenamento não está acessível no cartão de memória!</string>
|
||||
<string name="download_question">Descarregar {0} - {1} \?</string>
|
||||
|
@ -371,7 +371,7 @@
|
|||
<string name="poi_error_io_error_template">Erro de entrada/saída na execução da ação {0}.</string>
|
||||
<string name="poi_error_info_not_loaded">As informações sobre o objeto não foram carregadas</string>
|
||||
<string name="poi_dialog_opening_hours">Aberto</string>
|
||||
<string name="poi_dialog_comment">Comentário</string>
|
||||
<string name="poi_dialog_comment">Comentar</string>
|
||||
<string name="poi_dialog_comment_default">Alterar POI</string>
|
||||
<string name="poi_dialog_other_tags_message">Todas as outras etiquetas são preservadas</string>
|
||||
<string name="default_buttons_commit">Enviar</string>
|
||||
|
@ -395,18 +395,18 @@
|
|||
<string name="modify_transparency">Definir a transparência (0 - transparente, 255 - opaco)</string>
|
||||
<string name="confirm_interrupt_download">Cancelar o descarregamento\?</string>
|
||||
<string name="basemap_was_selected_to_download">O mapa base, necessário para fornecer funcionalidade básica, está na fila de descarregamentos.</string>
|
||||
<string name="local_indexes_cat_tile">Mosaicos de mapas on-line e em ficheiros temporários</string>
|
||||
<string name="local_indexes_cat_tile">Mosaicos de mapas online e em ficheiros temporários</string>
|
||||
<string name="local_indexes_cat_map">Mapas padrão (vetorial)</string>
|
||||
<string name="map_online_plugin_is_not_installed">Ative a extensão de \'Mapas on-line\' para selecionar diferentes origens de mapas</string>
|
||||
<string name="map_online_data">Mapas on-line e mosaicos</string>
|
||||
<string name="map_online_plugin_is_not_installed">Ative a extensão de \'Mapas online\' para selecionar diferentes origens de mapas</string>
|
||||
<string name="map_online_data">Mapas online e mosaicos</string>
|
||||
<string name="map_online_data_descr">Usar mapas online (descarregar e armazenar mosaicos no cartão de memória).</string>
|
||||
<string name="shared_string_online_maps">Mapas on-line</string>
|
||||
<string name="online_map_settings_descr">Configurar origens de mosaicos ou de mapas on-line.</string>
|
||||
<string name="osmand_rastermaps_plugin_description">Aceda a muitos tipos de mapas on-line (também chamados de mosaico ou raster) pré-definidos do OpenStreetMap (como Mapnik) para imagens de satélite e camadas especiais, como mapas aquáticos, climáticos, geológicos, camadas de sombra de relevo, etc.
|
||||
<string name="online_map_settings_descr">Configurar origens de mosaicos ou de mapas online.</string>
|
||||
<string name="osmand_rastermaps_plugin_description">Aceda a muitos tipos de mapas online (também chamados de mosaico ou raster) pré-definidos do OpenStreetMap (como Mapnik) para imagens de satélite e camadas especiais, como mapas aquáticos, climáticos, geológicos, camadas de sombra de relevo, etc.
|
||||
\n
|
||||
\nQuaisquer desses mapas podem ser usados como mapa principal (base) para ser mostrado no OsmAnd ou na camada superior ou inferior para outro mapa base (como o mapa off-line normal de OsmAnd). Para tornar qualquer camada inferior do mapa mais visível, certos elementos do mapa vetorial do OsmAnd podem facilmente ser ocultados através do menu \'Configurar mapa\'.
|
||||
\nQuaisquer desses mapas podem ser usados como mapa principal (base) para ser mostrado no OsmAnd ou na camada superior ou inferior para outro mapa base (como o mapa offline normal de OsmAnd). Para tornar qualquer camada inferior do mapa mais visível, certos elementos do mapa vetorial do OsmAnd podem facilmente ser ocultados através do menu \'Configurar mapa\'.
|
||||
\n
|
||||
\nOs mosaicos dos mapas podem ser obtidos diretamente através de origens on-line ou podem ser preparados para uso off-line (e copiados manualmente para o diretório de dados do OsmAnd) como uma base de dados sqlite, que pode ser produzido por uma variedade de ferramentas de terceiros para preparação de mapas.</string>
|
||||
\nOs mosaicos dos mapas podem ser obtidos diretamente através de origens online ou podem ser preparados para uso offline (e copiados manualmente para o diretório de dados do OsmAnd) como uma base de dados sqlite, que pode ser produzido por uma variedade de ferramentas de terceiros para preparação de mapas.</string>
|
||||
<string name="osmand_background_plugin_description">Mostra as configurações para ativar o rastreamento em segundo plano e a navegação, despertando periodicamente o dispositivo GPS (com o ecrã desligado).</string>
|
||||
<string name="osmand_accessibility_description">Mostra os recursos de acessibilidade do dispositivo disponíveis diretamente no OsmAnd. Facilita, por exemplo, o ajuste da velocidade da fala para vozes TTS, configurando a navegação no ecrã do teclado direcional, usando um trackball para controlo da ampliação, ou feedback texto-para-fala, por exemplo, para anunciar automaticamente a sua posição.</string>
|
||||
<string name="osmand_development_plugin_description">Mostra configurações para recursos de desenvolvimento e depuração como testar ou simular roteamento, o desempenho de renderização do ecrã ou solicitação de voz. Essas configurações são destinadas a programadores e não são necessárias para o utilizador em geral.</string>
|
||||
|
@ -465,7 +465,7 @@
|
|||
<string name="left">para a esquerda</string>
|
||||
<string name="front_left">para a frente à esquerda</string>
|
||||
<string name="oclock">horas</string>
|
||||
<string name="towards">em direção a</string>
|
||||
<string name="towards">para</string>
|
||||
<string name="accuracy">Precisão</string>
|
||||
<string name="altitude">Altitude</string>
|
||||
<string name="no_info">Sem informação</string>
|
||||
|
@ -493,11 +493,11 @@
|
|||
<string name="local_openstreetmap_descr_title">Edição assíncrona de OSM:</string>
|
||||
<string name="local_openstreetmap_settings">POIs / notas guardados no dispositivo</string>
|
||||
<string name="local_openstreetmap_settings_descr">Mostrar e gerir POIs/notas do OSM guardados localmente.</string>
|
||||
<string name="live_monitoring_interval_descr">Especifique o intervalo de rastreamento on-line.</string>
|
||||
<string name="live_monitoring_interval">Intervalo de rastreamento on-line</string>
|
||||
<string name="live_monitoring_interval_descr">Especifique o intervalo de rastreamento online.</string>
|
||||
<string name="live_monitoring_interval">Intervalo de rastreamento online</string>
|
||||
<string name="live_monitoring_url_descr">Especifique o endereço web com a sintaxe de parâmetros: lat={0}, lon={1}, data/hora={2}, hdop={3}, altitude={4}, velocidade={5}, bearing={6}.</string>
|
||||
<string name="live_monitoring_url">Endereço web de rastreamento on-line</string>
|
||||
<string name="gpx_monitoring_disabled_warn">Registo de trajeto usando widget GPX ou via \'Gravação de viagem\' nas configurações.</string>
|
||||
<string name="live_monitoring_url">Endereço web de rastreamento online</string>
|
||||
<string name="gpx_monitoring_disabled_warn">Registo de trajeto usando widget GPX ou via \'Gravar viagem\' nas configurações.</string>
|
||||
<string name="show_current_gpx_title">Mostrar rota atual</string>
|
||||
<string name="free_version_message">Pode descarregar ou atualizar %1$s mapas.</string>
|
||||
<string name="free_version_title">Versão gratuita</string>
|
||||
|
@ -562,7 +562,7 @@
|
|||
<string name="shared_string_undefined">Sem definir</string>
|
||||
<string name="search_position_map_view">Centro do mapa atual</string>
|
||||
<string name="select_search_position">Origem:</string>
|
||||
<string name="context_menu_item_search">Pesquisar nas proximidades</string>
|
||||
<string name="context_menu_item_search">Pesquisar perto daqui</string>
|
||||
<string name="route_successfully_saved_at">Rota guardada como \'%1$s\'.</string>
|
||||
<string name="filename_input">Nome do ficheiro:</string>
|
||||
<string name="file_with_name_already_exist">Já existe um ficheiro com o mesmo nome.</string>
|
||||
|
@ -665,9 +665,9 @@
|
|||
<string name="context_menu_item_share_location">Partilhar localização</string>
|
||||
<string name="add_waypoint_dialog_added">Foi adicionado o ponto de passagem GPX \'\'{0}\'\'</string>
|
||||
<string name="add_waypoint_dialog_title">Acrescentar ponto ao trilho GPX gravado</string>
|
||||
<string name="osmand_routing_experimental">Navegação OsmAnd off-line ainda é uma função experimental e não funciona em distâncias superiores a cerca de 20 km.
|
||||
<string name="osmand_routing_experimental">Navegação OsmAnd offline ainda é uma função experimental e não funciona em distâncias superiores a cerca de 20 km.
|
||||
\n
|
||||
\nO serviço de navegação está temporariamente mudado para CloudMade on-line.</string>
|
||||
\nO serviço de navegação está temporariamente mudado para CloudMade online.</string>
|
||||
<string name="specified_dir_doesnt_exist">Não foi possível encontrar a pasta especificada.</string>
|
||||
<string name="application_dir">Local de armazenamento</string>
|
||||
<string name="osmand_net_previously_installed">Todos os dados offline na aplicação instalada antiga serão suportados pela nova, mas os pontos Favoritos devem ser exportados da aplicação antiga e depois importados na nova.</string>
|
||||
|
@ -717,7 +717,7 @@
|
|||
<string name="osmand_parking_plugin_description">Permite gravar onde o seu carro foi estacionado e quanto tempo de estacionamento resta (se houver um limite de tempo).
|
||||
\nA localização e o tempo ficam visíveis no painel de controlo do OsmAnd e num widget no ecrã do mapa. Um alarme pode ser adicionado ao calendário Android como lembrete.</string>
|
||||
<string name="osmand_parking_plugin_name">Local de estacionamento</string>
|
||||
<string name="context_menu_item_add_parking_point">Marcar local de estacionamento</string>
|
||||
<string name="context_menu_item_add_parking_point">Marcar estacionamento</string>
|
||||
<string name="context_menu_item_delete_parking_point">Eliminar um marcador de estacionamento</string>
|
||||
<string name="starting_point_too_far">Ponto de partida demasiado distante da estrada mais próxima.</string>
|
||||
<string name="shared_location">Local partilhado</string>
|
||||
|
@ -736,7 +736,7 @@
|
|||
<string name="continue_follow_previous_route_auto">Continuar a navegação a seguir que ficou antes inacabada\? (%1$s segundos)</string>
|
||||
<string name="show_cameras">Radares de velocidade</string>
|
||||
<string name="show_traffic_warnings">Informações de circulação</string>
|
||||
<string name="avoid_toll_roads">Sem estradas com portagem</string>
|
||||
<string name="avoid_toll_roads">Evitar estradas com portagem</string>
|
||||
<string name="map_widget_top_text">Nome da rua</string>
|
||||
<string name="map_widget_config">Configuração do ecrã</string>
|
||||
<string name="map_widget_back_to_loc">Onde estou</string>
|
||||
|
@ -763,10 +763,10 @@
|
|||
\na execução em segundo plano</string>
|
||||
<string name="show_warnings_title">Mostrar alertas…</string>
|
||||
<string name="show_warnings_descr">Configure avisos de trânsito (limites de velocidade, portagens, lombas, passadeiras, túneis), radares e a faixa de rodagem.</string>
|
||||
<string name="avoid_motorway">Sem autoestradas</string>
|
||||
<string name="avoid_motorway">Evitar autoestradas</string>
|
||||
<string name="snap_to_road">Ajustar à estrada</string>
|
||||
<string name="osmand_short_description_80_chars">Visualização e navegação móvel de mapas globais do OSM offline e online</string>
|
||||
<string name="osmand_plus_short_description_80_chars">OsmAnd é uma aplicação de navegação de código aberto para mapas off-line e on-line</string>
|
||||
<string name="osmand_plus_short_description_80_chars">OsmAnd é uma aplicação de navegação de código aberto para mapas offline e online</string>
|
||||
<string name="filterpoi_activity">Criar filtro de POI</string>
|
||||
<string name="select_navigation_mode">Meio de transporte:</string>
|
||||
<string name="day_night_info_description">Nascer do sol: %1$s
|
||||
|
@ -776,8 +776,8 @@
|
|||
<string name="map_widget_renderer">Estilo de renderização</string>
|
||||
<string name="layer_map_appearance">Configurar ecrã</string>
|
||||
<string name="show_lanes">Mostrar faixas de rodagem</string>
|
||||
<string name="avoid_unpaved">Sem estradas não pavimentadas</string>
|
||||
<string name="avoid_ferries">Sem balsas/ferries</string>
|
||||
<string name="avoid_unpaved">Evitar estradas não pavimentadas</string>
|
||||
<string name="avoid_ferries">Evitar balsas/ferries</string>
|
||||
<string name="avoid_in_routing_title">Evitar…</string>
|
||||
<string name="map_widget_fluorescent">Rotas fluorescentes</string>
|
||||
<string name="map_widget_show_ruler">Régua</string>
|
||||
|
@ -810,7 +810,7 @@
|
|||
<string name="rendering_attr_roadColors_description">Selecione um esquema de cores de estrada:</string>
|
||||
<string name="rendering_attr_roadColors_name">Esquema de cores</string>
|
||||
<string name="map_widget_show_destination_arrow">Ver direção para o destino</string>
|
||||
<string name="enable_plugin_monitoring_services">Ative a extensão de \"Gravação de viagem\" para usar serviços de registo de posição (registo GPX, rastreamento on-line)</string>
|
||||
<string name="enable_plugin_monitoring_services">Ative a extensão de \"Gravar viagem\" para usar serviços de registo de posição (registo GPX, rastreamento online)</string>
|
||||
<string name="non_optimal_route_calculation">Calcular rota possivelmente não ideal em longas distâncias</string>
|
||||
<string name="gps_not_available">Ative o GPS nas configurações</string>
|
||||
<string name="map_widget_monitoring_services">Serviços de registo</string>
|
||||
|
@ -852,7 +852,7 @@
|
|||
<string name="search_villages_and_postcodes">Pesquisar mais povoações/códigos postais</string>
|
||||
<string name="dropbox_plugin_description">Sincroniza trilhos e notas de vídeo/áudio com a sua conta Dropbox.</string>
|
||||
<string name="av_def_action_video">Gravar vídeo</string>
|
||||
<string name="av_def_action_audio">Gravar audio</string>
|
||||
<string name="av_def_action_audio">Gravar áudio</string>
|
||||
<string name="av_widget_action_descr">Ação predefinida do widget:</string>
|
||||
<string name="av_widget_action">Ação widget padrão</string>
|
||||
<string name="av_video_format">Formato de saída de vídeo</string>
|
||||
|
@ -883,7 +883,7 @@
|
|||
<string name="clear_dest_confirm">Tem a certeza que quer limpar o seu destino (e destinos intermédios)\?</string>
|
||||
<string name="precise_routing_mode_descr">Calcula rotas precisas sem falhas, mas com distância limitada e lento.</string>
|
||||
<string name="precise_routing_mode">Roteamento preciso (alfa)</string>
|
||||
<string name="recording_context_menu_precord">Tirar uma foto</string>
|
||||
<string name="recording_context_menu_precord">Tirar uma fotografia</string>
|
||||
<string name="dropbox_plugin_name">Extensão Dropbox</string>
|
||||
<string name="intermediate_points_change_order">Alterar ordem</string>
|
||||
<string name="srtm_paid_version_msg">Por favor, considere comprar a extensão \'Curvas de nível\' para apoiar o desenvolvimento.</string>
|
||||
|
@ -891,7 +891,7 @@
|
|||
<string name="av_def_action_choose">A pedido\?</string>
|
||||
<string name="av_video_format_descr">Formato de saída de vídeo:</string>
|
||||
<string name="av_use_external_recorder_descr">Usar gravador do sistema para vídeo.</string>
|
||||
<string name="av_use_external_camera_descr">Utilizar a aplicação do sistema para fotos.</string>
|
||||
<string name="av_use_external_camera_descr">Utilizar a aplicação do sistema para tirar fotografias.</string>
|
||||
<string name="av_use_external_camera">Usar aplicação da câmara</string>
|
||||
<string name="recording_playing">A reproduzir o áudio da gravação.
|
||||
\n%1$s</string>
|
||||
|
@ -901,7 +901,7 @@
|
|||
<string name="shared_string_control_stop">Parar</string>
|
||||
<string name="shared_string_control_start">Iniciar</string>
|
||||
<string name="map_widget_av_notes">Notas de áudio/vídeo</string>
|
||||
<string name="osmand_srtm_short_description_80_chars">Extensão OsmAnd para curvas de nível off-line</string>
|
||||
<string name="osmand_srtm_short_description_80_chars">Extensão OsmAnd para curvas de nível offline</string>
|
||||
<string name="map_widget_distancemeasurement">Medição da distância</string>
|
||||
<string name="audionotes_location_not_defined">O local para associar à nota ainda não está definido. Toque em \"Usar posição…\" para atribuir uma nota ao local especificado.</string>
|
||||
<string name="map_widget_audionotes">Notas de áudio</string>
|
||||
|
@ -909,8 +909,8 @@
|
|||
<string name="audionotes_plugin_name">Notas de áudio/vídeo</string>
|
||||
<string name="index_srtm_parts">Partes</string>
|
||||
<string name="index_srtm_ele">Curvas de nível</string>
|
||||
<string name="recording_photo_description">Foto %1$s de %2$s</string>
|
||||
<string name="av_def_action_picture">Tirar uma foto</string>
|
||||
<string name="recording_photo_description">Fotografia %1$s de %2$s</string>
|
||||
<string name="av_def_action_picture">Tirar uma fotografia</string>
|
||||
<string name="osmand_srtm_long_description_1000_chars">Esta extensão disponibiliza \'Curvas de nível\' e \'Sombras de relevo\', que podem ser aplicadas nos mapas padrão do OsmAnd. Estas funcionalidades podem ser apreciadas por atletas, caminhantes e qualquer pessoa interessada na informação do relevo de uma paisagem.
|
||||
\n
|
||||
\nOs dados globais (entre as latitudes 70° norte e 70° sul) são baseados nas medições do SRTM (Shuttle Radar Topography Mission) e do ASTER (Advanced Spaceborn Thermal Emission and Reflection Radiometer), um instrumento de imagens no satélite \'Terra\', o satélite principal do Sistema de Observação da Terra da NASA. O ASTER é um esforço conjunto da NASA, do Ministério da Economia, Comércio e Indústria do Japão e do Sistema Espacial Japonês (J-spacesystems).</string>
|
||||
|
@ -920,7 +920,7 @@
|
|||
<string name="srtm_plugin_name">Curvas de nível</string>
|
||||
<string name="download_select_map_types">Outros mapas</string>
|
||||
<string name="download_srtm_maps">Curvas de nível</string>
|
||||
<string name="rendering_attr_noAdminboundaries_name">Limites</string>
|
||||
<string name="rendering_attr_noAdminboundaries_name">Fronteiras regionais</string>
|
||||
<string name="rendering_attr_noAdminboundaries_description">Ocultar a visualização de limites regionais (níveis de administração 5 – 9).</string>
|
||||
<string name="recording_context_menu_show">Ver</string>
|
||||
<string name="item_unchecked">desmarcado</string>
|
||||
|
@ -948,7 +948,7 @@
|
|||
<string name="files_limit">%1$d ficheiros restantes</string>
|
||||
<string name="available_downloads_left">Faltam %1$d ficheiros para descarregar</string>
|
||||
<string name="install_paid">Versão completa</string>
|
||||
<string name="cancel_route">Descartar a rota\?</string>
|
||||
<string name="cancel_route">Cancelar a rota\?</string>
|
||||
<string name="cancel_navigation">Parar navegação</string>
|
||||
<string name="local_osm_changes_backup_successful">Ficheiro de alterações OSM %1$s gerado</string>
|
||||
<string name="local_osm_changes_backup_failed">Não foi possível fazer a cópia de segurança das alterações do OSM.</string>
|
||||
|
@ -1018,7 +1018,7 @@
|
|||
<string name="av_camera_focus_auto">Focagem automática</string>
|
||||
<string name="av_camera_focus_hiperfocal">Foco hiperfocal</string>
|
||||
<string name="av_camera_focus_edof">Profundidade de campo alargada (EDOF)</string>
|
||||
<string name="av_camera_focus_infinity">O foco está definido como infinito</string>
|
||||
<string name="av_camera_focus_infinity">Focar infinito</string>
|
||||
<string name="av_camera_focus_macro">Focagem macro (close-up)</string>
|
||||
<string name="av_camera_focus_continuous">A câmara tenta focar continuadamente</string>
|
||||
<string name="av_photo_play_sound">Reproduzir o som do obturador da câmara</string>
|
||||
|
@ -1082,7 +1082,7 @@
|
|||
<string name="app_mode_aircraft">Aeronave</string>
|
||||
<string name="local_osm_changes_delete_all_confirm">Tem a certeza que quer eliminar %1$d alterações no OSM\?</string>
|
||||
<string name="shared_string_delete_all">Eliminar tudo</string>
|
||||
<string name="amenity_type_osmwiki">Wikipédia (off-line)</string>
|
||||
<string name="amenity_type_osmwiki">Wikipédia (offline)</string>
|
||||
<string name="amenity_type_seamark">Marca marítima</string>
|
||||
<string name="app_modes_choose_descr">Escolha os perfis a mostrar.</string>
|
||||
<string name="app_modes_choose">Perfis da aplicação</string>
|
||||
|
@ -1113,7 +1113,7 @@
|
|||
<string name="lang_en">Inglês</string>
|
||||
<string name="lang_af">Africâner</string>
|
||||
<string name="lang_hy">Arménio</string>
|
||||
<string name="calculate_osmand_route_without_internet">Cálculo off-line do segmento de rota OsmAnd</string>
|
||||
<string name="calculate_osmand_route_without_internet">Calcular segmento de rota OsmAnd sem Internet</string>
|
||||
<string name="gpx_option_calculate_first_last_segment">Calcular rota de OsmAnd para o primeiro e último segmento da rota</string>
|
||||
<string name="use_displayed_track_for_navigation">Usar o trajeto indicado para a navegação\?</string>
|
||||
<string name="keep_and_add_destination_point">Adicionar como destino posterior</string>
|
||||
|
@ -1125,13 +1125,13 @@
|
|||
<string name="route_info">Informações da rota</string>
|
||||
<string name="routing_attr_prefer_motorway_name">Preferir autoestradas</string>
|
||||
<string name="routing_attr_prefer_motorway_description">Preferir autoestradas</string>
|
||||
<string name="routing_attr_avoid_toll_name">Sem estradas com portagem</string>
|
||||
<string name="routing_attr_avoid_toll_name">Evitar portagens</string>
|
||||
<string name="routing_attr_avoid_toll_description">Evitar estradas com portagem</string>
|
||||
<string name="routing_attr_avoid_unpaved_name">Sem estradas não pavimentadas</string>
|
||||
<string name="routing_attr_avoid_unpaved_name">Evitar estradas não pavimentadas</string>
|
||||
<string name="routing_attr_avoid_unpaved_description">Evitar estradas não pavimentadas</string>
|
||||
<string name="routing_attr_avoid_ferries_name">Sem balsas/ferries</string>
|
||||
<string name="routing_attr_avoid_ferries_name">Evitar balsas/ferries</string>
|
||||
<string name="routing_attr_avoid_ferries_description">Evita balsas/ferries</string>
|
||||
<string name="routing_attr_avoid_motorway_name">Sem autoestradas</string>
|
||||
<string name="routing_attr_avoid_motorway_name">Evitar autoestradas</string>
|
||||
<string name="routing_attr_avoid_motorway_description">Evita autoestradas</string>
|
||||
<string name="routing_attr_weight_name">Peso máximo</string>
|
||||
<string name="routing_attr_weight_description">Especifique o limite de peso permitido para veículos em rotas.</string>
|
||||
|
@ -1141,7 +1141,7 @@
|
|||
<string name="copying_osmand_one_file_descr">A copiar o ficheiro (%s) para novo destino…</string>
|
||||
<string name="copying_osmand_files_descr">A copiar os ficheiros OsmAnd para o novo destino (%s)…</string>
|
||||
<string name="copying_osmand_files">A copiar ficheiros de dados do OsmAnd…</string>
|
||||
<string name="calculate_osmand_route_gpx">Cálculo de rota OsmAnd off-line</string>
|
||||
<string name="calculate_osmand_route_gpx">Cálculo de rota OsmAnd offline</string>
|
||||
<string name="app_mode_truck">Camião</string>
|
||||
<string name="lang_eu">Basco</string>
|
||||
<string name="lang_be">Bielorrusso</string>
|
||||
|
@ -1323,7 +1323,7 @@
|
|||
<string name="storage_directory">Armazenamento do mapa</string>
|
||||
<string name="shared_string_copy">Copiar</string>
|
||||
<string name="filter_poi_hint">Filtrar por nome</string>
|
||||
<string name="search_poi_category_hint">Digite para pesquisar tudo</string>
|
||||
<string name="search_poi_category_hint">Digite para pesquisar em tudo</string>
|
||||
<string name="shared_string_is_open">Aberto agora</string>
|
||||
<string name="rendering_attr_OSMMapperAssistant_name">Assistente de mapeador OSM</string>
|
||||
<string name="agps_info">Informação A-GPS</string>
|
||||
|
@ -1353,7 +1353,7 @@
|
|||
<string name="rendering_attr_streetLighting_name">Iluminação pública</string>
|
||||
<string name="rendering_value__name">Predefinido</string>
|
||||
<string name="rendering_value_highContrastRoads_name">Estradas em alto contraste</string>
|
||||
<string name="welcome_text">OsmAnd fornece mapas de navegação globais e navegação off-line.</string>
|
||||
<string name="welcome_text">OsmAnd fornece mapas de navegação globais e navegação offline.</string>
|
||||
<string name="welcome_header">Bem-vindo(a)</string>
|
||||
<string name="current_route">Rota atual</string>
|
||||
<string name="osm_changes_added_to_local_edits">Mudanças no OSM adicionadas ao conjunto de alterações local</string>
|
||||
|
@ -1398,7 +1398,7 @@
|
|||
<string name="shared_string_currently_recording_track">A gravar o trajeto</string>
|
||||
<string name="shared_string_audio">Áudio</string>
|
||||
<string name="shared_string_video">Vídeo</string>
|
||||
<string name="shared_string_photo">Foto</string>
|
||||
<string name="shared_string_photo">Fotografia</string>
|
||||
<string name="route_points">Pontos de rota</string>
|
||||
<string name="track_segments">Segmentos do trajeto</string>
|
||||
<string name="track_points">Pontos do trajeto</string>
|
||||
|
@ -1410,13 +1410,13 @@
|
|||
<string name="share_note">Partilhar nota</string>
|
||||
<string name="location_on_map">Posição:\n Lat %1$s\n Lon %2$s</string>
|
||||
<string name="notes">Notas de áudio/vídeo</string>
|
||||
<string name="online_map">Mapa on-line</string>
|
||||
<string name="online_map">Mapa online</string>
|
||||
<string name="roads_only">Apenas estradas</string>
|
||||
<string name="rendering_attr_pisteRoutes_name">Pistas de esqui</string>
|
||||
<string name="free">%1$s livre</string>
|
||||
<string name="device_memory">Memória do dispositivo</string>
|
||||
<string name="world_ski_missing">Para mostrar mapas de esqui, tem de descarregar o mapa off-line especial.</string>
|
||||
<string name="nautical_maps_missing">Para mostrar mapas náuticos, tem de descarregar o mapa off-line especial.</string>
|
||||
<string name="world_ski_missing">Para mostrar mapas de esqui, tem de descarregar o mapa offline especial.</string>
|
||||
<string name="nautical_maps_missing">Para mostrar mapas náuticos, tem de descarregar o mapa offline especial.</string>
|
||||
<string name="edit_group">Editar grupo</string>
|
||||
<string name="parking_place">Lugar de estacionamento</string>
|
||||
<string name="version_settings">Compilações</string>
|
||||
|
@ -1426,7 +1426,7 @@
|
|||
<string name="wake_on_voice">Ligar o ecrã</string>
|
||||
<string name="configure_map">Configurar mapa</string>
|
||||
<string name="shared_string_waypoints">Pontos de rota</string>
|
||||
<string name="shared_string_dismiss">Descartar</string>
|
||||
<string name="shared_string_dismiss">Cancelar</string>
|
||||
<string name="rendering_category_others">Outros atributos do mapa</string>
|
||||
<string name="rendering_attr_showAccess_name">Mostrar restrições de acesso e portagens</string>
|
||||
<string name="rendering_attr_showSurfaceGrade_name">Mostrar qualidade da via</string>
|
||||
|
@ -1435,7 +1435,7 @@
|
|||
<string name="rendering_attr_coloredBuildings_name">Colorir edifícios por tipo</string>
|
||||
<string name="rendering_attr_alpineHiking_name">Escala de montanhismo (SAC)</string>
|
||||
<string name="rendering_attr_hikingRoutesOSMC_name">Camada superior de símbolos de montanhismo</string>
|
||||
<string name="rendering_attr_showCycleRoutes_name">Mostrar rotas para bicicletas</string>
|
||||
<string name="rendering_attr_showCycleRoutes_name">Rotas para bicicletas</string>
|
||||
<string name="rendering_attr_hideBuildings_name">Edifícios</string>
|
||||
<string name="rendering_attr_trolleybusRoutes_name">Rotas de troleicarros</string>
|
||||
<string name="favorite_category_dublicate_message">Por favor, use um nome de categoria que ainda não exista.</string>
|
||||
|
@ -1471,7 +1471,7 @@
|
|||
<string name="show_on_start_description">\'Desligado\' abre o mapa diretamente.</string>
|
||||
<string name="show_on_start">Mostrar no arranque</string>
|
||||
<string name="copied_to_clipboard">Copiado para a área de transferência</string>
|
||||
<string name="osm_save_offline">Guardar off-line</string>
|
||||
<string name="osm_save_offline">Guardar offline</string>
|
||||
<string name="osm_edit_modified_poi">POI do OpenStreetMap alterado</string>
|
||||
<string name="impassable_road_desc">Escolha as estradas que quer evitar durante a navegação.</string>
|
||||
<string name="shared_string_sound">Som</string>
|
||||
|
@ -1513,7 +1513,7 @@
|
|||
<string name="share_osm_edits_subject">Edições OSM partilhadas via OsmAnd</string>
|
||||
<string name="read_more">Ler mais</string>
|
||||
<string name="whats_new">Novidades</string>
|
||||
<string name="rendering_attr_hideProposed_name">Objetos planeados</string>
|
||||
<string name="rendering_attr_hideProposed_name">Elementos com construção planeada</string>
|
||||
<string name="shared_string_upload">Enviar</string>
|
||||
<string name="osm_edit_created_poi">POI OSM adicionado</string>
|
||||
<string name="world_map_download_descr">Mapa base mundial (cobrindo o mundo inteiro em baixo nível de ampliação) ausente ou ultrapassado. Por favor, considere descarregá-lo para uma visão global.</string>
|
||||
|
@ -1535,7 +1535,7 @@
|
|||
<string name="av_locations_descr">Ficheiro GPX com localizações.</string>
|
||||
<string name="av_locations">Localizações</string>
|
||||
<string name="plugin_settings">Extensões</string>
|
||||
<string name="routing_attr_avoid_shuttle_train_name">Sem comboio vaivém</string>
|
||||
<string name="routing_attr_avoid_shuttle_train_name">Evitar comboios vaivém</string>
|
||||
<string name="routing_attr_avoid_shuttle_train_description">Evita usar comboios vaivém, em pequenos trajetos predefinidos como aeroportos</string>
|
||||
<string name="traffic_warning_hazard">Perigo</string>
|
||||
<string name="rendering_value_boldOutline_name">Contorno em negrito</string>
|
||||
|
@ -1545,8 +1545,8 @@
|
|||
<string name="rendering_value_defaultTranslucentCyan_name">Padrão (ciano translúcido)</string>
|
||||
<string name="rendering_attr_currentTrackColor_name">Cor GPX</string>
|
||||
<string name="rendering_attr_currentTrackColor_description">Cor GPX</string>
|
||||
<string name="rendering_attr_currentTrackWidth_name">Espessura GPX</string>
|
||||
<string name="rendering_attr_currentTrackWidth_description">Espessura GPX</string>
|
||||
<string name="rendering_attr_currentTrackWidth_name">Espessura dos trilhos GPX</string>
|
||||
<string name="rendering_attr_currentTrackWidth_description">Espessura dos trilhos GPX</string>
|
||||
<string name="rendering_value_red_name">Vermelho</string>
|
||||
<string name="rendering_value_translucent_red_name">Vermelho translúcido</string>
|
||||
<string name="rendering_value_translucent_orange_name">Laranja translúcido</string>
|
||||
|
@ -1593,7 +1593,7 @@
|
|||
<string name="download_wikipedia_files">Quer descarregar dados adicionais da Wikipédia (%1$s MB)\?</string>
|
||||
<string name="gps_network_not_enabled">O serviço de localização não está ativado. Quer ativá-lo\?</string>
|
||||
<string name="shared_string_import2osmand">Importar para o OsmAnd</string>
|
||||
<string name="read_full_article">Ler o artigo completo (on-line)</string>
|
||||
<string name="read_full_article">Ler o artigo completo (na Internet)</string>
|
||||
<string name="shared_string_wikipedia">Wikipédia</string>
|
||||
<string name="local_indexes_cat_wiki">Wikipédia</string>
|
||||
<string name="shared_string_show_details">Mostrar detalhes</string>
|
||||
|
@ -1659,7 +1659,7 @@
|
|||
<string name="map_mode">Modo do mapa</string>
|
||||
<string name="rendering_value_thin_name">Fino</string>
|
||||
<string name="rendering_value_medium_name">Médio</string>
|
||||
<string name="rendering_value_bold_name">Negrito</string>
|
||||
<string name="rendering_value_bold_name">Grosso</string>
|
||||
<string name="storage_permission_restart_is_required">Agora a aplicação está autorizada a gravar no armazenamento externo, mas primeiro é necessário reiniciar a aplicação.</string>
|
||||
<string name="shared_string_move_up">Mover ↑</string>
|
||||
<string name="shared_string_move_down">Mover ↓</string>
|
||||
|
@ -1754,7 +1754,7 @@
|
|||
<string name="map_markers">Marcadores</string>
|
||||
<string name="map_marker">Marcador de mapa</string>
|
||||
<string name="consider_turning_polygons_off">É recomendável desativar a renderização de polígono.</string>
|
||||
<string name="rendering_attr_showMtbRoutes_name">Mostrar trilhos de bicicletas de montanha</string>
|
||||
<string name="rendering_attr_showMtbRoutes_name">Trilhos de bicicletas BTT</string>
|
||||
<string name="show_polygons">Mostrar polígonos</string>
|
||||
<string name="find_parking">Encontrar estacionamento</string>
|
||||
<string name="shared_string_status">Situação</string>
|
||||
|
@ -1768,7 +1768,7 @@
|
|||
<string name="road_blocked">Estrada bloqueada</string>
|
||||
<string name="shared_string_select">Selecionar</string>
|
||||
<string name="switch_start_finish">Inverter ponto de partida e destino</string>
|
||||
<string name="rendering_attr_hideIcons_name">Ícones POI</string>
|
||||
<string name="rendering_attr_hideIcons_name">Ícones dos POI</string>
|
||||
<string name="item_removed">Item removido</string>
|
||||
<string name="n_items_removed">Itens removidos</string>
|
||||
<string name="shared_string_undo_all">Desfazer tudo</string>
|
||||
|
@ -1776,7 +1776,7 @@
|
|||
<string name="starting_point">Ponto de partida</string>
|
||||
<string name="rec_split">Divisão das gravações</string>
|
||||
<string name="rec_split_title">Usar divisão das gravações</string>
|
||||
<string name="rec_split_clip_length">Duração do recorte</string>
|
||||
<string name="rec_split_clip_length">Duração da divisão</string>
|
||||
<string name="rec_split_clip_length_desc">Limite de tempo máximo para clipes gravados.</string>
|
||||
<string name="lang_mk">Macedónio</string>
|
||||
<string name="lang_sh">Servo-Croata</string>
|
||||
|
@ -1807,14 +1807,14 @@
|
|||
<string name="search_another_country">Selecionar outra região</string>
|
||||
<string name="shared_string_change">Alterar</string>
|
||||
<string name="storage_directory_card">Cartão de memória</string>
|
||||
<string name="skip_map_downloading_desc">Não tem nenhum mapa off-line instalado. Pode escolher um mapa na lista ou descarregar mapas mais tarde através do \'menu - %1$s\'.</string>
|
||||
<string name="skip_map_downloading_desc">Não tem nenhum mapa offline instalado. Pode escolher um mapa na lista ou descarregar mapas mais tarde através do \'menu - %1$s\'.</string>
|
||||
<string name="shared_string_markers">Marcadores</string>
|
||||
<string name="coordinates_format">Formato de coordenadas</string>
|
||||
<string name="use_system_keyboard">Usar teclado do sistema</string>
|
||||
<string name="fast_coordinates_input_descr">Escolher formato de introdução de coordenada. Poderá sempre alterá-lo ao selecionar \'Opções\'.</string>
|
||||
<string name="fast_coordinates_input">Introdução rápida de coordenadas</string>
|
||||
<string name="routing_attr_avoid_ice_roads_fords_name">Sem estradas de gelo ou vaus</string>
|
||||
<string name="routing_attr_avoid_ice_roads_fords_description">Evitar estradas de gelo e vaus.</string>
|
||||
<string name="routing_attr_avoid_ice_roads_fords_name">Evitar estradas de gelo ou vaus</string>
|
||||
<string name="routing_attr_avoid_ice_roads_fords_description">Evitar estradas de gelo e vaus (passagens em riachos baixos).</string>
|
||||
<string name="use_location">Usar posição</string>
|
||||
<string name="add_location_as_first_point_descr">Adicionar a sua posição como ponto de partida para planear uma rota perfeita.</string>
|
||||
<string name="my_location">A minha posição</string>
|
||||
|
@ -1825,8 +1825,8 @@
|
|||
<string name="marker_save_as_track_descr">Exporte os seus marcadores para um ficheiro que pode especificar aqui:</string>
|
||||
<string name="move_to_history">Mover para histórico</string>
|
||||
<string name="group_will_be_removed_after_restart">O grupo terá desaparecido na próxima vez que iniciar a aplicação.</string>
|
||||
<string name="show_guide_line">Mostrar linhas direcionais</string>
|
||||
<string name="show_arrows_on_the_map">Mostrar setas no mapa</string>
|
||||
<string name="show_guide_line">Mostrar linhas para marcadores</string>
|
||||
<string name="show_arrows_on_the_map">Mostrar setas para marcadores</string>
|
||||
<string name="show_passed">Mostrar passado</string>
|
||||
<string name="hide_passed">Esconder o passado</string>
|
||||
<string name="remove_from_map_markers">Remover dos \'Marcadores do mapa\'</string>
|
||||
|
@ -1900,15 +1900,15 @@
|
|||
<string name="shared_string_install">Instalar</string>
|
||||
<string name="improve_coverage_mapillary">Melhorar cobertura fotográfica com Mapillary</string>
|
||||
<string name="improve_coverage_install_mapillary_desc">Instale o Mapillary para adicionar fotos a este local do mapa.</string>
|
||||
<string name="online_photos">Fotos on-line</string>
|
||||
<string name="shared_string_add_photos">Adicionar fotos</string>
|
||||
<string name="no_photos_descr">Não há fotos aqui.</string>
|
||||
<string name="online_photos">Fotografias na Internet</string>
|
||||
<string name="shared_string_add_photos">Adicionar fotografias</string>
|
||||
<string name="no_photos_descr">Não há fotografias aqui.</string>
|
||||
<string name="mapillary_action_descr">Partilhe as suas imagens ao nível do solo no Mapillary.</string>
|
||||
<string name="mapillary_widget">Widget Mapillary</string>
|
||||
<string name="mapillary_widget_descr">Permite contribuir rapidamente para o Mapillary.</string>
|
||||
<string name="mapillary_descr">Fotos on-line ao nível da rua para todos. Descubra locais, colabore, capture o mundo.</string>
|
||||
<string name="mapillary_descr">Fotografias online ao nível da rua para todos. Descubra locais, colabore, capture o mundo.</string>
|
||||
<string name="mapillary">Mapillary</string>
|
||||
<string name="plugin_mapillary_descr">Fotos ao nível da rua para todos. Descubra locais, colabore, capture o mundo.</string>
|
||||
<string name="plugin_mapillary_descr">Fotografias ao nível da rua para todos. Descubra locais, colabore, capture o mundo.</string>
|
||||
<string name="private_access_routing_req">O seu destino está localizado numa área de acesso privado. Permitir uso de estradas privadas para esta viagem\?</string>
|
||||
<string name="restart_search">Reiniciar pesquisa</string>
|
||||
<string name="increase_search_radius">Aumentar raio de pesquisa</string>
|
||||
|
@ -2023,10 +2023,10 @@
|
|||
<string name="rendering_value_high_name">Alto</string>
|
||||
<string name="rendering_value_medium_w_name">Médio</string>
|
||||
<string name="rendering_value_low_name">Baixo</string>
|
||||
<string name="rendering_attr_contourWidth_description">Largura das curvas de nível</string>
|
||||
<string name="rendering_attr_contourWidth_name">Largura das curvas de nível</string>
|
||||
<string name="rendering_attr_contourWidth_description">Espessura das curvas de nível</string>
|
||||
<string name="rendering_attr_contourWidth_name">Espessura das curvas de nível</string>
|
||||
<string name="rendering_attr_hideWaterPolygons_description">Água</string>
|
||||
<string name="rendering_attr_hideWaterPolygons_name">Ocultar água</string>
|
||||
<string name="rendering_attr_hideWaterPolygons_name">Corpos de água largos</string>
|
||||
<string name="routing_attr_allow_motorway_name">Utilizar autoestradas</string>
|
||||
<string name="routing_attr_allow_motorway_description">Permitir autoestradas.</string>
|
||||
<string name="wiki_around">Artigos da Wikipédia próximos</string>
|
||||
|
@ -2046,7 +2046,7 @@
|
|||
<string name="shared_string_paused">Em pausa</string>
|
||||
<string name="shared_string_trip">Viagem</string>
|
||||
<string name="shared_string_recorded">Gravado</string>
|
||||
<string name="shared_string_record">Registo</string>
|
||||
<string name="shared_string_record">Gravar</string>
|
||||
<string name="gpx_logging_no_data">Sem dados</string>
|
||||
<string name="rendering_attr_contourColorScheme_description">Esquema de cores das curvas de nível</string>
|
||||
<string name="save_track_min_speed">Velocidade mínima para registo</string>
|
||||
|
@ -2127,13 +2127,13 @@
|
|||
<string name="get_osmand_live">Adquira o OsmAnd Live para desbloquear todas as funcionalidades: atualizações diárias de mapas com descarregamentos ilimitados, todas as extensões pagas e gratuitas, Wikipédia, Wikivoyage e muito mais.</string>
|
||||
<string name="unirs_render_descr">Alteração do estilo padrão para aumentar o contraste de caminhos pedestres e ciclovias. Usa cores clássicas do Mapnik.</string>
|
||||
<string name="shared_string_bookmark">Favorito</string>
|
||||
<string name="hide_full_description">Esconder descrição completa</string>
|
||||
<string name="hide_full_description">Ocultar descrição completa</string>
|
||||
<string name="show_full_description">Mostrar a descrição completa</string>
|
||||
<string name="thank_you_for_feedback">Obrigado pelos seus comentários</string>
|
||||
<string name="search_street">Procurar rua</string>
|
||||
<string name="shared_string_restore">Restaurar</string>
|
||||
<string name="keep_passed_markers_descr">Os marcadores adicionados como um grupo de favoritos ou ponto de rota GPX marcados como Passado permanecerão no mapa. Se o grupo não estiver ativo, os marcadores desaparecerão do mapa.</string>
|
||||
<string name="keep_passed_markers">Manter marcadores passados no mapa</string>
|
||||
<string name="keep_passed_markers_descr">Os marcadores adicionados como um grupo de favoritos ou ponto de rota GPX marcados como visitado (passado) permanecerão no mapa. Se o grupo não estiver ativo, os marcadores desaparecerão do mapa.</string>
|
||||
<string name="keep_passed_markers">Manter marcadores visitados</string>
|
||||
<string name="more_transport_on_stop_hint">Outros transportes disponíveis nesta paragem.</string>
|
||||
<string name="ask_for_location_permission">Por favor, conceda ao OsmAnd o acesso à localização para continuar.</string>
|
||||
<string name="markers_remove_dialog_msg">Eliminar o marcador de mapa \'%s\'\?</string>
|
||||
|
@ -2213,7 +2213,7 @@
|
|||
<string name="shared_string_wifi_only">Apenas em Wi-Fi</string>
|
||||
<string name="select_travel_book">Selecione um livro de viagem</string>
|
||||
<string name="shared_string_travel_book">Livro de viagens</string>
|
||||
<string name="online_webpage_warning">Página disponível apenas on-line. Abrir no navegador da web\?</string>
|
||||
<string name="online_webpage_warning">Página disponível apenas online. Abrir no navegador da web\?</string>
|
||||
<string name="images_cache">Cache de imagens</string>
|
||||
<string name="delete_search_history">Eliminar histórico de pesquisa</string>
|
||||
<string name="download_images">Descarregar imagens</string>
|
||||
|
@ -2240,11 +2240,11 @@
|
|||
<string name="enter_lon">Digite a longitude</string>
|
||||
<string name="enter_lat">Digite a latitude</string>
|
||||
<string name="enter_lat_and_lon">Digite a latitude e a longitude</string>
|
||||
<string name="dd_mm_ss_format">DD°MM′SS″</string>
|
||||
<string name="dd_dddddd_format">DD.DDDDDD°</string>
|
||||
<string name="dd_ddddd_format">DD.DDDDD°</string>
|
||||
<string name="dd_mm_mmmm_format">DD°MM.MMMM′</string>
|
||||
<string name="dd_mm_mmm_format">DD°MM.MMM′</string>
|
||||
<string name="dd_mm_ss_format">GG°MM′SS″</string>
|
||||
<string name="dd_dddddd_format">GG.GGGGGG°</string>
|
||||
<string name="dd_ddddd_format">GG.GGGGG°</string>
|
||||
<string name="dd_mm_mmmm_format">GG°MM.MMMM′</string>
|
||||
<string name="dd_mm_mmm_format">GG°MM.MMM′</string>
|
||||
<string name="east_abbreviation">E</string>
|
||||
<string name="west_abbreviation">O</string>
|
||||
<string name="south_abbreviation">S</string>
|
||||
|
@ -2261,7 +2261,7 @@
|
|||
<string name="first_intermediate_dest_description">Adicionar paragem inicial</string>
|
||||
<string name="subsequent_dest_description">Mover destino para cima e criar destino</string>
|
||||
<string name="show_closed_notes">Mostrar notas fechadas</string>
|
||||
<string name="switch_osm_notes_visibility_desc">Mostrar ou ocultar notas do OpenStreetMap no mapa.</string>
|
||||
<string name="switch_osm_notes_visibility_desc">Mostrar notas do OpenStreetMap.</string>
|
||||
<string name="gpx_file_desc">GPX - adequado para exportar para o JOSM ou outros editores do OSM.</string>
|
||||
<string name="osc_file_desc">OSC - adequado para exportar para o OSM.</string>
|
||||
<string name="shared_string_gpx_file">Ficheiro GPX</string>
|
||||
|
@ -2300,7 +2300,7 @@
|
|||
<string name="one_tap_active_descr">Toque num marcador no mapa para movê-lo para a parte superior dos marcadores ativos sem abrir o menu de contexto.</string>
|
||||
<string name="one_tap_active">\'Um toque\' ativo</string>
|
||||
<string name="empty_state_av_notes">Faça notas!</string>
|
||||
<string name="empty_state_av_notes_desc">Adicione notas de áudio, vídeo ou foto em qualquer ponto do mapa, usando o widget ou o menu de contexto.</string>
|
||||
<string name="empty_state_av_notes_desc">Adicione notas de áudio, vídeo ou fotografia em qualquer ponto do mapa, usando o widget ou o menu de contexto.</string>
|
||||
<string name="notes_by_date">Notas de áudio/vídeo por data</string>
|
||||
<string name="by_date">Por data</string>
|
||||
<string name="by_type">Por tipo</string>
|
||||
|
@ -2321,7 +2321,7 @@
|
|||
<string name="shared_string_two">Dois</string>
|
||||
<string name="shared_string_one">Um</string>
|
||||
<string name="show_guide_line_descr">Mostrar linha direcional desde a sua posição até os locais dos marcadores ativos.</string>
|
||||
<string name="show_arrows_descr">Mostrar uma ou duas setas indicando a direção para os marcadores ativos.</string>
|
||||
<string name="show_arrows_descr">Mostrar uma ou duas setas indicando a direção em linha reta para os marcadores ativos.</string>
|
||||
<string name="distance_indication_descr">Escolher como mostrar a distância para os marcadores ativos.</string>
|
||||
<string name="active_markers_descr">Especifique a quantidade de indicadores de orientação.</string>
|
||||
<string name="digits_quantity">Número de casas decimais</string>
|
||||
|
@ -2330,7 +2330,7 @@
|
|||
<string name="show_number_pad">Mostrar teclado numérico</string>
|
||||
<string name="shared_string_paste">Colar</string>
|
||||
<string name="go_to_next_field">Próximo campo</string>
|
||||
<string name="rename_marker">Renomear marcador</string>
|
||||
<string name="rename_marker">Alterar nome do marcador</string>
|
||||
<string name="tap_on_map_to_hide_interface_descr">Um toque no mapa mostra/esconde os botões de controlo e widgets.</string>
|
||||
<string name="tap_on_map_to_hide_interface">Modo ecrã cheio</string>
|
||||
<string name="mark_passed">Marcador visitado</string>
|
||||
|
@ -2459,9 +2459,9 @@
|
|||
<string name="forward">Avançar</string>
|
||||
<string name="home">Painel de controlo</string>
|
||||
<string name="live_monitoring_m_descr">Enviar o rastreamento para um serviço web especificado, se o registo de GPX estiver ligado.</string>
|
||||
<string name="live_monitoring_m">Rastreamento on-line (requer GPX)</string>
|
||||
<string name="live_monitoring_start">Iniciar rastreamento on-line</string>
|
||||
<string name="live_monitoring_stop">Parar rastreamento on-line</string>
|
||||
<string name="live_monitoring_m">Rastreamento online (requer GPX)</string>
|
||||
<string name="live_monitoring_start">Iniciar rastreamento online</string>
|
||||
<string name="live_monitoring_stop">Parar rastreamento online</string>
|
||||
<string name="gpx_start_new_segment">Iniciar novo segmento</string>
|
||||
<string name="rendering_attr_hideNonVehicleHighways_name">Estradas não transitáveis</string>
|
||||
<string name="rendering_attr_hideText_name">Texto</string>
|
||||
|
@ -2487,9 +2487,9 @@
|
|||
<string name="lang_zh_cn">Chinês (simplificado)</string>
|
||||
<string name="lang_zh_hk">Chinês (Hong Kong)</string>
|
||||
<string name="lang_zh_tw">Chinês (tradicional)</string>
|
||||
<string name="routing_attr_avoid_stairs_name">Sem escadas</string>
|
||||
<string name="routing_attr_avoid_stairs_name">Evitar escadas</string>
|
||||
<string name="routing_attr_avoid_stairs_description">Evita escadas</string>
|
||||
<string name="routing_attr_avoid_borders_name">Sem passagens por fronteiras</string>
|
||||
<string name="routing_attr_avoid_borders_name">Evitar passagens por fronteiras</string>
|
||||
<string name="routing_attr_avoid_borders_description">Evita cruzar fronteiras nacionais</string>
|
||||
<string name="routing_attr_height_name">Altura máxima</string>
|
||||
<string name="routing_attr_height_description">Especifique a altura permitida do veículo nas rotas.</string>
|
||||
|
@ -2504,7 +2504,7 @@
|
|||
\n
|
||||
\nPoderá usar o navegador visual e por voz, ver POIs (pontos de interesse), criar e gerir trilhos GPX, usar (através de uma extensão) curvas de nível e dados de altitude, escolher entre os modos motorista, ciclista e pedestre, editar o OpenStreetMap e muito mais.</string>
|
||||
<string name="osmand_extended_description_part2">Navegação GPS
|
||||
\n• Escolha entre modos off-line (sem tarifa de roaming quando estiver no exterior) ou on-line (mais rápido)
|
||||
\n• Escolha entre modos offline (sem tarifa de roaming quando estiver no exterior) ou online (mais rápido)
|
||||
\n• Orientação por voz passo-a-passo lhe guia ao longo do caminho (vozes gravadas e sintetizadas)
|
||||
\n• A rota é recalculada sempre que se desviar dela
|
||||
\n• Orientação de pista, nomes de ruas e tempo estimado de chegada ajudará ao longo do caminho
|
||||
|
@ -2522,7 +2522,7 @@
|
|||
\n• Partilhe sua posição para que seus amigos possam encontrá-lo
|
||||
\n• Mantém seus lugares mais importantes em \'Favoritos\'
|
||||
\n• Permite-lhe escolher como mostrar nomes no mapa: em inglês, local ou escrita fonética
|
||||
\n• Mostra mapas on-line especializados, vista de satélite (do Bing), sobreposições diferentes como trajetos GPX de navegação/turismo e camadas adicionais com transparência personalizável
|
||||
\n• Mostra mapas online especializados, vista de satélite (do Bing), sobreposições diferentes como trajetos GPX de navegação/turismo e camadas adicionais com transparência personalizável
|
||||
\n</string>
|
||||
<string name="osmand_extended_description_part4">Esqui
|
||||
\nA extensão de mapas de esqui OsmAnd Ski permite que veja pistas de esqui com nível de complexidade e algumas informações adicionais, como localização de elevadores e outras instalações invernais.</string>
|
||||
|
@ -2565,7 +2565,7 @@
|
|||
\n
|
||||
\nAlgumas das características principais:</string>
|
||||
<string name="osmand_plus_extended_description_part2">Navegação
|
||||
\n• Funciona on-line (rápido) ou off-line (sem custos de roaming quando estiver no estrangeiro)
|
||||
\n• Funciona online (rápido) ou offline (sem custos de roaming quando estiver no estrangeiro)
|
||||
\n• Orientação por voz passo a passo (vozes gravadas e sintetizadas)
|
||||
\n• Orientação de trajetos opcionais, visualização do nome da rua e tempo estimado de chegada
|
||||
\n• Suporta pontos intermédios do seu itinerário
|
||||
|
@ -2585,7 +2585,7 @@
|
|||
\n • Dados do OpenStreetMap disponíveis por país ou região
|
||||
\n • POIs da Wikipédia, ótimo para passeios turísticos
|
||||
\n • Descarregamentos grátis ilimitados, diretamente da aplicação
|
||||
\n • Mapas off-line vetoriais compactos e atualizados mensalmente
|
||||
\n • Mapas offline vetoriais compactos e atualizados mensalmente
|
||||
\n
|
||||
\n • Escolha entre região completa ou apenas a rede rodoviária (exemplo: o Japão inteiro tem 700 MB e a rede rodoviária tem apenas 200 MB)</string>
|
||||
<string name="osmand_plus_extended_description_part5">Recursos de segurança
|
||||
|
@ -2598,15 +2598,15 @@
|
|||
\n• Visualização de caminhos a pé, pistas de caminhadas e ciclovias, ideal para atividades ao ar livre
|
||||
\n• Navegação e modos de visualização especiais para bicicleta e pedestres
|
||||
\n• Paragens de transporte público opcionais (autocarro, elétrico, comboio) incluindo nomes de linhas
|
||||
\n• Gravação opcional de viagem para ficheiro GPX local ou serviço on-line
|
||||
\n• Gravação opcional de viagem para ficheiro GPX local ou serviço online
|
||||
\n• Visualização opcional de velocidade e altitudes
|
||||
\n• Visualização de curvas de nível e sombreamento de relevo (com uma extensão adicional)</string>
|
||||
<string name="osmand_plus_extended_description_part7">Contribua diretamente para o OpenStreetMap
|
||||
\n• Envie relatórios de erros.
|
||||
\n• Envie trilhos GPX para o OpenStreetMap diretamente da aplicação.
|
||||
\n• Adicione POIs e envie-os diretamente para o OpenStreetMap (ou mais tarde se estiver desconectado da Internet).
|
||||
\n • Gravação de viagem opcional também em plano de fundo (enquanto o dispositivo está no modo adormecido).
|
||||
\n O OsmAnd é um programa de fonte aberta desenvolvido ativamente. Todos podem contribuir para a aplicação reportando erros, a melhorar as traduções ou a programar novas funcionalidades. Além disso, o projeto conta com contribuições financeiras para financiar a programação e testes de novas funcionalidades.
|
||||
\n• Gravar viagem opcional também em plano de fundo (enquanto o dispositivo está no modo adormecido).
|
||||
\n• O OsmAnd é um programa de fonte aberta desenvolvido ativamente. Todos podem contribuir para a aplicação reportando erros, a melhorar as traduções ou a programar novas funcionalidades. Além disso, o projeto conta com contribuições financeiras para financiar a programação e testes de novas funcionalidades.
|
||||
\n</string>
|
||||
<string name="osmand_plus_extended_description_part8">Cobertura de mapa e qualidade aproximada:
|
||||
\n• Europa Ocidental: ****
|
||||
|
@ -2627,7 +2627,7 @@
|
|||
<string name="arrival_distance_factor_normally">Normal</string>
|
||||
<string name="arrival_distance_factor_late">Atrasado</string>
|
||||
<string name="arrival_distance_factor_at_last">Nos últimos metros</string>
|
||||
<string name="live_monitoring_max_interval_to_send">Buffer de tempo para rastreamento on-line</string>
|
||||
<string name="live_monitoring_max_interval_to_send">Buffer de tempo para rastreamento online</string>
|
||||
<string name="live_monitoring_max_interval_to_send_desrc">Especificar um buffer de tempo para manter locais para enviar sem conexão</string>
|
||||
<string name="index_name_netherlands">Europa - Países Baixos</string>
|
||||
<string name="shared_string_others">Outros</string>
|
||||
|
@ -2636,7 +2636,7 @@
|
|||
<string name="favourites_context_menu_add">Adicionar favorito</string>
|
||||
<string name="poi_action_delete">eliminar</string>
|
||||
<string name="poi_dialog_reopen">Reabrir</string>
|
||||
<string name="av_camera_pic_size">Tamanho da foto</string>
|
||||
<string name="av_camera_pic_size">Tamanho da fotografia</string>
|
||||
<string name="av_camera_pic_size_descr">Definir o tamanho da imagem</string>
|
||||
<string name="get_plugin">Obter</string>
|
||||
<string name="use_fast_recalculation">Recálculo de rota inteligente</string>
|
||||
|
@ -2657,7 +2657,7 @@
|
|||
<string name="shared_string_undo">Desfazer</string>
|
||||
<string name="app_name_osmand">OsmAnd</string>
|
||||
<string name="offline_maps_and_navigation">Mapas e navegação
|
||||
\noff-line</string>
|
||||
\noffline</string>
|
||||
<string name="commit_poi">Enviar POI</string>
|
||||
<string name="tab_title_basic">Básico</string>
|
||||
<string name="tab_title_advanced">Avançado</string>
|
||||
|
@ -2685,7 +2685,7 @@
|
|||
<string name="file_size_in_mb">%.1f MB</string>
|
||||
<string name="update_all">Atualizar tudo (%1$s MB)</string>
|
||||
<string name="save_poi_too_many_uppercase">O nome contém demasiadas letras maiúsculas. Continuar\?</string>
|
||||
<string name="configure_screen_quick_action">Ação rápida</string>
|
||||
<string name="configure_screen_quick_action">Botão de ação rápida</string>
|
||||
<string name="quick_action_item_action">Ação %d</string>
|
||||
<string name="quick_action_item_screen">Ecrã %d</string>
|
||||
<string name="quick_action_add_marker">Adicionar marcador de mapa</string>
|
||||
|
@ -2694,25 +2694,25 @@
|
|||
<string name="quick_action_map_style_switch">O estilo do mapa foi alterado para \"%s\".</string>
|
||||
<string name="quick_action_take_audio_note">Nova nota de áudio</string>
|
||||
<string name="quick_action_take_video_note">Nova nota de vídeo</string>
|
||||
<string name="quick_action_take_photo_note">Nova nota de foto</string>
|
||||
<string name="quick_action_take_photo_note">Nova nota de fotografia</string>
|
||||
<string name="quick_action_add_osm_bug">Adicionar nota OSM</string>
|
||||
<string name="quick_action_navigation_voice">Ligar/desligar voz</string>
|
||||
<string name="quick_action_navigation_voice_off">Ativar voz</string>
|
||||
<string name="quick_action_navigation_voice_on">Desativar voz</string>
|
||||
<string name="quick_action_add_parking">Adicionar local de estacionamento</string>
|
||||
<string name="quick_action_new_action">Adicionar ação</string>
|
||||
<string name="quick_action_edit_action">Editar ação</string>
|
||||
<string name="quick_action_edit_action">Editar botão de ação rápida</string>
|
||||
<string name="quick_action_add_favorite">Adicionar favorito</string>
|
||||
<string name="dialog_add_action_title">Adicionar ação</string>
|
||||
<string name="quick_actions_delete">Eliminar ação</string>
|
||||
<string name="quick_actions_delete_text">Tem a certeza de que quer eliminar a ação \"%s\"\?</string>
|
||||
<string name="quick_actions_delete">Eliminar botão de ação rápida</string>
|
||||
<string name="quick_actions_delete_text">Tem a certeza de que quer eliminar o botão de ação rápida \"%s\"\?</string>
|
||||
<string name="quick_favorites_show_favorites_dialog">Mostrar lista dos favoritos</string>
|
||||
<string name="quick_favorites_name_preset">Nome do modelo</string>
|
||||
<string name="quick_action_add_marker_descr">O botão é para adicionar um marcador de mapa no local do centro do ecrã.</string>
|
||||
<string name="quick_action_add_gpx_descr">Um botão para adicionar um ponto de rota GPX no local do centro do ecrã.</string>
|
||||
<string name="quick_action_take_audio_note_descr">Um botão para adicionar uma nota de áudio no local do centro do ecrã.</string>
|
||||
<string name="quick_action_take_video_note_descr">Um botão para adicionar uma nota de vídeo no local do centro do ecrã.</string>
|
||||
<string name="quick_action_take_photo_note_descr">Um botão para adicionar uma nota de foto no local do centro do ecrã.</string>
|
||||
<string name="quick_action_take_photo_note_descr">Um botão para adicionar uma nota de fotografia no local do centro do ecrã.</string>
|
||||
<string name="quick_action_add_osm_bug_descr">Um botão para adicionar uma nota OSM no local do centro do ecrã.</string>
|
||||
<string name="quick_action_add_poi_descr">Um botão para adicionar um POI no local do centro do ecrã.</string>
|
||||
<string name="quick_action_navigation_voice_descr">Um botão para ativar ou desativar a orientação por voz durante a navegação.</string>
|
||||
|
@ -2720,8 +2720,8 @@
|
|||
<string name="quick_action_interim_dialog">Mostrar uma janela temporal</string>
|
||||
<string name="favorite_autofill_toast_text">" guardado em "</string>
|
||||
<string name="favorite_empty_place_name">Local</string>
|
||||
<string name="quick_action_duplicates">O nome da ação rápida foi alterado para %1$s para evitar duplicação.</string>
|
||||
<string name="quick_action_duplicate">Nome de ação rápida duplicado</string>
|
||||
<string name="quick_action_duplicates">O nome do botão de ação rápida foi alterado para %1$s para evitar duplicação.</string>
|
||||
<string name="quick_action_duplicate">Nome do botão de ação rápida duplicado</string>
|
||||
<string name="quick_action_showhide_favorites_descr">Uma alternância para mostrar ou ocultar os pontos favoritos no mapa.</string>
|
||||
<string name="quick_action_showhide_poi_descr">Uma alternância para mostrar ou ocultar POIs no mapa.</string>
|
||||
<string name="quick_action_poi_show">Mostrar %1$s</string>
|
||||
|
@ -2754,9 +2754,9 @@
|
|||
<string name="quick_action_map_source_action">Adicionar origem do mapa</string>
|
||||
<string name="quick_action_map_source_switch">A origem do mapa foi alterada para \"%s\".</string>
|
||||
<string name="quick_action_btn_tutorial_title">Mudar posição do botão</string>
|
||||
<string name="quick_action_btn_tutorial_descr">Segure e arraste o botão para mudar a sua posição no ecrã.</string>
|
||||
<string name="quick_action_btn_tutorial_descr">Pressione e segure arrastando o botão para mudar a sua posição no ecrã.</string>
|
||||
<string name="shared_string_action_name">Nome da ação</string>
|
||||
<string name="mappilary_no_internet_desc">As fotos do Mapillary só estão disponíveis on-line.</string>
|
||||
<string name="mappilary_no_internet_desc">As fotografias do Mapillary só estão disponíveis online.</string>
|
||||
<string name="retry">Repetir</string>
|
||||
<string name="add_route_points">Adicionar pontos de rota</string>
|
||||
<string name="add_waypoint">Adicionar ponto de passagem</string>
|
||||
|
@ -2782,7 +2782,7 @@
|
|||
<string name="show_tunnels">Túneis</string>
|
||||
<string name="download_wikipedia_description">Descarregar artigos da Wikipédia de %1$s para lê-los offline.</string>
|
||||
<string name="download_wikipedia_label">Descarregar dados da Wikipédia</string>
|
||||
<string name="open_in_browser_wiki">Abrir artigo on-line</string>
|
||||
<string name="open_in_browser_wiki">Abrir artigo na Internet</string>
|
||||
<string name="open_in_browser_wiki_description">Ver artigo no navegador web.</string>
|
||||
<string name="download_wiki_region_placeholder">esta região</string>
|
||||
<string name="wiki_article_search_text">A procurar o artigo wiki correspondente</string>
|
||||
|
@ -2890,17 +2890,17 @@
|
|||
<string name="show_more">Mostrar mais</string>
|
||||
<string name="tracks_on_map">Trilhos mostrados</string>
|
||||
<string name="quick_action_show_hide_gpx_tracks_descr">Um botão para mostrar ou ocultar trilhos selecionados no mapa.</string>
|
||||
<string name="routing_attr_avoid_tram_name">Sem elétricos</string>
|
||||
<string name="routing_attr_avoid_tram_name">Evitar elétricos</string>
|
||||
<string name="routing_attr_avoid_tram_description">Evita elétricos</string>
|
||||
<string name="routing_attr_avoid_bus_name">Sem autocarros</string>
|
||||
<string name="routing_attr_avoid_bus_name">Evitar autocarros</string>
|
||||
<string name="routing_attr_avoid_bus_description">Evita autocarros e troleicarros</string>
|
||||
<string name="routing_attr_avoid_share_taxi_name">Sem táxis partilhados</string>
|
||||
<string name="routing_attr_avoid_share_taxi_name">Evitar táxis partilhados</string>
|
||||
<string name="routing_attr_avoid_share_taxi_description">Evita táxis partilhados</string>
|
||||
<string name="routing_attr_avoid_train_name">Sem comboios</string>
|
||||
<string name="routing_attr_avoid_train_name">Evitar comboios</string>
|
||||
<string name="routing_attr_avoid_train_description">Evitar comboios</string>
|
||||
<string name="routing_attr_avoid_subway_name">Sem metropolitanos</string>
|
||||
<string name="routing_attr_avoid_subway_name">Evitar metropolitanos</string>
|
||||
<string name="routing_attr_avoid_subway_description">Evitar metropolitanos subterrâneos e de superfície</string>
|
||||
<string name="routing_attr_avoid_ferry_name">Sem balsas/ferries</string>
|
||||
<string name="routing_attr_avoid_ferry_name">Evitar balsas/ferries</string>
|
||||
<string name="routing_attr_avoid_ferry_description">Evita balsas/ferries</string>
|
||||
<string name="shared_string_milliradians">Milirradianos</string>
|
||||
<string name="rendering_attr_surface_sett_name">Paralelos</string>
|
||||
|
@ -2997,7 +2997,7 @@
|
|||
<string name="third_party_routing_type">Roteamento de terceiros</string>
|
||||
<string name="application_profiles_descr">Escolha os perfis mostrados na aplicação.</string>
|
||||
<string name="application_profiles">Perfis da aplicação</string>
|
||||
<string name="quick_action_need_to_add_item_to_list">Adicione pelo menos um item à lista nas configurações de \'Ação rápida\'</string>
|
||||
<string name="quick_action_need_to_add_item_to_list">Adicione pelo menos um item à lista nas configurações de \'Botão de ações rápidas\'</string>
|
||||
<string name="routing_attr_piste_type_downhill_name">Esqui alpino e descendente</string>
|
||||
<string name="routing_attr_piste_type_downhill_description">Pistas para esqui alpino ou downhill e acesso a teleféricos de esqui.</string>
|
||||
<string name="routing_attr_piste_type_nordic_name">Esqui de travessia e nórdico</string>
|
||||
|
@ -3133,7 +3133,7 @@
|
|||
<string name="coordinates_format_info">O formato selecionado será aplicado em toda a aplicação.</string>
|
||||
<string name="pref_selected_by_default_for_profiles">Esta configuração é selecionada por padrão para os perfis: %s</string>
|
||||
<string name="change_default_settings">Alterar a configuração</string>
|
||||
<string name="discard_changes">Descartar alteração</string>
|
||||
<string name="discard_changes">Cancelar alteração</string>
|
||||
<string name="apply_to_current_profile">Aplicar só a \"%1$s\"</string>
|
||||
<string name="apply_to_all_profiles">Aplicar a todos os perfis</string>
|
||||
<string name="start_up_message_pref">Mensagem de inicialização</string>
|
||||
|
@ -3293,7 +3293,7 @@
|
|||
<string name="empty_filename">O nome do ficheiro está vazio</string>
|
||||
<string name="shared_string_revert">Reverter</string>
|
||||
<string name="quick_action_directions_from_desc">Um botão para centrar o ecrã no ponto de partida. Em seguida, solicitará para definir o destino ou acionar o cálculo da rota.</string>
|
||||
<string name="rendering_attr_showCycleNodeNetworkRoutes_name">Mostrar nós da rede de ciclovias</string>
|
||||
<string name="rendering_attr_showCycleNodeNetworkRoutes_name">Nós da rede de ciclovias</string>
|
||||
<string name="clear_confirmation_msg">Limpar %1$s\?</string>
|
||||
<string name="download_map_dialog">Diálogo de descarregar mapas</string>
|
||||
<string name="dialogs_and_notifications_title">Diálogos e notificações</string>
|
||||
|
@ -3442,7 +3442,7 @@
|
|||
<string name="osm_authorization_success">Autorização bem sucedida</string>
|
||||
<string name="multimedia_photo_play_sound">Som do obturador da câmara</string>
|
||||
<string name="multimedia_use_system_camera">Usar aplicação do sistema</string>
|
||||
<string name="multimedia_rec_split_title">Divisão de gravação</string>
|
||||
<string name="multimedia_rec_split_title">Dividir gravações</string>
|
||||
<string name="reset_plugin_to_default">Repor configurações originais da extensão</string>
|
||||
<string name="monitoring_min_distance">Deslocamento mínimo</string>
|
||||
<string name="monitoring_min_accuracy">Precisão mínima</string>
|
||||
|
@ -3454,7 +3454,7 @@
|
|||
<string name="live_monitoring_time_buffer">Memória intermédia</string>
|
||||
<string name="monitoring_min_distance_descr_recommendation">Recomendação: uma configuração de 5 metros pode funcionar bem se não precisar capturar detalhes mais refinados do que isso e não quer capturar dados explicitamente enquanto estiver parado.</string>
|
||||
<string name="monitoring_min_distance_descr_side_effect">Efeitos colaterais: os períodos em que está parado não são registados em absoluto ou em apenas um ponto cada. Pequenos movimentos (no mundo real, por exemplo de lado, para marcar um possível desvio na sua viagem) podem ser filtrados. O seu ficheiro contém menos informações para pós-processamento e possui estatísticas piores ao filtrar pontos obviamente redundantes no tempo de gravação, mantendo potencialmente os artefactos causados por má receção ou efeitos do chipset GPS.</string>
|
||||
<string name="monitoring_min_distance_descr">Este filtro evita que sejam gravados pontos duplicados onde ocorrer muito pouco movimento real, cria uma aparência espacial mais agradável dos trilhos que não são processados posteriormente.</string>
|
||||
<string name="monitoring_min_distance_descr">Este filtro evita que sejam gravados pontos duplicados quando houver muito pouco movimento real e cria uma aparência espacial mais agradável dos trilhos que não são processados posteriormente.</string>
|
||||
<string name="monitoring_min_accuracy_descr_remark">Observação: se o GPS estava desligado imediatamente antes de uma gravação, o primeiro ponto medido pode ter uma precisão diminuída; portanto, no nosso código, podemos esperar um segundo antes da gravação de um ponto (ou gravar o melhor de três pontos consecutivos, etc.), mas isso ainda não foi implementado.</string>
|
||||
<string name="monitoring_min_accuracy_descr_recommendation">Recomendação: é difícil prever o que será gravado e o que não será, talvez seja melhor desativar este filtro.</string>
|
||||
<string name="monitoring_min_accuracy_descr_side_effect">Efeito colateral: como resultado da filtragem por precisão, os pontos podem estar totalmente ausentes por ex. debaixo de pontes, sob árvores, entre prédios altos ou com certas condições climáticas.</string>
|
||||
|
@ -3501,7 +3501,7 @@
|
|||
<string name="settings_item_import_error">Não foi possível importar de \'%1$s\'.</string>
|
||||
<string name="ui_customization_description">Personalize a quantidade de itens em \"Gaveta\", \"Configurar Mapa\" e \"Menu de Contexto\".
|
||||
\n
|
||||
\nDesative as extensões não utilizados para ocultar todos os seus controlos. %1$s.</string>
|
||||
\nDesative as extensões não utilizadas para ocultar todos os seus controlos. %1$s.</string>
|
||||
<string name="ui_customization_short_descr">Itens da gaveta, menu de contexto</string>
|
||||
<string name="ui_customization">Personalização da interface</string>
|
||||
<string name="shared_string_drawer">Gaveta</string>
|
||||
|
@ -3525,7 +3525,7 @@
|
|||
<string name="select_wikipedia_article_langs">Selecione as línguas dos artigos da Wikipédia no mapa. Mude para qualquer língua disponível enquanto lê o artigo.</string>
|
||||
<string name="mapillary_item">OsmAnd + Mapillary</string>
|
||||
<string name="tracker_item">OsmAnd Tracker</string>
|
||||
<string name="quick_action_item">Ação rápida</string>
|
||||
<string name="quick_action_item">Botão de ações rápidas</string>
|
||||
<string name="radius_ruler_item">Régua radial</string>
|
||||
<string name="measure_distance_item">Medir distância</string>
|
||||
<string name="travel_item">Viagem (Wikivoyage e Wikipédia)</string>
|
||||
|
@ -3604,9 +3604,9 @@
|
|||
<string name="pseudo_mercator_projection">Projeção pseudo-Mercator</string>
|
||||
<string name="one_image_per_tile">Um ficheiro de imagem por mosaico</string>
|
||||
<string name="sqlite_db_file">Ficheiro SQLiteDB</string>
|
||||
<string name="online_map_name_helper_text">Forneça um nome para a origem do mapa on-line.</string>
|
||||
<string name="online_map_url_helper_text">Introduza ou cole o URL para a origem on-line.</string>
|
||||
<string name="edit_online_source">Editar origem on-line</string>
|
||||
<string name="online_map_name_helper_text">Forneça um nome para a origem do mapa online.</string>
|
||||
<string name="online_map_url_helper_text">Introduza ou cole o URL para a origem online.</string>
|
||||
<string name="edit_online_source">Editar origem online</string>
|
||||
<string name="expire_time">Tempo de validade</string>
|
||||
<string name="mercator_projection">Projeção de Mercator</string>
|
||||
<string name="storage_format">Formato de armazenamento</string>
|
||||
|
@ -3648,7 +3648,7 @@
|
|||
\nSelecione %1$s e receberá alertas e avisos sobre radares de velocidade.
|
||||
\n
|
||||
\nSelecione %2$s e yodos os dados relacionados a radares de velocidade: alertas, notificações, POIs serão eliminados até que o OsmAnd seja completamente reinstalado.</string>
|
||||
<string name="plugin_wikipedia_description">Obter informações sobre pontos de interesse da Wikipédia. Um guia de bolso off-line para ver artigos sobre locais e destinos.</string>
|
||||
<string name="plugin_wikipedia_description">Obter informações sobre pontos de interesse da Wikipédia. Um guia de bolso offline para ver artigos sobre locais e destinos.</string>
|
||||
<string name="app_mode_motor_scooter">Scooter</string>
|
||||
<string name="quick_action_remove_next_destination">Eliminar o ponto de destino mais próximo</string>
|
||||
<string name="search_download_wikipedia_maps">Descarregar mapas da Wikipédia</string>
|
||||
|
@ -3704,7 +3704,7 @@
|
|||
<string name="add_to_a_track">Adicionar a um trilho</string>
|
||||
<string name="add_hidden_group_info">O ponto adicionado não será visível no mapa, já que o grupo selecionado está escondido, pode encontrá-lo em \"%s\".</string>
|
||||
<string name="track_show_start_finish_icons">Mostrar ícones de início e fim</string>
|
||||
<string name="select_track_width">Selecionar a largura</string>
|
||||
<string name="select_track_width">Espessura da linha do trilho</string>
|
||||
<string name="gpx_split_interval_descr">Selecione o intervalo em que as marcas com distância ou tempo no trilho serão mostradas.</string>
|
||||
<string name="gpx_split_interval_none_descr">Selecione a opção de divisão desejada: por tempo ou por distância.</string>
|
||||
<string name="shared_string_custom">Personalizado</string>
|
||||
|
@ -3715,7 +3715,7 @@
|
|||
<string name="plan_route_open_existing_track">Abrir trilho existente</string>
|
||||
<string name="plan_route_select_track_file_for_open">Selecione um ficheiro de trilho para abrir.</string>
|
||||
<string name="plan_route_create_new_route">Criar nova rota</string>
|
||||
<string name="shared_string_done">Pronto</string>
|
||||
<string name="shared_string_done">Feito</string>
|
||||
<string name="overwrite_track">Substituir trilho</string>
|
||||
<string name="save_as_new_track">Guardar como novo trilho</string>
|
||||
<string name="reverse_route">Rota inversa</string>
|
||||
|
@ -3759,9 +3759,9 @@
|
|||
<string name="save_track_to_gpx_globally">Registar o trilho num ficheiro GPX</string>
|
||||
<string name="layer_gpx_layer">Trilhos</string>
|
||||
<string name="context_menu_item_add_waypoint">Adicionar ponto de passagem de trilho</string>
|
||||
<string name="map_widget_monitoring">Gravação de viagem</string>
|
||||
<string name="map_widget_monitoring">Gravar viagem</string>
|
||||
<string name="monitoring_control_start">Gravar</string>
|
||||
<string name="save_global_track_interval_descr">Especifique o intervalo de registo para a gravação geral do trilho (ligado através do widget de \'gravação de viagem\' no mapa).</string>
|
||||
<string name="save_global_track_interval_descr">Especifique o intervalo de registo para a gravação geral do trilho (ligado através do widget de \'Gravar viagem\' no mapa).</string>
|
||||
<string name="gpx_monitoring_stop">Pausar a gravação da viagem</string>
|
||||
<string name="gpx_monitoring_start">Retomar a gravação da viagem</string>
|
||||
<string name="system_default_theme">Predefinição do sistema</string>
|
||||
|
@ -3865,10 +3865,10 @@
|
|||
<string name="osm_edit_close_note">Fechar nota do OSM</string>
|
||||
<string name="osm_edit_comment_note">Comentário de nota do OSM</string>
|
||||
<string name="osm_login_descr">Pode iniciar sessão pelo método seguro OAuth ou use o seu nome de utilizador e a palavra-passe.</string>
|
||||
<string name="shared_string_add_photo">Adicionar foto</string>
|
||||
<string name="shared_string_add_photo">Adicionar fotografia</string>
|
||||
<string name="register_on_openplacereviews">Crie uma conta em
|
||||
\nOpenPlaceReviews.org</string>
|
||||
<string name="register_on_openplacereviews_desc">As fotos são fornecidas pelo projeto de dados abertos OpenPlaceReviews.org. Para enviar as suas fotos tem de criar uma conta no site.</string>
|
||||
<string name="register_on_openplacereviews_desc">As fotografias são fornecidas pelo projeto de dados abertos OpenPlaceReviews.org. Para enviar as suas fotografias tem de criar uma conta nesse site.</string>
|
||||
<string name="register_opr_create_new_account">Criar uma conta</string>
|
||||
<string name="register_opr_have_account">Já tenho uma conta</string>
|
||||
<string name="shared_string_search_history">Histórico de pesquisa</string>
|
||||
|
@ -3932,12 +3932,12 @@
|
|||
<string name="analyze_by_intervals">Analisar por intervalos</string>
|
||||
<string name="upload_to_openstreetmap">Enviar para OpenStreetMap</string>
|
||||
<string name="edit_track">Editar trilho</string>
|
||||
<string name="rename_track">Renomear trilho</string>
|
||||
<string name="rename_track">Alterar nome do trilho</string>
|
||||
<string name="change_folder">Mudar pasta</string>
|
||||
<string name="hillshade_slope_contour_lines">Sombras de relevo / declives / curvas de nível</string>
|
||||
<string name="open_place_reviews_plugin_description">OpenPlaceReviews é um projeto comunitário sobre lugares públicos como restaurantes, hotéis, museus, pontos de passagem. Recolhe toda a informação pública sobre eles, como fotos, resenhas, ligações para outros sistemas OpenStreetMap, Wikipédia.
|
||||
<string name="open_place_reviews_plugin_description">OpenPlaceReviews é um projeto comunitário sobre lugares públicos como restaurantes, hotéis, museus, locais etc. Recolhe toda a informação pública sobre eles, como fotografias, classificações/avaliações, ligações para outros sistemas como o OpenStreetMap e a Wikipédia.
|
||||
\n
|
||||
\nTodos os dados do OpenPlaceReviews estão abertos e disponíveis para todos: http://openplacereviews.org/data.
|
||||
\nTodos os dados do OpenPlaceReviews estão abertos e disponíveis para todos: http://openplacereviews.org/data
|
||||
\n
|
||||
\nPode ler mais em: http://openplacereviews.org</string>
|
||||
<string name="open_place_reviews">OpenPlaceReviews</string>
|
||||
|
@ -4025,7 +4025,7 @@
|
|||
<string name="no_purchases">Não tem compras</string>
|
||||
<string name="contact_support_description">Se tiver alguma dúvida, contacte-nos em %1$s.</string>
|
||||
<string name="announcement_time_intervals">Intervalos de tempo e distância</string>
|
||||
<string name="map_widget_distance_by_tap">Distância por toque</string>
|
||||
<string name="map_widget_distance_by_tap">Distância com 2 dedos</string>
|
||||
<string name="contact_support">Contacte o suporte</string>
|
||||
<string name="troubleshooting_description">Por favor siga este link se tiver algum problema com assinaturas.</string>
|
||||
<string name="update_all_maps_added">Atualizar todos os mapas para %1$s\?</string>
|
||||
|
|
|
@ -141,8 +141,8 @@
|
|||
<string name="routing_attr_height_obstacles_name">Использовать данные о высотах</string>
|
||||
<string name="quick_action_duplicates">Действие переименовано в %1$s, чтобы избежать дублирования.</string>
|
||||
<string name="quick_action_duplicate">Обнаружен дубликат имени</string>
|
||||
<string name="quick_action_showhide_favorites_descr">Переключатель, чтобы показать или скрыть избранные точки на карте.</string>
|
||||
<string name="quick_action_showhide_poi_descr">Переключатель, чтобы показать или скрыть POI на карте.</string>
|
||||
<string name="quick_action_showhide_favorites_descr">Переключатель для отображения или скрытия избранных точек на карте.</string>
|
||||
<string name="quick_action_showhide_poi_descr">Переключатель для отображения или скрытия POI на карте.</string>
|
||||
<string name="quick_action_add_category">Категория</string>
|
||||
<string name="quick_action_add_create_items">Действия</string>
|
||||
<string name="quick_action_fav_name_descr">Если оставить это поле пустым, то оно будет автоматически заполнено адресом или названием места.</string>
|
||||
|
@ -3660,7 +3660,7 @@
|
|||
<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_descr">Переключатель, чтобы показать или скрыть слой Mapillary на карте.</string>
|
||||
<string name="quick_action_showhide_mapillary_descr">Переключатель для отображения или скрытия слоя Mapillary на карте.</string>
|
||||
<string name="shared_string_legal">Законодательство</string>
|
||||
<string name="speed_cameras_legal_descr">В некоторых странах и регионах использование предупреждений о камерах контроля скорости запрещено законом.
|
||||
\n
|
||||
|
|
|
@ -3926,4 +3926,6 @@
|
|||
<string name="poi_hoops">Canisteddos</string>
|
||||
<string name="poi_camp_pitch">Pratzola de acampamentu</string>
|
||||
<string name="poi_bay_filter">Casta de baia</string>
|
||||
<string name="poi_club_social">Tzìrculu sotziale</string>
|
||||
<string name="poi_plateau">Artipranu</string>
|
||||
</resources>
|
|
@ -4006,7 +4006,7 @@
|
|||
<string name="routing_attr_driving_style_description">Zvoľte účel jazdy pre získanie kratšej, rýchlejšej alebo bezpečnejšej trasy</string>
|
||||
<string name="map_orientation_threshold_descr">Neotáčať mapu, ak je rýchlosť nižšia ako hranica</string>
|
||||
<string name="restart">Reštartovať</string>
|
||||
<string name="shared_strings_all_regions">Všetky regióny</string>
|
||||
<string name="shared_strings_all_regions">Všetky oblasti</string>
|
||||
<string name="delete_number_files_question">Zmazať %1$d súborov\?</string>
|
||||
<string name="track_recording_stop_without_saving">Zastaviť bez uloženia</string>
|
||||
<string name="track_recording_save_and_stop">Uložiť a zastaviť záznam</string>
|
||||
|
|
|
@ -3867,4 +3867,45 @@
|
|||
<string name="poi_water_source_river">Река</string>
|
||||
<string name="poi_vaccination_covid19">Цепљење: Ковид 19</string>
|
||||
<string name="poi_health_specialty_vaccination_yes">Цепљење</string>
|
||||
<string name="poi_club_social">Друштвени клуб</string>
|
||||
<string name="poi_plateau">Плато</string>
|
||||
<string name="poi_office_diplomatic">Дипломатско представништво</string>
|
||||
<string name="poi_kickboxing">Кик-бокс</string>
|
||||
<string name="poi_fencing">Мачевање</string>
|
||||
<string name="poi_curling">Курлинг</string>
|
||||
<string name="poi_crossfit">Кросфит</string>
|
||||
<string name="poi_cockfighting">Туча петлова</string>
|
||||
<string name="poi_bullfighting">Борба са биковима</string>
|
||||
<string name="poi_bobsleigh">Боб</string>
|
||||
<string name="poi_biathlon">Биатлон</string>
|
||||
<string name="poi_aikido">Аикидо</string>
|
||||
<string name="poi_water_ski">Водено скијање</string>
|
||||
<string name="poi_water_polo">Ватерполо</string>
|
||||
<string name="poi_wrestling">Рвање</string>
|
||||
<string name="poi_weightlifting">Дизање тегова</string>
|
||||
<string name="poi_wakeboarding">Вејкбординг</string>
|
||||
<string name="poi_ultimate">Ултимат</string>
|
||||
<string name="poi_taekwondo">Таеквондо</string>
|
||||
<string name="poi_table_soccer">Футсал</string>
|
||||
<string name="poi_sumo">Сумо</string>
|
||||
<string name="poi_snooker">Снукер</string>
|
||||
<string name="poi_piste_status_open">Стање стазе: отворена</string>
|
||||
<string name="poi_patrolled_no">Обилажена: не</string>
|
||||
<string name="poi_patrolled_yes">Обилажена: да</string>
|
||||
<string name="poi_piste_name">Име стазе</string>
|
||||
<string name="poi_piste_ski_jump">Ски скок</string>
|
||||
<string name="poi_wildlife_crossing_bat_tunnel">Тунел за слепе мишеве</string>
|
||||
<string name="poi_wildlife_crossing_bat_bridge">Мост за слепе мишеве</string>
|
||||
<string name="poi_wildlife_crossing">Прелаз за дивљач</string>
|
||||
<string name="poi_swimming_area">Део за пливање</string>
|
||||
<string name="poi_lavoir">Појило</string>
|
||||
<string name="poi_waste_transfer_station">Станица за пренос отпада</string>
|
||||
<string name="poi_weightbridge">Колска вага</string>
|
||||
<string name="poi_ranger_station">Шумарска станица</string>
|
||||
<string name="poi_water_source_tube_well">Цевни бунар</string>
|
||||
<string name="poi_water_source_well">Бунар</string>
|
||||
<string name="poi_water_source_powered_pump">Електрична пумпа</string>
|
||||
<string name="poi_water_source_water_tank">Танк са водом</string>
|
||||
<string name="poi_water_source_tap">Чесма</string>
|
||||
<string name="poi_bay_filter">Тип залива</string>
|
||||
</resources>
|
|
@ -662,7 +662,7 @@
|
|||
<string name="share_osm_edits_subject">ОСМ измене дељене преко OsmAnd-а</string>
|
||||
<string name="osm_edit_created_poi">OSM тачка од интереса је направљена</string>
|
||||
<string name="nm">nmi</string>
|
||||
<string name="nm_h">kn</string>
|
||||
<string name="nm_h">чв</string>
|
||||
<string name="min_mile">min/m</string>
|
||||
<string name="min_km">min/km</string>
|
||||
<string name="m_s">m/s</string>
|
||||
|
@ -922,7 +922,7 @@
|
|||
<string name="rendering_attr_roadColors_name">Образац боја путева</string>
|
||||
<string name="enable_plugin_monitoring_services">Омогућите додатак за „снимање путовања“ ради коришћења услуга бележења (GPX бележење, праћење положаја на мрежи)</string>
|
||||
<string name="non_optimal_route_calculation">Рачунај могућу приближну путању за велике раздаљине</string>
|
||||
<string name="gps_not_available">Омогућите GPS у поставкама</string>
|
||||
<string name="gps_not_available">Омогућите GPS у подешавањима</string>
|
||||
<string name="map_widget_monitoring_services">Услуге бележења путање</string>
|
||||
<string name="no_route">Нема пута</string>
|
||||
<string name="arrived_at_intermediate_point">Стигли сте на пролазно одредиште</string>
|
||||
|
@ -1005,7 +1005,7 @@
|
|||
<string name="new_filter_desc">Молимо, унесите име новог филтера који ће бити придодат језичку „Категорије“.</string>
|
||||
<string name="osm_live_payment_desc">Чланарина се наплаћује по одабраном периоду. Можете је отказати на Гугл плеју кад год пожелите.</string>
|
||||
<string name="donation_to_osm">Прилог ОСМ заједници</string>
|
||||
<string name="donation_to_osm_desc">Део Вашег прилога ће бити послат корисницима ОСМ-а. Чланарина остаје иста.</string>
|
||||
<string name="donation_to_osm_desc">Део Ваше чланарине ће бити послат корисницима ОСМ-а. Чланарина остаје иста.</string>
|
||||
<string name="osm_live_subscription_desc">Чланарина омогућава часовне, дневне и седмичне надоградње, и неограничена преузимања свих карата.</string>
|
||||
<string name="get_it">Добавите је</string>
|
||||
<string name="get_for">Добавите за %1$s</string>
|
||||
|
@ -1062,9 +1062,9 @@
|
|||
<string name="access_direction_audio_feedback_descr">Указуј на правац циљне тачке звуком.</string>
|
||||
<string name="access_direction_haptic_feedback">Упутства трешењем</string>
|
||||
<string name="access_direction_haptic_feedback_descr">Указуј на правац циљне тачке трешњом.</string>
|
||||
<string name="use_osm_live_routing_description">Омогући навођење живих измена ОСМ-а.</string>
|
||||
<string name="use_osm_live_routing_description">Омогући навођење измена ОСМ-а уживо.</string>
|
||||
<string name="use_osm_live_routing">Навођење уживо ОСМ-а</string>
|
||||
<string name="access_no_destination">Одредиште није подешено</string>
|
||||
<string name="access_no_destination">Додатак за приступачност: Одредиште није подешено</string>
|
||||
<string name="access_category_choice">Изаберите категорију</string>
|
||||
<string name="storage_directory_readonly_desc">Пребачено на интерну меморију пошто је означено складиште за податке заштићено од писања. Изаберите фасциклу за складиште у коју може да се пише.</string>
|
||||
<string name="save_track_interval_descr">Наведите интервал логовања снимања путање приликом навођења</string>
|
||||
|
@ -1221,7 +1221,7 @@
|
|||
<string name="rendering_attr_horseRoutes_name">Коњске стазе</string>
|
||||
<string name="share_geo">положај:</string>
|
||||
<string name="lang_br">Бретонски</string>
|
||||
<string name="hillshade_menu_download_descr">Преузмите слој са сенчењем да бисте видели рељеф на карти.</string>
|
||||
<string name="hillshade_menu_download_descr">Преузмите карту слоја са сенчењем да бисте видели рељеф на карти.</string>
|
||||
<string name="hillshade_purchase_header">Инсталирајте додатак \"Изохипсе\" да прикажете нагиб вертикалних области.</string>
|
||||
<string name="shared_string_plugin">Додатак</string>
|
||||
<string name="display_zoom_level">Приказ нивоа увеличања: %1$s</string>
|
||||
|
@ -1234,11 +1234,11 @@
|
|||
<string name="shared_string_add_photos">Додај слике</string>
|
||||
<string name="no_photos_descr">Нема слика овде.</string>
|
||||
<string name="mapillary_action_descr">Поделите Ваш поглед са улице преко Мапилара.</string>
|
||||
<string name="mapillary_widget">Справица Мапилара</string>
|
||||
<string name="mapillary_widget_descr">Омогућава брзи допринос Мапилару.</string>
|
||||
<string name="open_mapillary">Отвори Мапилар</string>
|
||||
<string name="mapillary_widget">Mapillary справица</string>
|
||||
<string name="mapillary_widget_descr">Омогућава брзи допринос Mapillary-ју.</string>
|
||||
<string name="open_mapillary">Отвори Mapillary</string>
|
||||
<string name="mapillary_descr">Мрежне слике улица за све. Откријте места, сарађујте, освојите свет.</string>
|
||||
<string name="mapillary">Мапилари</string>
|
||||
<string name="mapillary">Mapillary</string>
|
||||
<string name="plugin_mapillary_descr">Мрежне слике улица за све. Откријте места, сарађујте, освојите свет.</string>
|
||||
<string name="private_access_routing_req">Ваше одредиште се налази на приватном поседу. Дозволити коришћење приватних путева на овом путовању\?</string>
|
||||
<string name="restart_search">Препокрени претрагу</string>
|
||||
|
@ -1512,8 +1512,8 @@
|
|||
<string name="import_gpx_failed_descr">Не могу да увезем фајл. Проверите да ли OsmAnd има дозволе за читање фајла.</string>
|
||||
<string name="distance_moving">Растојање је исправљено</string>
|
||||
<string name="mapillary_image">Слика са Мапилара</string>
|
||||
<string name="improve_coverage_mapillary">Побољшајте покривеност слика користећи Мапилар</string>
|
||||
<string name="improve_coverage_install_mapillary_desc">Инсталирајте програм Мапилар (Mapillary) да додате слике на ову локацију на карти.</string>
|
||||
<string name="improve_coverage_mapillary">Побољшајте покривеност слика користећи Mapillary</string>
|
||||
<string name="improve_coverage_install_mapillary_desc">Инсталирајте програм Mapillary да додате слике на ову локацију на карти.</string>
|
||||
<string name="subscribe_email_desc">Претплатите се на нашу дописну листу за попуст и добијте још 3 преузимања карти!</string>
|
||||
<string name="depth_contour_descr">Изобате мора (изохипсе дубине) и карте поморских ознака.</string>
|
||||
<string name="sea_depth_thanks">Хвала Вам на куповини „Поморских изобата“</string>
|
||||
|
@ -1861,7 +1861,7 @@
|
|||
<string name="quick_action_btn_tutorial_title">Помери дугме</string>
|
||||
<string name="quick_action_btn_tutorial_descr">Дуго држање и превлачење дугмета га помера по екрану.</string>
|
||||
<string name="shared_string_action_name">Име радње</string>
|
||||
<string name="mappilary_no_internet_desc">Слике са Мапилара је могуће видети само ако сте повезани на интернет.</string>
|
||||
<string name="mappilary_no_internet_desc">Слике са Mapillary-ја је могуће видети само ако сте повезани на интернет.</string>
|
||||
<string name="retry">Покушај поново</string>
|
||||
<string name="empty_state_favourites">Додај омиљене</string>
|
||||
<string name="empty_state_favourites_desc">Увезите Омиљене тачке или их додајте означавајући их као ознаке на карти.</string>
|
||||
|
@ -2134,7 +2134,7 @@
|
|||
<string name="plugin_install_needs_network">Морате имати интернет да бисте инсталирали овај додатак.</string>
|
||||
<string name="get_plugin">Преузми</string>
|
||||
<string name="use_fast_recalculation">Пмаетно прерачунавање пута</string>
|
||||
<string name="use_fast_recalculation_desc">Прерачунава само почетни део руте. Може се користити за дуга путовања.</string>
|
||||
<string name="use_fast_recalculation_desc">Прерачунава само почетни део руте, корисно за дуга путовања.</string>
|
||||
<string name="do_you_like_osmand">Да ли Вам се OsmAnd свиђа?</string>
|
||||
<string name="we_really_care_about_your_opinion">Важно нам је да чујемо Ваше мишљење.</string>
|
||||
<string name="rate_this_app">Оцените ову апликацију</string>
|
||||
|
@ -2543,7 +2543,7 @@
|
|||
<string name="update_poi_error_local">Не могу да ажурирам локални списак тачака од интереса.</string>
|
||||
<string name="quick_action_add_gpx_descr">Дугме за додавање GPX пролазне тачке на средину екрана.</string>
|
||||
<string name="show_images">Прикажи слике</string>
|
||||
<string name="purchase_cancelled_dialog_title">Укинули сте чланарину за OsmAnd Live</string>
|
||||
<string name="purchase_cancelled_dialog_title">Отказали сте чланарину за OsmAnd уживо</string>
|
||||
<string name="purchase_cancelled_dialog_descr">Обновите чланарину да наставите да користите све ове функционалности:</string>
|
||||
<string name="gpxup_identifiable">Може да се користи за идентификацију</string>
|
||||
<string name="gpxup_trackable">Може да се користи за праћење</string>
|
||||
|
@ -2581,7 +2581,7 @@
|
|||
<string name="default_render_descr">Стил опште намене. Густи градови су приказани јасно. Приказује изохипсе, путање, квалитет подлоге, забране приступа, блокаде путева, исцртавање путева по SAC алпској скали, објекти за спортове на брзацима.</string>
|
||||
<string name="open_wikipedia_link_online">Отвори Википедија везу са интернетом</string>
|
||||
<string name="open_wikipedia_link_online_description">Веза ће бити отворена у веб читачу.</string>
|
||||
<string name="read_wikipedia_offline_description">Да бисте читали чланке са Википедије и Wikivoyage-а, претплатите се на OsmAnd Live.</string>
|
||||
<string name="read_wikipedia_offline_description">Да бисте читали чланке са Википедије и Wikivoyage-а, купите чланарину на OsmAnd уживо.</string>
|
||||
<string name="how_to_open_link">Како да отворим везу?</string>
|
||||
<string name="read_wikipedia_offline">Читај Википедију ван мреже</string>
|
||||
<string name="download_all">Преузми све</string>
|
||||
|
@ -2703,7 +2703,7 @@
|
|||
\n - Окретањем мапе према компасу или правцу кретања
|
||||
\n - Навођењем у праву траку, приказ ограничења брзине, снимљени и синтетизовани гласови за навођење
|
||||
\n</string>
|
||||
<string name="get_osmand_live">Набавите OsmAnd Live да откључате ове могућности: дневна ажурирања карти са неограниченим бројем скидања, сви и плаћени и бесплатни додаци, Википедија, Wikivoyage и још много тога.</string>
|
||||
<string name="get_osmand_live">Набавите OsmAnd уживо да откључате ове могућности: дневна ажурирања карти са неограниченим бројем скидања, сви и плаћени и бесплатни додаци, Википедија, Wikivoyage и још много тога.</string>
|
||||
<string name="osmand_extended_description_part3">Карта
|
||||
\n • Приказ тачака од интереса око Вас
|
||||
\n • Подешавање карте према правцу кретања (или компасу)
|
||||
|
@ -2777,14 +2777,14 @@
|
|||
<string name="osm_live_payment_month_cost_descr">%1$s / месечно</string>
|
||||
<string name="osm_live_payment_month_cost_descr_ex">%1$.2f %2$s / месечно</string>
|
||||
<string name="osm_live_payment_discount_descr">Уштедите %1$s</string>
|
||||
<string name="osm_live_payment_current_subscription">Тренутна претплата</string>
|
||||
<string name="osm_live_payment_current_subscription">Тренутна чланарина</string>
|
||||
<string name="osm_live_payment_renews_monthly">Месечно обнављање</string>
|
||||
<string name="osm_live_payment_renews_quarterly">Квартално обнављање</string>
|
||||
<string name="osm_live_payment_renews_annually">Годишње обнављање</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="osm_live_subscriptions">Претплате</string>
|
||||
<string name="osm_live_subscriptions">Чланарине</string>
|
||||
<string name="mapillary_menu_title_pano">Прикажи само слике од 360°</string>
|
||||
<string name="shared_string_launch">Покрени</string>
|
||||
<string name="lang_gn_py">Гварани</string>
|
||||
|
@ -2894,8 +2894,8 @@
|
|||
<string name="tracks_on_map">Приказане путање</string>
|
||||
<string name="sit_on_the_stop">Укрцавање на стајању</string>
|
||||
<string name="quick_action_show_hide_gpx_tracks_descr">Дугме које приказује или сакрива одабране путање са карте.</string>
|
||||
<string name="use_osm_live_public_transport_description">Омогући јавни превоз на OsmAnd Live изменама.</string>
|
||||
<string name="use_osm_live_public_transport">OsmAnd Live јавни превоз</string>
|
||||
<string name="use_osm_live_public_transport_description">Омогући јавни превоз на OsmAnd уживо изменама.</string>
|
||||
<string name="use_osm_live_public_transport">OsmAnd уживо јавни превоз</string>
|
||||
<string name="rendering_attr_surface_sett_name">Калдрма</string>
|
||||
<string name="rendering_attr_surface_paving_stones_name">Поплочано камење</string>
|
||||
<string name="rendering_attr_highway_class_motorway_name">Ауто-пут</string>
|
||||
|
@ -3119,7 +3119,7 @@
|
|||
<string name="get_discount_first_part">%1$s првих %2$s</string>
|
||||
<string name="get_discount_first_few_part">%1$s првих %2$s</string>
|
||||
<string name="get_discount_second_part">онда %1$s</string>
|
||||
<string name="cancel_subscription">Поништи претплату</string>
|
||||
<string name="cancel_subscription">Поништи чланарину</string>
|
||||
<string name="price_and_discount">%1$s • Уштеди %2$s</string>
|
||||
<string name="configure_profile_info">Поставке за профил:</string>
|
||||
<string name="utm_format_descr">OsmAnd користи UTM Standard format који је сличан, али није истоветан као UTM NATO format.</string>
|
||||
|
@ -3330,7 +3330,7 @@
|
|||
<string name="login_and_pass">Корисничко име и лозинка</string>
|
||||
<string name="plugin_global_prefs_info">Ова подешавања додатака су глобална и примењују се на све профиле</string>
|
||||
<string name="osm_editing">OSM уређивање</string>
|
||||
<string name="osm_edits_view_descr">Све своје још увек не отпремљене измене или ОСМ белешке можете погледати у %1$s. Отпремљене тачке се не приказују у ОсмАнду.</string>
|
||||
<string name="osm_edits_view_descr">Погледајте све Ваше још увек неотпремљене измене или ОСМ белешке у %1$s. Отпремљене тачке се не више приказују.</string>
|
||||
<string name="app_mode_osm">OSM</string>
|
||||
<string name="select_nav_icon_descr">Иконица која се приказује за време навођења или померања.</string>
|
||||
<string name="select_map_icon_descr">Иконица која се приказује у мировању.</string>
|
||||
|
@ -3484,7 +3484,7 @@
|
|||
<string name="measure_distance_item">Измери удаљеност</string>
|
||||
<string name="travel_item">Путовање (Wikivoyage и Википедија)</string>
|
||||
<string name="favorites_item">Омиљени</string>
|
||||
<string name="subscription_osmandlive_item">Претплата - OsmAnd уживо</string>
|
||||
<string name="subscription_osmandlive_item">Чланарина - OsmAnd уживо</string>
|
||||
<string name="osmand_purchases_item">OsmAnd куповине</string>
|
||||
<string name="legend_item_description">Упутство за легенду карте.</string>
|
||||
<string name="navigation_profiles_item">Профили навођења</string>
|
||||
|
@ -3650,9 +3650,9 @@
|
|||
<string name="context_menu_actions">Акције Контекст менија</string>
|
||||
<string name="osm_live_payment_subscription_management">Наплатом ће бити оптерећен ваш Гугл Плеј налог при потврди куповине.
|
||||
\n
|
||||
\n Претплата се аутоматски обнавља уколико није отказана пре датума обнове. Ваш налог биће задужен периодом обнове (месец / три месеца / годину дана) само на дан обнове.
|
||||
\nЧланарина се аутоматски обнавља уколико није отказана пре датума обнове. Ваш налог биће задужен периодом обнове (месец / три месеца / годину дана) само на дан обнове.
|
||||
\n
|
||||
\n Претплатама можете управљати и отказати их тако што ћете отићи на ваша Гугл Плеј подешавања.</string>
|
||||
\nЧланаринама можете управљати и отказати их тако што ћете отићи на ваша Гугл Плеј подешавања.</string>
|
||||
<string name="release_3_7">• Нове офлајн мапе нагиба
|
||||
\n
|
||||
\n • Пуно прилагођавање Фаворита и ГПКС тачака – прилагођавање боја, икона, облика
|
||||
|
@ -3683,9 +3683,9 @@
|
|||
<string name="lenght_limit_description">Унесите дужину возила, нека ограничења пута могу бити примењена за дужа возила.</string>
|
||||
<string name="quick_action_remove_next_destination">Обриши најближу одредишну тачку</string>
|
||||
<string name="please_provide_point_name_error">Молимо одредите име тачке</string>
|
||||
<string name="quick_action_remove_next_destination_descr">Тренутна одредишна тачка биће уклоњена. Ако је она одредишна, стопираће се навигација.</string>
|
||||
<string name="quick_action_remove_next_destination_descr">Уклања тренутну одредишну тачку. Ако је она и завршна тачка, навођење ће се зауставити.</string>
|
||||
<string name="search_download_wikipedia_maps">Преузмите мапе Википедије</string>
|
||||
<string name="plugin_wikipedia_description">Информације о тачкама од интереса потражите на Википедији. То је ваш џепни ванмрежни водич - само укључите додатак Википедија и уживајте у чланцима о објектима око вас.</string>
|
||||
<string name="plugin_wikipedia_description">Информације о тачкама од интереса потражите на Википедији, џепном ванмрежном водичу који има чланке о местима и одредиштима.</string>
|
||||
<string name="app_mode_enduro_motorcycle">Ендуро скутер</string>
|
||||
<string name="app_mode_motor_scooter">Скутер</string>
|
||||
<string name="app_mode_wheelchair">Инвалидска колица</string>
|
||||
|
@ -3723,7 +3723,7 @@
|
|||
<string name="navigation_profile">Навигацијски профил</string>
|
||||
<string name="route_between_points_add_track_desc">Изаберите датотеку записа којој ће се додати нови сегмент.</string>
|
||||
<string name="street_level_imagery">Слике на нивоу улице</string>
|
||||
<string name="plan_route_exit_dialog_descr">Да ли сте сигурни да желите да одбаците све промене на планираној рути затварањем\?</string>
|
||||
<string name="plan_route_exit_dialog_descr">Да ли сте сигурни да желите да одбаците све промене на планираној рути\?</string>
|
||||
<string name="in_case_of_reverse_direction">У случају обрнутог правца</string>
|
||||
<string name="shared_string_save_as_gpx">Сачувај као нову датотеку стазе</string>
|
||||
<string name="add_segment_to_the_track">Додај у датотеку стазе</string>
|
||||
|
@ -3761,9 +3761,9 @@
|
|||
<string name="gpx_monitoring_stop">Паузирај снимање пута</string>
|
||||
<string name="one_point_error">Додајте бар две тачке.</string>
|
||||
<string name="osm_edit_logout_success">Одјављен</string>
|
||||
<string name="gpx_upload_private_visibility_descr">„Приватно“ значи да се траг не појављује ни на једној јавној листи, али су тачке праћења у њему у нехронолошком редоследу доступне путем јавног ГПС АПИ-ја без временских ознака.</string>
|
||||
<string name="gpx_upload_identifiable_visibility_descr">„Могуће је идентификовати“ значи да ће се траг јавно приказати у вашим ГПС траговима и у јавним списковима ГПС трагова, тј. други корисници ће моћи да преузму необрађени траг и повежу га са вашим корисничким именом. Јавни подаци о временским тачкама трага из ГПС АПИ-ја који се сервирају путем АПИ-ја за тачке праћења имаће референцу на вашу оригиналну страницу праћења.</string>
|
||||
<string name="gpx_upload_trackable_visibility_descr">„Следљиво“ значи да се траг не приказује нигде на јавним листама, али обрађене тачке праћења са временским ознакама у њима (које не могу бити директно повезане са вама) иду кроз преузимања са јавног ГПС АПИ-ја.</string>
|
||||
<string name="gpx_upload_private_visibility_descr">„Приватно“ значи да се траг не појављује ни на једној јавној листи, али су тачке праћења у њему у нехронолошком редоследу доступне путем јавног GPS API-ја без временских ознака.</string>
|
||||
<string name="gpx_upload_identifiable_visibility_descr">„Могуће је идентификовати“ значи да ће се траг јавно приказати у Вашим GPS траговима и у јавним списковима GPS трагова, тј. други корисници ће моћи да преузму необрађени траг и повежу га са Вашим корисничким именом. Јавни подаци о временским тачкама трага из GPS API-ја који се сервирају путем API-ја за тачке праћења имаће референцу на вашу оригиналну страницу праћења.</string>
|
||||
<string name="gpx_upload_trackable_visibility_descr">„Следљиво“ значи да се траг не приказује нигде на јавним листама, али обрађене тачке праћења са временским ознакама у њима (које не могу бити директно повезане са вама) иду кроз преузимања са јавног GPS API-ја.</string>
|
||||
<string name="osm_edit_close_note">Затвори ОСМ белешку</string>
|
||||
<string name="osm_edit_comment_note">Коментар ОСМ напомене</string>
|
||||
<string name="osm_login_descr">Можете се пријавити користећи безбедан ОАут метод или користити своје корисничко име и лозинку.</string>
|
||||
|
@ -3776,12 +3776,12 @@
|
|||
<string name="shared_string_search_history">Претрага</string>
|
||||
<string name="app_mode_kayak">Кајак</string>
|
||||
<string name="app_mode_motorboat">Моторни чамац</string>
|
||||
<string name="add_to_mapillary">Додај у Мапилари</string>
|
||||
<string name="add_to_opr">Додај у ОпенПлејсРевјуз</string>
|
||||
<string name="add_photos_descr">ОсмАнд приказује фотографије из неколико извора:
|
||||
\nОпенПлејсРевјуз - ПОИ фотографије;
|
||||
\nМапилари - слике на нивоу улице;
|
||||
\nВеб / Викимедиа - ПОИ фотографије наведене у подацима ОпенСтритМап.</string>
|
||||
<string name="add_to_mapillary">Додај у Mapillary</string>
|
||||
<string name="add_to_opr">Додај у OpenPlaceReviews</string>
|
||||
<string name="add_photos_descr">OsmAnd приказује фотографије из неколико извора:
|
||||
\nOpenPlaceReviews - фотографије тачака од интереса;
|
||||
\nMapillary - слике на нивоу улице;
|
||||
\nВеб / Викимедија - фотографије тачака од интереса наведене у OpenStreetMap подацима.</string>
|
||||
<string name="shared_string_resources">Ресурси</string>
|
||||
<string name="approximate_file_size">Приближна величина датотеке</string>
|
||||
<string name="select_data_to_export">Изаберите податке за извоз у датотеку.</string>
|
||||
|
@ -3795,7 +3795,7 @@
|
|||
<string name="mgrs_format_descr">ОсмАнд користи МГРС, који је сличан УТМ НАТО формату.</string>
|
||||
<string name="simplified_track">Поједностављена стаза</string>
|
||||
<string name="simplified_track_description">Само линија руте ће бити сачувана, а путне тачке ће бити избрисане.</string>
|
||||
<string name="disable_recording_once_app_killed_descrp">Паузираће евидентирање стазе када се апликација убије (преко скорашњих програма). (Индикатор рада OsmAnd-а у позадини тада нестаје из обавештајне траке.)</string>
|
||||
<string name="disable_recording_once_app_killed_descrp">Евидентирање стазе ће бити паузирано када се апликација убије (преко скорашњих програма). (Индикатор рада OsmAnd-а у позадини тада нестаје из обавештајне траке.)</string>
|
||||
<string name="save_global_track_interval_descr">Наведите интервал евидентирања за опште снимање стаза (укључено помоћу виџета „Снимање путовања“ на мапи).</string>
|
||||
<string name="gpx_monitoring_start">Наставите снимање путовања</string>
|
||||
<string name="system_default_theme">Системско подразумевана</string>
|
||||
|
@ -3827,17 +3827,17 @@
|
|||
<string name="sort_name_descending">Име: З - А</string>
|
||||
<string name="sort_name_ascending">Име: А - З</string>
|
||||
<string name="contour_lines_thanks">Хвала вам што сте купили „Контурне линије“</string>
|
||||
<string name="osm_live_payment_desc_hw">Претплата се наплаћује по изабраном периоду. Откажите га у АппГалери у било ком тренутку.</string>
|
||||
<string name="osm_live_payment_subscription_management_hw">Уплата ће бити наплаћена са вашег рачуна АппГалери при потврди куповине.
|
||||
<string name="osm_live_payment_desc_hw">Чланарина се наплаћује по изабраном периоду. Откажите је у AppGallery у било ком тренутку.</string>
|
||||
<string name="osm_live_payment_subscription_management_hw">Уплата ће бити наплаћена са вашег рачуна AppGallery при потврди куповине.
|
||||
\n
|
||||
\nПретплата се аутоматски обнавља уколико није отказана пре датума обнове. Ваш рачун ће бити задужен за период обнове (месец / три месеца / година) само на датум обнове.
|
||||
\nЧланарина се аутоматски обнавља уколико није отказана пре датума обнове. Ваш рачун ће бити задужен за период обнове (месец / три месеца / година) само на датум обнове.
|
||||
\n
|
||||
\nПретплатама можете управљати и отказати их тако што ћете отићи у подешавања апликације АппГалери.</string>
|
||||
\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">ОсмАнд лајв подаци</string>
|
||||
<string name="use_live_routing">ОсмАнд лајв подаци</string>
|
||||
<string name="use_live_public_transport">OsmAnd уживо подаци</string>
|
||||
<string name="use_live_routing">OsmAnd уживо подаци</string>
|
||||
<string name="complex_routing_descr">Двофазно усмеравање за аутомобилску навигацију.</string>
|
||||
<string name="use_native_pt">Развој матичног јавног превоза</string>
|
||||
<string name="use_native_pt_desc">Пребаците се на Јава (безбедан) прорачун рутирања јавног превоза</string>
|
||||
|
@ -3847,9 +3847,9 @@
|
|||
<string name="file_already_imported">Датотека је већ увезена у ОсмАнд</string>
|
||||
<string name="use_two_phase_routing">Користите двофазни алгоритам усмеравања А*</string>
|
||||
<string name="shared_string_graph">Графикон</string>
|
||||
<string name="message_need_calculate_route_before_show_graph">%1$s подаци доступни само на путевима, морате израчунати руту користећи „Рута између тачака“ да бисте је добили.</string>
|
||||
<string name="message_graph_will_be_available_after_recalculation">Сачекајте поновно израчунавање руте.
|
||||
\nГрафикон ће бити доступан након поновног израчунавања.</string>
|
||||
<string name="message_need_calculate_route_before_show_graph">%1$s подаци доступни само на путевима, израчунајте руту користећи „Рута између тачака“ да бисте видели графике.</string>
|
||||
<string name="message_graph_will_be_available_after_recalculation">Молимо сачекајте.
|
||||
\nГрафикон ће бити доступан након поновног израчунавања путање.</string>
|
||||
<string name="shared_string_local_maps">Локалне мапе</string>
|
||||
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
|
||||
<string name="app_mode_gap">Размак</string>
|
||||
|
@ -3871,15 +3871,15 @@
|
|||
<string name="use_login_password">Користите корисничко име и лозинку</string>
|
||||
<string name="login_account">Налог</string>
|
||||
<string name="user_login">Пријавите се</string>
|
||||
<string name="manage_subscription">Управљајте претплатом</string>
|
||||
<string name="subscription_payment_issue_title">Постоји проблем са вашом претплатом. Кликните на дугме да бисте отворили подешавања претплате за Гугле Плеј и да бисте поправили начин плаћања.</string>
|
||||
<string name="subscription_expired_title">Претплата на ОсмАнд лајв је истекла</string>
|
||||
<string name="subscription_paused_title">Претплата на ОсмАнд лајв је паузирана</string>
|
||||
<string name="subscription_on_hold_title">Претплата на ОсмАнд лајв је на чекању</string>
|
||||
<string name="manage_subscription">Управљајте чланарином</string>
|
||||
<string name="subscription_payment_issue_title">Постоји проблем са Вашом чланарином. Кликните на дугме да бисте отворили подешавања претплате за Гугле Плеј и да бисте поправили начин плаћања.</string>
|
||||
<string name="subscription_expired_title">Чланарина за OsmAnd уживо је истекла</string>
|
||||
<string name="subscription_paused_title">Чланарина на OsmAnd уживо је паузирана</string>
|
||||
<string name="subscription_on_hold_title">Чланарина на OsmAnd уживо је на чекању</string>
|
||||
<string name="markers_history">Историја маркера</string>
|
||||
<string name="send_files_to_openstreetmap">Пошаљите ГПКС датотеку на ОпенСтритМап</string>
|
||||
<string name="enter_text_separated">Унесите ознаке одвојене зарезом.</string>
|
||||
<string name="gpx_upload_public_visibility_descr">„Јавно“ значи да је траг јавно приказан у вашим ГПС траговима и на јавним ГПС траговима, као и на јавном списку трагова са временским ознакама у сировом облику. Подаци који се приказују путем АПИ-ја не упућују на вашу страницу трагова. Временске ознаке праћења нису доступне путем јавног ГПС АПИ-ја и тачке праћења нису хронолошки поређане.</string>
|
||||
<string name="gpx_upload_public_visibility_descr">„Јавно“ значи да је траг јавно приказан у вашим GPS траговима и на јавним GPS траговима, као и на јавном списку трагова са временским ознакама у сировом облику. Подаци који се приказују путем API-ја не упућују на вашу страницу трагова. Временске ознаке праћења нису доступне путем јавног GPS API-ја и тачке праћења нису хронолошки поређане.</string>
|
||||
<string name="cannot_upload_image">Није могуће отпремити слику, покушајте поново касније</string>
|
||||
<string name="select_picture">Изаберите слику</string>
|
||||
<string name="select_groups_for_import">Изаберите групе које ће бити увезене.</string>
|
||||
|
@ -3895,11 +3895,11 @@
|
|||
<string name="plan_route_add_new_segment">Додајте нови сегмент</string>
|
||||
<string name="release_3_9">• Додата је опција за извоз и увоз свих података, укључујући подешавања, ресурсе, моја места
|
||||
\n
|
||||
\n • Планирање руте: графикони за сегменте са рутом, додата је могућност креирања и уређивања вишеструких сегмената стаза
|
||||
\n • Планирање руте: графикони за сегменте са рутом, и додата је могућност креирања и уређивања вишеструких сегмената стаза
|
||||
\n
|
||||
\n • Додан је метод аутентификације ОАут за ОпенСтритМап, побољшан кориснички интерфејс ОСМ дијалога
|
||||
\n
|
||||
\n • Прилагођене боје за омиљене и путне тачаке стаза
|
||||
\n • Подршка за прилагођене боје за омиљене и пролазне тачке путања
|
||||
\n
|
||||
\n</string>
|
||||
<string name="activity_type_water_name">Вода</string>
|
||||
|
@ -3959,7 +3959,7 @@
|
|||
<string name="routing_engine_vehicle_type_cycling_electric">Екетрични бициклизам</string>
|
||||
<string name="routing_engine_vehicle_type_cycling_mountain">Планински бициклизам</string>
|
||||
<string name="routing_engine_vehicle_type_cycling_road">Друмски бициклизам</string>
|
||||
<string name="routing_engine_vehicle_type_cycling_regular">Стаднардни бициклизам</string>
|
||||
<string name="routing_engine_vehicle_type_cycling_regular">Стандардни бициклизам</string>
|
||||
<string name="routing_engine_vehicle_type_hgv">Теретни камион</string>
|
||||
<string name="routing_engine_vehicle_type_small_truck">Камионет</string>
|
||||
<string name="routing_engine_vehicle_type_truck">Камион</string>
|
||||
|
@ -3988,4 +3988,98 @@
|
|||
<string name="rename_track">Преименуј путању</string>
|
||||
<string name="trip_recording_save_and_continue">Сачувај и настави</string>
|
||||
<string name="lost_data_warning">Сви несачувани подаци ће бити изгубљени.</string>
|
||||
<string name="routing_attr_prefer_hiking_routes_description">Преферира планинске пешачке путеве</string>
|
||||
<string name="routing_attr_prefer_hiking_routes_name">Преферирај планинске пешачке путеве</string>
|
||||
<string name="routing_attr_allow_intermittent_description">Дозвољава водене токове који некад пресуше</string>
|
||||
<string name="routing_attr_allow_streams_description">Дозвољава потоке и одвоје</string>
|
||||
<string name="routing_attr_allow_streams_name">Дозволи потоке и одводе</string>
|
||||
<string name="routing_attr_allow_intermittent_name">Дозволи несталне водене токове</string>
|
||||
<string name="shared_string_api_key">Кључ API-ја</string>
|
||||
<string name="shared_string_server_url">Адреса сервера</string>
|
||||
<string name="shared_string_enter_param">Унесите параметар</string>
|
||||
<string name="keep_it_empty_if_not">Задржи је празном ако није</string>
|
||||
<string name="online_routing_example_hint">Адреса са свим параметрима ће изгледати овако:</string>
|
||||
<string name="test_route_calculation">Тестирај израчунавање пута</string>
|
||||
<string name="shared_string_folders">Фасцикле</string>
|
||||
<string name="select_folder">Одаберите фасциклу</string>
|
||||
<string name="select_folder_descr">Одаберите фасциклу или додајте нову</string>
|
||||
<string name="analyze_by_intervals">Анализирај интервале поделе</string>
|
||||
<string name="upload_to_openstreetmap">Отпреми на OpenStreetMap</string>
|
||||
<string name="change_folder">Измени фасциклу</string>
|
||||
<string name="shared_string_sec">сек</string>
|
||||
<string name="announcement_time_passing">Пролажење</string>
|
||||
<string name="announcement_time_approach">Прилазак</string>
|
||||
<string name="announcement_time_prepare_long">Припрема унапред</string>
|
||||
<string name="announcement_time_prepare">Припрема</string>
|
||||
<string name="announcement_time_off_route">Ван пута</string>
|
||||
<string name="announcement_time_arrive">Долазак на одредиште</string>
|
||||
<string name="shared_string_turn">Скретање</string>
|
||||
<string name="announcement_time_intervals">Интервали времена и удаљености</string>
|
||||
<string name="announcement_time_descr">Времена објава различитих гласовних навођења зависе од типа објаве, као и тренутне и подразумеване брзине навођења.</string>
|
||||
<string name="online_routing_engines">Мрежни усмеривачи</string>
|
||||
<string name="routing_engine_vehicle_type_foot">Пешке</string>
|
||||
<string name="routing_engine_vehicle_type_driving">Вожња аутомобила</string>
|
||||
<string name="edit_online_routing_engine">Измени мрежни усмеривач</string>
|
||||
<string name="add_online_routing_engine">Додај мрежни усмеривач</string>
|
||||
<string name="online_routing_engine">Мрежни усмеривач</string>
|
||||
<string name="delete_online_routing_engine">Обриши овај мрежни усмеривач\?</string>
|
||||
<string name="delete_waypoints">Обриши пролазну тачку</string>
|
||||
<string name="copy_to_map_markers">Копирај у ознаке карте</string>
|
||||
<string name="hillshade_slope_contour_lines">Рељеф / Нагиб / Контурне линије</string>
|
||||
<string name="open_place_reviews">OpenPlaceReviews</string>
|
||||
<string name="login_open_place_reviews">Пријавите се за OpenPlaceReviews</string>
|
||||
<string name="activity_type_offroad_name">Вожња ван пута</string>
|
||||
<string name="quick_action_coordinates_widget_descr">Прекидач да на карти покаже или сакрије справицу са координатама.</string>
|
||||
<string name="map_widget_distance_by_tap">Удаљеност по кликтању</string>
|
||||
<string name="latest_openstreetmap_update">Последње OpenStreetMap ажурирање доступно:</string>
|
||||
<string name="trip_recording_logging_interval_info">Временски интервал бележења на који ће OsmAnd да пита за податке о тренутној позицији.</string>
|
||||
<string name="show_start_dialog">Прикажи почетни дијалог</string>
|
||||
<string name="trip_recording_show_start_dialog_setting">Ако се искључи, снимање ће почети одмах после кликтања на справицу или на ставку менија, прескакајући дијалог потврде.</string>
|
||||
<string name="customize_route_line">Прилагоди линију руте</string>
|
||||
<string name="route_line_use_map_style_appearance">Линија руте ће користити %1$s одабран на означеном стилу карте: %2$s.</string>
|
||||
<string name="shared_string_route_line">Линија руте</string>
|
||||
<string name="specify_color_for_map_mode">Одаберите боју за режим карте: %1$s.</string>
|
||||
<string name="no_purchases">Немате ниједну куповину</string>
|
||||
<string name="new_device_account">Нови уређај / нови налог</string>
|
||||
<string name="contact_support_description">Ако имате икаквих питања, контактирајте нас на %1$s.</string>
|
||||
<string name="empty_purchases_description">Ако се Ваша куповина не појави овде, кликните на „%1$s” или контактирајте нашу подршку.</string>
|
||||
<string name="contact_support">Контактирајте подршку</string>
|
||||
<string name="troubleshooting">Решавање проблема</string>
|
||||
<string name="troubleshooting_description">Пратите ову везу ако имате икаквих проблема са куповином.</string>
|
||||
<string name="osmand_live">OsmAnd уживо</string>
|
||||
<string name="renew_subscription">Обнови чланарину</string>
|
||||
<string name="annual_subscription">Годишња чланарина</string>
|
||||
<string name="monthly_subscription">Месечна чланарина</string>
|
||||
<string name="three_months_subscription">Тромесечна чланарина</string>
|
||||
<string name="next_billing_date">Следећи датум наплате: %1$s</string>
|
||||
<string name="osmand_live_cancelled">Отказано</string>
|
||||
<string name="in_grace_period">У грејс периоду</string>
|
||||
<string name="on_hold">На чекању</string>
|
||||
<string name="expired">Истекло</string>
|
||||
<string name="update_all_maps_added">Ажурирај све карте додате на %1$s\?</string>
|
||||
<string name="exit_number">Број излаза</string>
|
||||
<string name="announce_when_exceeded">Објави када се премаши</string>
|
||||
<string name="user_points">Кориснички поени</string>
|
||||
<string name="output">Излаз</string>
|
||||
<string name="open_place_reviews_plugin_description">OpenPlaceReviews је пројакат покретан од стране заједнице о јавним местима, као што су ресторани, хотели, пролазне тачке. Пројекат сакупља јавне информације о њима, као што су слике, рецензије, везе ка другим местима као OpenStreetMap или Википедија.
|
||||
\n
|
||||
\nСви подаци на OpenPlaceReview су отворени и доступни свима: http://openplacereviews.org/data.
|
||||
\n
|
||||
\nМожете прочитати више на: http://openplacereviews.org</string>
|
||||
<string name="release_4_0_beta">• Ажурирања OsmAnd уживо су премештена у „Преузимања > Ажурирања”
|
||||
\n
|
||||
\n • Путање се сада могу обојити по висини, брзини или нагибу.
|
||||
\n
|
||||
\n • Додата опција да се измени изглед линије која се приказује приликом навођења
|
||||
\n
|
||||
\n • Ажуриран дијалог за „Снимање пута”
|
||||
\n
|
||||
\n</string>
|
||||
<string name="copy_address">Копирај адресу</string>
|
||||
<string name="voice_prompts_timetable">Времена гласовних навођења</string>
|
||||
<string name="profile_type_osmand_string">OsmAnd профил</string>
|
||||
<string name="profile_type_user_string">Кориснички профил</string>
|
||||
<string name="reverse_all_points">Обрни све тачке</string>
|
||||
<string name="profile_by_default_description">Одаберите профил које ће се користити по покретању апликације.</string>
|
||||
<string name="shared_string_last_used">Последње коришћено</string>
|
||||
</resources>
|
|
@ -3926,4 +3926,6 @@
|
|||
<string name="poi_hoops">Ringar</string>
|
||||
<string name="poi_office_diplomatic">Diplomatiskt kontor</string>
|
||||
<string name="poi_bay_filter">Typ av vik</string>
|
||||
<string name="poi_plateau">Platå</string>
|
||||
<string name="poi_club_social">Social klubb</string>
|
||||
</resources>
|
|
@ -470,7 +470,7 @@
|
|||
<string name="indexing_map">Indexerar kartan …</string>
|
||||
<string name="indexing_poi">Indexerar Intressepunkter …</string>
|
||||
<string name="indexing_transport">Indexerar transport …</string>
|
||||
<string name="shared_string_io_error">Ett I/O-fel har inträffat</string>
|
||||
<string name="shared_string_io_error">I/O-fel</string>
|
||||
<string name="km">km</string>
|
||||
<string name="km_h">km/h</string>
|
||||
<string name="m">m</string>
|
||||
|
@ -736,7 +736,7 @@
|
|||
<string name="favourites_remove_dialog_success">Favoritpunkten {0} togs bort utan problem.</string>
|
||||
<string name="osb_comment_dialog_message">Meddelande</string>
|
||||
<string name="osb_comment_dialog_author">Författarnamn</string>
|
||||
<string name="osb_comment_dialog_success">Kommentaren lades till utan problem</string>
|
||||
<string name="osb_comment_dialog_success">Kommentaren tillagd</string>
|
||||
<string name="osb_comment_dialog_error">Det gick inte att lägga till kommentar.</string>
|
||||
<string name="poi_edit_title">Redigera POI</string>
|
||||
<string name="poi_create_title">Skapa POI</string>
|
||||
|
@ -759,7 +759,7 @@
|
|||
<string name="osmand_srtm_short_description_80_chars">OsmAnd-modul för höjdkurvor offline</string>
|
||||
<string name="map_widget_distancemeasurement">Avståndsmätning</string>
|
||||
<string name="map_widget_audionotes">Ljudanteckningar</string>
|
||||
<string name="audionotes_plugin_description">Denna modul för ljud- och videoanteckningar erbjuder möjlighet att skapa ljud-/foto-/videoanteckningar under en resa, antingen med hjälp av en knapp på kartskärmen eller direkt i kontextmenyn för en position på kartan.</string>
|
||||
<string name="audionotes_plugin_description">Gör ljud-/foto-/videoanteckningar under en resa, med antingen en kartknapp eller platsens snabbmeny.</string>
|
||||
<string name="audionotes_plugin_name">Ljud-/Videoanteckningar</string>
|
||||
<string name="index_srtm_parts">delar</string>
|
||||
<string name="index_srtm_ele">Höjdkurvor</string>
|
||||
|
@ -1259,7 +1259,10 @@
|
|||
<string name="fav_point_emoticons_message">Vi ändrade namnet på din favoritpunkt till %1$s för att underlätta din smiley i filnamnet.</string>
|
||||
<string name="speed_limit_exceed_message">Välj hur mycket hastighetsgränsen måste överskridas för att du ska få ett röstmeddelande.</string>
|
||||
<string name="speed_limit_exceed">Tolerans för hastighetsgräns</string>
|
||||
<string name="anonymous_user_hint">En anonym användare kan inte:\n- skapa grupper;\n- synkronisera grupper och enheter med servern;\n- hantera grupper och enheter på ett personligt ställe på webbplatsen.</string>
|
||||
<string name="anonymous_user_hint">Anonyma användare kan inte:
|
||||
\n- Skapa grupper;
|
||||
\n- Synkronisera grupper och enheter med servern;
|
||||
\n- Hantera grupper och enheter i en personlig instrumentpanel på webbplatsen.</string>
|
||||
<string name="anonymous_user">Anonym användare</string>
|
||||
<string name="logged_as">Inloggad som %1$s</string>
|
||||
<string name="configure_map">Konfigurera kartan</string>
|
||||
|
@ -1357,11 +1360,11 @@
|
|||
<string name="notes">Anteckningar</string>
|
||||
<string name="online_map">Online-karta</string>
|
||||
<string name="share_note">Dela anteckning</string>
|
||||
<string name="plugin_nautical_descr">Om du aktiverar denna vy ändras kartstilen till Nautisk och visar alla sjömärken och sjökortssymboler.
|
||||
<string name="plugin_nautical_descr">Detta plugin berikar OsmAnds kart- och navigationsapp för att också producera nautiska kartor för båtliv, segling och andra typer av vattensporter.
|
||||
\n
|
||||
\nEn kartfil som innehåller alla nautiska symboler globalt finns tillgänglig som en enda nedladdning med namnet \'World seamarks\'.
|
||||
\nEtt speciellt karttillägg för OsmAnd kommer att tillhandahålla alla nautiska navigationsmärken och kartsymboler, både för inland och för närliggande navigering. Beskrivningen av varje navigeringsmärke innehåller de detaljer som behövs för att identifiera dem och deras betydelse (kategori, form, färg, sekvens, referens etc.).
|
||||
\n
|
||||
\nDenna vy kan ändras genom att antingen inaktivera den här igen eller genom att ändra kartstilen under Konfigurera kartor.</string>
|
||||
\nFör att återgå till en av OsmAnds konventionella kartstilar, helt enkelt avaktivera detta plugin igen, eller ändra \'Kartstil\' under \'Konfigurera karta\' efter önskemål.</string>
|
||||
<string name="plugin_ski_descr">Detta plugin för OsmAnd ger dig detaljer om globala utförsåkning, längdskidspår, alpina skidvägar, linbanor och skidliftar. Rutter och pister visas färgkodade av svårigheter och avbildas i en speciell \"vinter\" -stil som liknar ett snöfärgat vinterlandskap.
|
||||
\n
|
||||
\nOm du aktiverar den här vyn ändras kartstilen till \"Vinter och skidor\" och visar alla landskapsfunktioner under vinterförhållanden. Denna vy kan återställas genom att antingen avaktivera den igen här, eller genom att ändra \'Kartstil\' under \'Konfigurera karta\' efter önskemål.</string>
|
||||
|
@ -1415,12 +1418,12 @@
|
|||
<string name="shared_string_more">Mer…</string>
|
||||
<string name="shared_string_more_actions">Fler åtgärder</string>
|
||||
<string name="shared_string_do_not_show_again">Visa inte nästa gång</string>
|
||||
<string name="shared_string_remember_my_choice">Kom ihåg mitt val</string>
|
||||
<string name="shared_string_remember_my_choice">Kom ihåg valet</string>
|
||||
<string name="shared_string_refresh">Uppdatera</string>
|
||||
<string name="shared_string_download">Hämta</string>
|
||||
<string name="shared_string_downloading">Laddar ner…</string>
|
||||
<string name="shared_string_download_successful">Hämtningen lyckades</string>
|
||||
<string name="shared_string_unexpected_error">Ett oväntat fel uppstod</string>
|
||||
<string name="shared_string_download_successful">Nedladdat</string>
|
||||
<string name="shared_string_unexpected_error">Oväntat fel</string>
|
||||
<string name="shared_string_action_template">Åtgärd {0}</string>
|
||||
<string name="shared_string_close">Stäng</string>
|
||||
<string name="shared_string_exit">Utgång</string>
|
||||
|
@ -1430,10 +1433,10 @@
|
|||
<string name="shared_string_map">Karta</string>
|
||||
<string name="shared_string_favorite">Favorit</string>
|
||||
<string name="shared_string_favorites">Favoriter</string>
|
||||
<string name="shared_string_add_to_favorites">Lägg till i Favoriter</string>
|
||||
<string name="shared_string_add_to_favorites">Lägg till i \'Favoriter\'</string>
|
||||
<string name="shared_string_my_location">Min position</string>
|
||||
<string name="shared_string_my_places">Mina platser</string>
|
||||
<string name="shared_string_my_favorites">Mina favoriter</string>
|
||||
<string name="shared_string_my_favorites">Favoriter</string>
|
||||
<string name="shared_string_tracks">Mina spår</string>
|
||||
<string name="shared_string_currently_recording_track">Spelar för tillfället in spår</string>
|
||||
<string name="shared_string_audio">Ljud</string>
|
||||
|
@ -1459,21 +1462,21 @@
|
|||
<string name="your_edits">Dina redigeringar</string>
|
||||
<string name="osmand_parking_overdue">över tiden</string>
|
||||
<string name="delay_to_start_navigation_descr">Ange väntetid att stanna kvar på ruttplaneringsskärmen.</string>
|
||||
<string name="delay_to_start_navigation">Börja sväng-efter-sväng-navigering efter …</string>
|
||||
<string name="delay_to_start_navigation">Starta sväng-för-sväng-vägledning efter …</string>
|
||||
<string name="shared_string_go">Kör</string>
|
||||
<string name="local_osm_changes_upload_all_confirm">Du håller på att skicka %1$d ändring(ar) till OSM. Är du säker?</string>
|
||||
<string name="confirmation_to_clear_history">Vill du tömma historiken?</string>
|
||||
<string name="local_osm_changes_upload_all_confirm">Är du säker på att du vill ladda upp %1$d ändringar till OSM\?</string>
|
||||
<string name="confirmation_to_clear_history">Rensa historik\?</string>
|
||||
<string name="current_route">Aktuell rutt</string>
|
||||
<string name="osm_changes_added_to_local_edits">OSM-ändringar lades till i lokala ändringar</string>
|
||||
<string name="mark_to_delete">Markera för att ta bort</string>
|
||||
<string name="confirm_usage_speed_cameras">I många länder (Tyskland, Frankrike, Italien och andra) är det inte tillåtet att använda varningar för hastighetskameror. OsmAnd tar inget ansvar om du bryter mot lagen. Tryck på Ja endast om du får använda denna funktion.</string>
|
||||
<string name="confirm_usage_speed_cameras">I många länder (Tyskland, Frankrike, Italien och andra) är användning av hastighetskameravarningar olaglig. OsmAnd tar inget ansvar om du bryter mot lagen. Klicka bara på \'Ja\' om du är berättigad att använda den här funktionen.</string>
|
||||
<string name="welmode_download_maps">Hämta kartor</string>
|
||||
<string name="welcome_select_region">För att avspegla dina trafiksignaler och -förordningar på ett korrekt sätt, välj den region du kör i:</string>
|
||||
<string name="welcome_text">OsmAnd erbjuder global frånkopplad kartsurfning och frånkopplad navigering.</string>
|
||||
<string name="welcome_header">Välkommen</string>
|
||||
<string name="agps_info">A-GPS-info</string>
|
||||
<string name="shared_string_message">Meddelande</string>
|
||||
<string name="agps_data_last_downloaded">A-GPS-data senast nedladdade: %1$s</string>
|
||||
<string name="agps_data_last_downloaded">A-GPS-data har laddats ner: %1$s</string>
|
||||
<string name="shared_string_do_not_use">Använd inte</string>
|
||||
<string name="shared_string_address">Adress</string>
|
||||
<string name="shared_string_show_description">Visa beskrivning.</string>
|
||||
|
@ -1488,9 +1491,9 @@
|
|||
<string name="index_name_netherlands">Europa - Nederländerna</string>
|
||||
<string name="rendering_value_highContrastRoads_name">Högkontrastvägar</string>
|
||||
<string name="rendering_value__name">Standard</string>
|
||||
<string name="application_dir_change_warning3">Kopiera OsmAnds datafiler till den nya destinationen?</string>
|
||||
<string name="application_dir_change_warning3">Flytta OsmAnds datafiler till den nya destinationen\?</string>
|
||||
<string name="specified_directiory_not_writeable">Kunde inte skapa kartor i den angivna mappen</string>
|
||||
<string name="copying_osmand_file_failed">Kopieringen misslyckades</string>
|
||||
<string name="copying_osmand_file_failed">Det gick inte att flytta filer</string>
|
||||
<string name="storage_directory_external">Extern lagring</string>
|
||||
<string name="storage_directory_multiuser">Lagring för flera användare</string>
|
||||
<string name="storage_directory_internal_app">Internt appminne</string>
|
||||
|
@ -1512,16 +1515,16 @@
|
|||
<string name="shared_string_wikipedia">Wikipedia</string>
|
||||
<string name="local_indexes_cat_wiki">Wikipedia</string>
|
||||
<string name="shared_string_show_details">Visa detaljer</string>
|
||||
<string name="local_recordings_delete_all_confirm">Du håller på att ta bort %1$d anteckningar. Är du säker?</string>
|
||||
<string name="local_recordings_delete_all_confirm">Är du säker på att du vill ta bort %1$d anteckningar\?</string>
|
||||
<string name="download_wikipedia_maps">Wikipedia</string>
|
||||
<string name="shared_string_import2osmand">Importera till OsmAnd</string>
|
||||
<string name="gps_network_not_enabled">Platstjänsten är av. Vill du slå på den\?</string>
|
||||
<string name="archive_wikipedia_data">Du har gamla och inkompatibla data från Wikipedia. Vill du arkivera dem?</string>
|
||||
<string name="download_wikipedia_files">Hämta ytterligare data från Wikipedia (%1$s MB)?</string>
|
||||
<string name="download_wikipedia_files">Hämta ytterligare data från Wikipedia (%1$s MB)\?</string>
|
||||
<string name="lang_vo">Volapük</string>
|
||||
<string name="lang_th">Thai</string>
|
||||
<string name="lang_te">Telugu</string>
|
||||
<string name="lang_nn">Norska (nynorska)</string>
|
||||
<string name="lang_nn">Norska (Nynorska)</string>
|
||||
<string name="lang_new">Newar/Nepal Bhasa</string>
|
||||
<string name="lang_ms">Malajiska</string>
|
||||
<string name="lang_ht">Haitiska</string>
|
||||
|
@ -1565,7 +1568,7 @@
|
|||
<string name="rendering_value_translucent_blue_name">Genomskinlig blå</string>
|
||||
<string name="rendering_value_purple_name">Purpur</string>
|
||||
<string name="rendering_value_translucent_purple_name">Genomskinlig purpur</string>
|
||||
<string name="restart_is_required">Starta om appen manuellt för att ändringarna ska börja gälla.</string>
|
||||
<string name="restart_is_required">En omstart krävs för att tillämpa ändringen.</string>
|
||||
<string name="rendering_attr_currentTrackColor_name">GPX-färg</string>
|
||||
<string name="rendering_value_yellow_name">Gul</string>
|
||||
<string name="rendering_value_default13_name">Standard (13)</string>
|
||||
|
@ -1589,8 +1592,8 @@
|
|||
<string name="shared_string_undo">ÅNGRA</string>
|
||||
<string name="shared_string_skip">Hoppa över</string>
|
||||
<string name="app_name_osmand">OsmAnd</string>
|
||||
<string name="routing_attr_avoid_shuttle_train_name">Undvik pendeltåg</string>
|
||||
<string name="routing_attr_avoid_shuttle_train_description">Undvik att använda pendeltåg</string>
|
||||
<string name="routing_attr_avoid_shuttle_train_name">Inget pendeltåg</string>
|
||||
<string name="routing_attr_avoid_shuttle_train_description">Undviker att använda pendeltåg</string>
|
||||
<string name="plugin_settings">Insticksprogram</string>
|
||||
<string name="traffic_warning_hazard">Varning</string>
|
||||
<string name="tab_title_basic">Grundläggande</string>
|
||||
|
@ -1600,7 +1603,7 @@
|
|||
<string name="opening_at">Öppnar</string>
|
||||
<string name="closing_at">Stänger</string>
|
||||
<string name="av_locations">Platser</string>
|
||||
<string name="av_locations_descr">GPX-fil med anteckningar om platser.</string>
|
||||
<string name="av_locations_descr">GPX-fil med platser.</string>
|
||||
<string name="poi_dialog_poi_type">Typ av POI</string>
|
||||
<string name="add_opening_hours">Lägg till öppettider</string>
|
||||
<string name="contact_info">Kontaktinformation</string>
|
||||
|
@ -1620,7 +1623,7 @@
|
|||
<string name="simulate_your_location_stop_descr">Sluta simulera din plats.</string>
|
||||
<string name="simulate_your_location_descr">Simulera din plats med en beräknad rutt eller med ett inspelat GPX-spår.</string>
|
||||
<string name="downloads_left_template">%1$s nedladdningar kvar</string>
|
||||
<string name="favourites_edit_dialog_title">Information om favoriter</string>
|
||||
<string name="favourites_edit_dialog_title">Favoritinformation</string>
|
||||
<string name="roads">Vägar</string>
|
||||
<string name="favourites_context_menu_add">Lägg till favorit</string>
|
||||
<string name="default_speed_system_descr">Ange enhet för hastighet.</string>
|
||||
|
@ -1634,7 +1637,7 @@
|
|||
<string name="si_nm_h">Sjömil per timme (knop)</string>
|
||||
<string name="shared_string_trip_recording">Inspelning av resa</string>
|
||||
<string name="shared_string_navigation">Navigering</string>
|
||||
<string name="osmand_running_in_background">Körs i bakgrunden</string>
|
||||
<string name="osmand_running_in_background">Kör i bakgrunden</string>
|
||||
<string name="favorite_category_add_new">Lägg till ny</string>
|
||||
<string name="favorite_category_select">Välj kategori</string>
|
||||
<string name="count_of_lines">Antal rader</string>
|
||||
|
@ -1653,7 +1656,7 @@
|
|||
<string name="activate_srtm_plugin">Aktivera modulen SRTM</string>
|
||||
<string name="later">Senare</string>
|
||||
<string name="get_full_version">Fullversionen</string>
|
||||
<string name="favorite_category_dublicate_message">Det angivna kategorinamnet finns redan. Ange ett annat namn.</string>
|
||||
<string name="favorite_category_dublicate_message">Använd ett kategorinamn som inte redan finns.</string>
|
||||
<string name="favorite_category_name">Kategorinamn</string>
|
||||
<string name="favorite_category_add_new_title">Lägg till en ny kategori</string>
|
||||
<string name="file_size_in_mb">%.1f MB</string>
|
||||
|
@ -1668,9 +1671,9 @@
|
|||
<string name="share_menu_location">Dela platsen</string>
|
||||
<string name="shared_string_send">Sänd</string>
|
||||
<string name="hillshade_layer_disabled">Skuggad relief-lager inaktiverat</string>
|
||||
<string name="show_on_start_description">\'Av\' startar kartskärmen direkt.</string>
|
||||
<string name="show_on_start_description">\'Av\' startar kartan direkt.</string>
|
||||
<string name="map_downloaded">Karta hämtad</string>
|
||||
<string name="map_downloaded_descr">Kartan över %1$s har hämtats, och du kan nu börja använda den.</string>
|
||||
<string name="map_downloaded_descr">%1$s -kartan är redo att användas.</string>
|
||||
<string name="go_to_map">Visa kartan</string>
|
||||
<string name="shared_string_qr_code">QR-kod</string>
|
||||
<string name="enter_country_name">Ange land</string>
|
||||
|
@ -1693,7 +1696,7 @@
|
|||
<string name="versions_item">Versioner</string>
|
||||
<string name="contact_us">Kontakta oss</string>
|
||||
<string name="osm_edit_created_poi">Skapat en OSM POI</string>
|
||||
<string name="world_map_download_descr">Baskarta över världen (täcker hela världen med låg zoomningsgrad) saknas eller är gammal. Hämta gärna denna karta för en global översikt.</string>
|
||||
<string name="world_map_download_descr">Världskarta (täcker hela världen vid låg zoomnivå) saknas eller är föråldrad. Överväg att ladda ner den för en global översikt.</string>
|
||||
<string name="shared_string_upload">Skicka</string>
|
||||
<string name="map_legend">Teckenförklaring</string>
|
||||
<string name="shared_string_update">Uppdatering</string>
|
||||
|
@ -1721,9 +1724,9 @@
|
|||
<string name="osn_comment_dialog_title">Lägg till kommentar</string>
|
||||
<string name="osn_reopen_dialog_title">Öppna anteckning igen</string>
|
||||
<string name="osn_close_dialog_title">Stäng anteckning</string>
|
||||
<string name="osn_add_dialog_success">En anteckning har skapats utan problem</string>
|
||||
<string name="osn_add_dialog_success">Anteckningen har skapats</string>
|
||||
<string name="osn_add_dialog_error">Det gick inte att skapa anteckningen.</string>
|
||||
<string name="osn_close_dialog_success">Anteckningen stängdes utan problem</string>
|
||||
<string name="osn_close_dialog_success">Anteckningen stängd</string>
|
||||
<string name="osn_close_dialog_error">Det gick inte att stänga anteckningen.</string>
|
||||
<string name="context_menu_item_delete_waypoint">Ta bort GPX-waypoint?</string>
|
||||
<string name="context_menu_item_edit_waypoint">Redigera GPX-waypoint</string>
|
||||
|
@ -1767,8 +1770,8 @@
|
|||
<string name="route_duration">Tid:</string>
|
||||
<string name="missing_write_external_storage_permission">Appen har inte tillåtelse att använda SD-kortet</string>
|
||||
<string name="no_location_permission">Ge platsåtkomst.</string>
|
||||
<string name="no_camera_permission">Appen har inte tillräckliga behörigheter för att komma åt kameran.</string>
|
||||
<string name="no_microphone_permission">Appen har inte tillräckliga behörigheter för att komma åt mikrofonen.</string>
|
||||
<string name="no_camera_permission">Ge kameraåtkomst.</string>
|
||||
<string name="no_microphone_permission">Ge mikrofonåtkomst.</string>
|
||||
<string name="select_voice_provider">Välj röstvägledning</string>
|
||||
<string name="select_voice_provider_descr">Välj eller hämta röstvägledning för ditt språk.</string>
|
||||
<string name="impassable_road_desc">Välj de vägar du vill undvika under navigering.</string>
|
||||
|
@ -1790,7 +1793,7 @@
|
|||
<string name="starting_point">Startpunkt</string>
|
||||
<string name="item_removed">Post borttagen</string>
|
||||
<string name="n_items_removed">poster raderade</string>
|
||||
<string name="shared_string_undo_all">ÅNGRA ALLA</string>
|
||||
<string name="shared_string_undo_all">Ångra allt</string>
|
||||
<string name="rendering_attr_hideIcons_name">POI-ikoner</string>
|
||||
<string name="switch_start_finish">Skifta startpunkt och destination</string>
|
||||
<string name="number_of_contributors">Antal bidragsgivare</string>
|
||||
|
@ -1798,10 +1801,10 @@
|
|||
<string name="reports_for">Rapport för</string>
|
||||
<string name="shared_string_select">Välj</string>
|
||||
<string name="shared_string_remove">Ta bort</string>
|
||||
<string name="clear_updates_proposition_message">Du kan ta bort hämtade uppdateringar och få tillbaka originalkartan</string>
|
||||
<string name="clear_updates_proposition_message">Ta bort hämtade uppdateringar och få tillbaka originalkartan</string>
|
||||
<string name="add_time_span">Lägg till tidsspann</string>
|
||||
<string name="road_blocked">Blockerad väg</string>
|
||||
<string name="data_is_not_available">Inga data tillgängliga</string>
|
||||
<string name="data_is_not_available">Ingen data tillgänglig</string>
|
||||
<string name="rendering_attr_hideUnderground_name">Underjordiska objekt</string>
|
||||
<string name="shared_string_read_more">Läs mer</string>
|
||||
<string name="rec_split_storage_size">Lagringsutrymme</string>
|
||||
|
@ -1810,18 +1813,18 @@
|
|||
<string name="shared_string_save_changes">Spara ändringar</string>
|
||||
<string name="find_parking">Hitta en parkeringsplats</string>
|
||||
<string name="show_polygons">Visa polygoner</string>
|
||||
<string name="rendering_attr_showMtbRoutes_name">Visa MTB-rutter</string>
|
||||
<string name="rendering_attr_showMtbRoutes_name">Visa mountainbike spår</string>
|
||||
<string name="select_map_markers">Välj kartmarkörer</string>
|
||||
<string name="shared_string_reverse_order">Omvänd ordning</string>
|
||||
<string name="show_map_markers_description">Aktivera kartmarkörerna.</string>
|
||||
<string name="clear_active_markers_q">Vill du ta bort alla aktiva markörer?</string>
|
||||
<string name="clear_markers_history_q">Vill du radera kartmarkörshistoriken?</string>
|
||||
<string name="clear_active_markers_q">Ta bort alla aktiva markörer\?</string>
|
||||
<string name="clear_markers_history_q">Radera kartmarkörshistoriken\?</string>
|
||||
<string name="active_markers">Aktiva markörer</string>
|
||||
<string name="map_markers">Kartmarkörer</string>
|
||||
<string name="map_marker">Kartmarkör</string>
|
||||
<string name="add_points_to_map_markers_q">Vill du lägga till alla punkter i Kartmarkörer?</string>
|
||||
<string name="add_points_to_map_markers_q">Lägg till alla punkter som kartmarkörer\?</string>
|
||||
<string name="shared_string_add_to_map_markers">Lägg till i Kartmarkörer</string>
|
||||
<string name="consider_turning_polygons_off">Rekommendationen är att slå av rendering av polygoner.</string>
|
||||
<string name="consider_turning_polygons_off">Det är rekommenderat att slå av rendering av polygoner.</string>
|
||||
<string name="map_marker_1st">Första kartmarkör</string>
|
||||
<string name="map_marker_2nd">Andra kartmarkör</string>
|
||||
<string name="shared_string_toolbar">Verktygsfält</string>
|
||||
|
@ -1839,34 +1842,34 @@
|
|||
<string name="donations">Donationer</string>
|
||||
<string name="number_of_recipients">Antal mottagare</string>
|
||||
<string name="osm_user_stat">Redigeringar %1$s, rang %2$s, redigeringar totalt %3$s</string>
|
||||
<string name="osm_editors_ranking">Ranglista OSM-redigerare</string>
|
||||
<string name="osm_editors_ranking">OSM Editor rankning</string>
|
||||
<string name="osm_live_subscription">OsmAnd Live-prenumeration</string>
|
||||
<string name="osm_live_subscribe_btn">Prenumerera</string>
|
||||
<string name="osm_live_email_desc">Krävs för att ge er information om bidrag.</string>
|
||||
<string name="osm_live_user_public_name">Publikt namn</string>
|
||||
<string name="osm_live_email_desc">Behövs för att uppdatera dig om dina bidrag.</string>
|
||||
<string name="osm_live_user_public_name">Offentligt namn</string>
|
||||
<string name="osm_live_hide_user_name">Visa inte mitt namn i rapporter</string>
|
||||
<string name="osm_live_month_cost">Månadskostnad</string>
|
||||
<string name="osm_live_month_cost">Kostnad per månad</string>
|
||||
<string name="osm_live_month_cost_desc">Månadsbetalning</string>
|
||||
<string name="osm_live_active">Aktiv</string>
|
||||
<string name="osm_live_not_active">Inaktiv</string>
|
||||
<string name="osm_live_enter_email">Ange en giltig e-postadress</string>
|
||||
<string name="osm_live_enter_user_name">Ange publikt namn</string>
|
||||
<string name="osm_live_enter_user_name">Ange ett offentligt namn</string>
|
||||
<string name="osm_live_thanks">Tack för att du stödjer OsmAnd!
|
||||
\nFör att aktivera alla nya funktioner behöver du starta om OsmAnd.</string>
|
||||
<string name="osm_live_region_desc">Delar av din donation kommer att skickas till OSM-användare som skickar in kartändringar i det området.</string>
|
||||
<string name="osm_live_subscription_settings">Prenumerationsinställningar</string>
|
||||
<string name="osm_live_ask_for_purchase">Köp en OsmAnd Live-prenumeration först</string>
|
||||
<string name="osm_live_ask_for_purchase">Köp först ett abonnemang på OsmAnd Live</string>
|
||||
<string name="show_transparency_seekbar">Visa transparent sökfält</string>
|
||||
<string name="recalculate_route">Beräkna om rutten</string>
|
||||
<string name="shared_string_topbar">Toppfält</string>
|
||||
<string name="storage_directory_shared">Delat minne</string>
|
||||
<string name="avoid_road">Undvik väg</string>
|
||||
<string name="storage_directory_readonly_desc">Den för tillfället valda datalagringsmappen är skrivskyddad. Lagringsmappen har tillfälligt ändrats till internminnet. Välj en giltig datalagringsmapp.</string>
|
||||
<string name="shared_string_move_up">Flytta upp</string>
|
||||
<string name="shared_string_move_down">Flytta ned</string>
|
||||
<string name="storage_directory_readonly_desc">Växlade till internminnet eftersom den valda datalagringsmappen är skrivskyddad. Välj en skrivbar lagringskatalog.</string>
|
||||
<string name="shared_string_move_up">Flytta ↑</string>
|
||||
<string name="shared_string_move_down">Flytta ↓</string>
|
||||
<string name="finish_navigation">Avsluta navigeringen</string>
|
||||
<string name="full_report">Fullständig rapport</string>
|
||||
<string name="open_street_map_login_and_pass">OpenStreetMap inloggning och lösenord</string>
|
||||
<string name="open_street_map_login_and_pass">OSM-användarnamn och lösenord</string>
|
||||
<string name="no_map_markers_found">Lägg till kartmarkörer via kartan</string>
|
||||
<string name="no_waypoints_found">Hittar inga waypoints</string>
|
||||
<string name="map_widget_bearing">Relativ bäring</string>
|
||||
|
@ -1897,12 +1900,12 @@
|
|||
<string name="rendering_value_medium_name">Mellan</string>
|
||||
<string name="rendering_value_bold_name">Tjock</string>
|
||||
<string name="report">Rapporter</string>
|
||||
<string name="storage_permission_restart_is_required">Nu har appen tillåtelse att skriva till extern lagringsplats. En manuell omstart av appen krävs.</string>
|
||||
<string name="storage_permission_restart_is_required">Appen får nu skriva till extern lagring, men måste startas igen för att göra det.</string>
|
||||
<string name="osm_live_support_region">Stödregion</string>
|
||||
<string name="osm_live_header">Denna prenumeration aktiverar uppdateringar varje timme av kartor runt omkring i världen.
|
||||
\nEn del av inkomsterna går tillbaka till OSM-gemenskapen och betalas ut för varje OSM-bidrag.
|
||||
\nOm du tycker om OsmAnd och OSM och vill stödja och stödjas av dem så är detta ett utmärkt sätt att göra det på.</string>
|
||||
<string name="access_no_destination">Destinationen är inte fastställd</string>
|
||||
<string name="access_no_destination">Tillgänglighetsplugin: Ingen destination inställd</string>
|
||||
<string name="map_widget_magnetic_bearing">Magnetisk bäring</string>
|
||||
<string name="rec_split_clip_length">Klipplängd</string>
|
||||
<string name="file_name_containes_illegal_char">Filnamnet innehåller ogiltiga tecken</string>
|
||||
|
@ -1968,7 +1971,7 @@
|
|||
<string name="no_inet_connection_desc_map">Krävs för att hämta kartor.</string>
|
||||
<string name="search_location">Söker efter plats…</string>
|
||||
<string name="storage_free_space">Oanvänt utrymme</string>
|
||||
<string name="storage_place_description">OsmAnds lagringsplats för data (för kartor, GPX-filer med mera): %1$s.</string>
|
||||
<string name="storage_place_description">OsmAnds lagringsplats för data (för kartor, spårfiler med mera): %1$s.</string>
|
||||
<string name="give_permission">Bevilja tillstånd</string>
|
||||
<string name="allow_access_location">Tillåt platsåtkomst</string>
|
||||
<string name="update_all_maps_now">Uppdatera alla kartor nu\?</string>
|
||||
|
@ -1978,7 +1981,7 @@
|
|||
<string name="replace_favorite_confirmation">Är du säker på att du vill ersätta favoriten %1$s?</string>
|
||||
<string name="clear_tile_data">Rensa alla rutor</string>
|
||||
<string name="search_hint">Ange stad, adress och POI-namn</string>
|
||||
<string name="donation_to_osm">Donation till OpenStreetMap-gemenskapen</string>
|
||||
<string name="donation_to_osm">Donation till OSM-communityn</string>
|
||||
<string name="get_it">Skaffa det</string>
|
||||
<string name="get_for">Skaffa för %1$s</string>
|
||||
<string name="skip_map_downloading_desc">Du har inte några offline-kartor installerade. Du kan välja en karta från listan eller hämta kartor senare via \'Meny - %1$s\'.</string>
|
||||
|
@ -1993,7 +1996,7 @@
|
|||
<string name="save_track_precision">Minsta loggningsprecision</string>
|
||||
<string name="save_track_precision_descr">Filter: Ingen loggning om inte denna noggrannhet uppnås.</string>
|
||||
<string name="christmas_poi">Jul-POI</string>
|
||||
<string name="christmas_desc_q">Visa Jul-POI?</string>
|
||||
<string name="christmas_desc_q">Visa POI:er för julhelgen\?</string>
|
||||
<string name="rendering_value_light_brown_name">Ljusbrun</string>
|
||||
<string name="rendering_value_dark_brown_name">Mörkbrun</string>
|
||||
<string name="rendering_attr_contourColorScheme_name">Färgschema för konturer</string>
|
||||
|
@ -2004,26 +2007,26 @@
|
|||
<string name="shared_string_recorded">Inspelat</string>
|
||||
<string name="shared_string_record">Spela in</string>
|
||||
<string name="gpx_logging_no_data">Inga data</string>
|
||||
<string name="trip_rec_notification_settings_desc">Visa en systemavisering som gör att du kan starta trippinspelning.</string>
|
||||
<string name="routing_attr_allow_motorway_name">Tillåt motorvägar</string>
|
||||
<string name="routing_attr_allow_motorway_description">Tillåt motorvägar.</string>
|
||||
<string name="trip_rec_notification_settings_desc">Visa ett systemmeddelande som gör det möjligt att starta trippinspelning.</string>
|
||||
<string name="routing_attr_allow_motorway_name">Använd motorvägar</string>
|
||||
<string name="routing_attr_allow_motorway_description">Tillåter motorvägar.</string>
|
||||
<string name="wiki_around">Närliggande Wikipedia-artiklar</string>
|
||||
<string name="search_map_hint">Sök stad eller region</string>
|
||||
<string name="search_map_hint">Stad eller region</string>
|
||||
<string name="route_roundabout_short">Tag den %1$d avfarten och kör</string>
|
||||
<string name="upload_poi">Ladda upp POI</string>
|
||||
<string name="route_calculation">Ruttberäkning</string>
|
||||
<string name="gpx_no_tracks_title">Du har inga GPX-filer ännu</string>
|
||||
<string name="gpx_no_tracks_title_folder">Du kan också lägga till GPX-filer i mappen</string>
|
||||
<string name="gpx_no_tracks_title">Du har inga spårfiler än</string>
|
||||
<string name="gpx_no_tracks_title_folder">Du kan också lägga till spårfiler i mappen</string>
|
||||
<string name="gpx_add_track">Lägg till mer…</string>
|
||||
<string name="shared_string_appearance">Utseende</string>
|
||||
<string name="trip_rec_notification_settings">Aktivera snabbstart av inspelning</string>
|
||||
<string name="christmas_desc">Med tanke på den kommande julen och nyåret så kan du välja att visa POI som har med julen att göra: julgranar, julmarknader med mera.</string>
|
||||
<string name="trip_rec_notification_settings">Aktivera snabbinspelning</string>
|
||||
<string name="christmas_desc">Förutse jul- och nyårsferier kan du välja att visa tillhörande intressepunkter som julgranar och marknader etc.</string>
|
||||
<string name="rendering_attr_contourWidth_name">Bredd på konturlinjen</string>
|
||||
<string name="rendering_attr_hideWaterPolygons_description">Vatten</string>
|
||||
<string name="osm_live_payment_desc">Prenumerationsavgiften faktureras varje månad. Avbryt den när som helst i Google Play.</string>
|
||||
<string name="donation_to_osm_desc">En del av din donation skickas till OSM-användare som skickar in ändringar till OpenStreetMap. Kostnaden för abonnemanget förblir densamma.</string>
|
||||
<string name="osm_live_payment_desc">Prenumerationen debiteras per vald period. Avbryt det på Google Play när som helst.</string>
|
||||
<string name="donation_to_osm_desc">En del av din donation skickas till OSM-bidragsgivare. Prenumerationskostnaden förblir densamma.</string>
|
||||
<string name="osm_live_subscription_desc">En prenumeration aktiverar uppdateringar varje timme, dag eller vecka och obegränsade nedladdningar av alla kartor globalt.</string>
|
||||
<string name="osm_live_banner_desc">Erhåll obegränsade karthämtningar och kartuppdateringar oftare än en gång i månaden: varje vecka, dagligen eller varje timme.</string>
|
||||
<string name="osm_live_banner_desc">Få obegränsad nedladdning av kartor, lägg till uppdateringar varje vecka, dagligen eller till och med varje timme.</string>
|
||||
<string name="rendering_value_low_name">Låg</string>
|
||||
<string name="rendering_attr_contourWidth_description">Bredd på konturlinjen</string>
|
||||
<string name="rendering_value_high_name">Hög</string>
|
||||
|
@ -2069,7 +2072,7 @@
|
|||
\n</string>
|
||||
<string name="navigate_point_olc_info_short">Kort OLC
|
||||
\nVänligen tillhandahåll fullständig kod</string>
|
||||
<string name="file_can_not_be_moved">Filen kan inte flyttas.</string>
|
||||
<string name="file_can_not_be_moved">Det gick inte att flytta filen.</string>
|
||||
<string name="shared_string_move">Flytta</string>
|
||||
<string name="shared_string_gpx_tracks">Spår</string>
|
||||
<string name="routing_attr_driving_style_name">Körstil</string>
|
||||
|
@ -2104,7 +2107,7 @@
|
|||
<string name="quick_action_add_marker_descr">Tryck på åtgärdsknappen sätter en kartmarkör i centrum av skärmen.</string>
|
||||
<string name="add_new_folder">Lägg till ny mapp</string>
|
||||
<string name="points_delete_multiple_succesful">Punkt(er) togs bort.</string>
|
||||
<string name="points_delete_multiple">Du håller på att ta bort %1$d punkt(er). Är du säker?</string>
|
||||
<string name="points_delete_multiple">Är du säker på att du vill ta bort %1$d punkt(er)\?</string>
|
||||
<string name="route_points_category_name">Kurvor att passera längs rutten</string>
|
||||
<string name="track_points_category_name">Vägpunkter, sevärdheter, namngivna funktioner</string>
|
||||
<string name="shared_string_gpx_track">Spår</string>
|
||||
|
@ -2135,11 +2138,11 @@
|
|||
<string name="select_street">Välj gator</string>
|
||||
<string name="shared_string_in_name">i %1$s</string>
|
||||
<string name="type_address">Ange adress</string>
|
||||
<string name="type_city_town">Ange stad</string>
|
||||
<string name="type_city_town">Skriv stad/samhälle/ort</string>
|
||||
<string name="type_postcode">Ange postnummer</string>
|
||||
<string name="nearest_cities">Närmaste städer</string>
|
||||
<string name="select_city">Välj stad</string>
|
||||
<string name="select_postcode">Välj postnummer</string>
|
||||
<string name="select_postcode">Postnummer sökning</string>
|
||||
<string name="quick_action_auto_zoom">Autozoomning på/av</string>
|
||||
<string name="quick_action_showhide_osmbugs_descr">Knapp för att visa eller dölja OSM-anteckningar på kartan.</string>
|
||||
<string name="restart_search">Starta om sökningen</string>
|
||||
|
@ -2153,7 +2156,7 @@
|
|||
<string name="favorite_group_name">Gruppnamn</string>
|
||||
<string name="change_color">Ändra färg</string>
|
||||
<string name="edit_name">Redigera namn</string>
|
||||
<string name="quick_action_add_destination">Lägg till destination</string>
|
||||
<string name="quick_action_add_destination">Ange destination</string>
|
||||
<string name="quick_action_replace_destination">Ersätt destination</string>
|
||||
<string name="no_overlay">Inget överlägg</string>
|
||||
<string name="no_underlay">Inget underlägg</string>
|
||||
|
@ -2212,7 +2215,7 @@
|
|||
<string name="mapillary_menu_title_dates">Datum</string>
|
||||
<string name="mapillary_menu_edit_text_hint">Ange användarnamn</string>
|
||||
<string name="mapillary_menu_title_username">Användarnamn</string>
|
||||
<string name="animate_my_location">Animera min plats</string>
|
||||
<string name="animate_my_location">Animera din egen position</string>
|
||||
<string name="analyze_on_map">Analysera på kartan</string>
|
||||
<string name="restore_purchases">Återställ köp</string>
|
||||
<string name="shared_string_paused">Pausad</string>
|
||||
|
@ -2396,15 +2399,15 @@
|
|||
<string name="routing_attr_allow_private_name">Tillåt privat åtkomst</string>
|
||||
<string name="routing_attr_allow_private_description">Tillåta åtkomst till privata områden.</string>
|
||||
<string name="display_zoom_level">Visa zoom-nivå: %1$s</string>
|
||||
<string name="animate_my_location_desc">Aktivera kartpanoreringsanimation av \'Min Position\' under navigering.</string>
|
||||
<string name="animate_my_location_desc">Aktivera animerad kartpanning av \"Min position\" under navigering.</string>
|
||||
<string name="shared_string_overview">Översikt</string>
|
||||
<string name="quick_action_auto_zoom_desc">Ett tryck på den här åtgärdsknappen kommer att slå på/av automatisk zoomkarta enligt din hastighet.</string>
|
||||
<string name="quick_action_auto_zoom_on">Aktivera autozoom karta</string>
|
||||
<string name="quick_action_auto_zoom_off">Inaktivera autozoom karta</string>
|
||||
<string name="quick_action_auto_zoom_desc">Knapp för att slå på eller av hastighetsstyrd automatisk zoom.</string>
|
||||
<string name="quick_action_auto_zoom_on">Aktivera autozoom</string>
|
||||
<string name="quick_action_auto_zoom_off">Inaktivera autozoom</string>
|
||||
<string name="quick_action_add_first_intermediate">Lägg till första mellanliggande</string>
|
||||
<string name="quick_action_add_destination_desc">Genom att trycka på den här åtgärdsknappen blir skärmens mittpunkt resmålet, alla tidigare valda mål blir den senaste mellanliggande destinationen.</string>
|
||||
<string name="quick_action_replace_destination_desc">Genom att trycka på den här åtgärdsknappen kan skärmen centrera den nya ruttdestinationen och ersätta den tidigare valda destinationen (om någon).</string>
|
||||
<string name="quick_action_add_first_intermediate_desc">Genom att trycka på denna åtgärdsknapp kommer skärmens mittpunkt att bli den första mellanliggande destinationen.</string>
|
||||
<string name="quick_action_add_destination_desc">En knapp för att göra skärmen centrerad till ruttdestinationen, en tidigare vald destination skulle bli den sista mellandestinationen.</string>
|
||||
<string name="quick_action_replace_destination_desc">En knapp för att göra skärmen centrerad till den nya ruttdestinationen och ersätta den tidigare valda destinationen (om någon).</string>
|
||||
<string name="quick_action_add_first_intermediate_desc">En knapp för att göra skärmens centrum till den första mellanliggande destinationen.</string>
|
||||
<string name="subscribe_email_desc">Anmäl dig till vår e-postlista om apprabatter och få 3 extra kartnedladdningar!</string>
|
||||
<string name="depth_contour_descr">Havsdjupskonturer och sjömärken.</string>
|
||||
<string name="sea_depth_thanks">Tack för att du köpt \"Nautiska djupkonturer\"</string>
|
||||
|
@ -3358,4 +3361,50 @@
|
|||
<string name="renew_subscription">Förnya prenumerationen</string>
|
||||
<string name="in_grace_period">I nådeperioden</string>
|
||||
<string name="on_hold">Pausad</string>
|
||||
<string name="shared_string_night_map">Nattkarta</string>
|
||||
<string name="add_online_source">Lägg till onlinekälla</string>
|
||||
<string name="clear_tiles_warning">Om du använder dessa ändringar raderas cachade data för denna kakelkälla</string>
|
||||
<string name="vessel_height_warning_link">Ställ in fartygets höjd</string>
|
||||
<string name="vessel_height_warning">Du kan ställa in fartygets höjd för att undvika låga broar. Tänk på att om bron är rörlig kommer vi att använda dess höjd i öppet tillstånd.</string>
|
||||
<string name="vessel_height_limit_description">Ställ in fartygets höjd för att undvika låga broar. Tänk på att om bron är rörlig kommer vi att använda dess höjd i öppet tillstånd.</string>
|
||||
<string name="vessel_width_limit_description">Ställ in fartygets bredd för att undvika smala broar</string>
|
||||
<string name="quick_action_showhide_mapillary_descr">En växling för att visa eller dölja Mapillary-lagret på kartan.</string>
|
||||
<string name="routing_attr_length_description">Ange tillåten fordonslängd på rutter.</string>
|
||||
<string name="routing_attr_length_name">Längdsgräns</string>
|
||||
<string name="shared_string_bearing">Bäring</string>
|
||||
<string name="item_deleted">%1$s har tagits bort</string>
|
||||
<string name="speed_cameras_restart_descr">Starta om appen för att radera all hastighetskameradata.</string>
|
||||
<string name="shared_string_uninstall_and_restart">Avinstallera och starta om</string>
|
||||
<string name="speed_cameras_removed_descr">Den här enheten har inte hastighetskameror.</string>
|
||||
<string name="app_mode_inline_skates">Rullskridskor</string>
|
||||
<string name="quick_action_remove_next_destination">Ta bort närmaste destination</string>
|
||||
<string name="use_volume_buttons_as_zoom_descr">Kontrollera zoomningsnivån för kartan med volymknapparna på enheten.</string>
|
||||
<string name="use_volume_buttons_as_zoom">Volymknappar som zoom</string>
|
||||
<string name="please_provide_point_name_error">Ange ett namn för punkten</string>
|
||||
<string name="quick_action_remove_next_destination_descr">Raderar nästa destination på din rutt. Om det är den slutliga destinationen kommer navigationen att stoppas.</string>
|
||||
<string name="add_hidden_group_info">Den tillagda punkten kommer inte att synas på kartan, eftersom den valda gruppen är dold kan du hitta den i \"%s\".</string>
|
||||
<string name="app_mode_enduro_motorcycle">Enduro motorcykel</string>
|
||||
<string name="app_mode_motor_scooter">Skoter</string>
|
||||
<string name="app_mode_wheelchair">Rullstol</string>
|
||||
<string name="app_mode_wheelchair_forward">Rullstol framåt</string>
|
||||
<string name="show_start_dialog">Visa startdialogrutan</string>
|
||||
<string name="trip_recording_show_start_dialog_setting">Om den är inaktiverad startar inspelningen direkt efter att du har tryckt på widgeten eller menyalternativet och hoppat över bekräftelsedialogrutan.</string>
|
||||
<string name="customize_route_line">Anpassa ruttlinjen</string>
|
||||
<string name="shared_string_route_line">Ruttlinje</string>
|
||||
<string name="route_line_use_map_style_appearance">Ruttlinje skulle användas %1$s som anges i vald kartstil: %2$s.</string>
|
||||
<string name="expired">Upphörd</string>
|
||||
<string name="release_4_0_beta">• OsmAnd Live-uppdateringar flyttade till \"Nedladdningar> Uppdateringar\"
|
||||
\n
|
||||
\n• Spår kan nu färga efter höjd, hastighet eller lutning.
|
||||
\n
|
||||
\n• Lagt till alternativ för att ändra utseendet på navigeringslinjen
|
||||
\n
|
||||
\n• Uppdaterad \"Trip recording\" -dialog
|
||||
\n
|
||||
\n</string>
|
||||
<string name="update_all_maps_added">Uppdatera alla kartor som lagts till i %1$s\?</string>
|
||||
<string name="exit_number">Utgångsnummer</string>
|
||||
<string name="announce_when_exceeded">Meddela när den överskrids</string>
|
||||
<string name="user_points">Användarpunkter</string>
|
||||
<string name="output">Utgång</string>
|
||||
</resources>
|
|
@ -3926,4 +3926,6 @@
|
|||
<string name="poi_karate">Карате</string>
|
||||
<string name="poi_office_diplomatic">Дипломатичне відомство</string>
|
||||
<string name="poi_bay_filter">Тип затоки</string>
|
||||
<string name="poi_plateau">Плато</string>
|
||||
<string name="poi_club_social">Суспільний клуб</string>
|
||||
</resources>
|
|
@ -3926,4 +3926,6 @@
|
|||
<string name="poi_hoops">籃圈</string>
|
||||
<string name="poi_office_diplomatic">外交部</string>
|
||||
<string name="poi_bay_filter">海灣類型</string>
|
||||
<string name="poi_plateau">高原</string>
|
||||
<string name="poi_club_social">社交俱樂部</string>
|
||||
</resources>
|
|
@ -16,8 +16,14 @@
|
|||
<string name="user_points">User points</string>
|
||||
<string name="announce_when_exceeded">Announce when exceeded</string>
|
||||
<string name="exit_number">Exit number</string>
|
||||
<string name="srtm_download_single_help_message">Please select the needed format. You will need to re-download the file to change the format.</string>
|
||||
<string name="srtm_download_list_help_message">OsmAnd provides contour lines data in meters and feet. You will need to re-download the file to change the format.</string>
|
||||
<string name="srtm_unit_format">Contour lines unit format</string>
|
||||
<string name="shared_string_feet">feet</string>
|
||||
<string name="update_all_maps_added">Update all maps added to %1$s?</string>
|
||||
<string name="release_4_0_beta">
|
||||
• Added option to download Contour lines in feet\n\n
|
||||
• Plan Route landscape: added tabs to switch between points or graphs\n\n
|
||||
• OsmAnd Live updates moved to \"Downloads > Updates\"\n\n
|
||||
• Tracks now could be colorizing by altitude, speed, or slope.\n\n
|
||||
• Added option to change the appearance of the navigation route line\n\n
|
||||
|
|
|
@ -3,10 +3,10 @@ package net.osmand;
|
|||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import net.osmand.osm.io.NetworkUtils;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
|
@ -38,6 +38,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
public class AndroidNetworkUtils {
|
||||
|
@ -56,6 +57,15 @@ public class AndroidNetworkUtils {
|
|||
void onFilesUploadDone(@NonNull Map<File, String> errors);
|
||||
}
|
||||
|
||||
public interface OnFilesDownloadCallback {
|
||||
@Nullable
|
||||
Map<String, String> getAdditionalParams(@NonNull File file);
|
||||
void onFileDownloadProgress(@NonNull File file, int percent);
|
||||
@WorkerThread
|
||||
void onFileDownloadedAsync(@NonNull File file);
|
||||
void onFilesDownloadDone(@NonNull Map<File, String> errors);
|
||||
}
|
||||
|
||||
public static class RequestResponse {
|
||||
private Request request;
|
||||
private String response;
|
||||
|
@ -74,35 +84,46 @@ public class AndroidNetworkUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public interface OnRequestsResultListener {
|
||||
void onResult(@NonNull List<RequestResponse> results);
|
||||
public interface OnSendRequestsListener {
|
||||
void onRequestSent(@NonNull RequestResponse response);
|
||||
void onRequestsSent(@NonNull List<RequestResponse> results);
|
||||
}
|
||||
|
||||
public static void sendRequestsAsync(final OsmandApplication ctx,
|
||||
final List<Request> requests,
|
||||
final OnRequestsResultListener listener) {
|
||||
public static void sendRequestsAsync(@Nullable final OsmandApplication ctx,
|
||||
@NonNull final List<Request> requests,
|
||||
@Nullable final OnSendRequestsListener listener) {
|
||||
|
||||
new AsyncTask<Void, Void, List<RequestResponse>>() {
|
||||
new AsyncTask<Void, RequestResponse, List<RequestResponse>>() {
|
||||
|
||||
@Override
|
||||
protected List<RequestResponse> doInBackground(Void... params) {
|
||||
List<RequestResponse> responses = new ArrayList<>();
|
||||
for (Request request : requests) {
|
||||
RequestResponse requestResponse;
|
||||
try {
|
||||
String response = sendRequest(ctx, request.getUrl(), request.getParameters(),
|
||||
request.getUserOperation(), request.isToastAllowed(), request.isPost());
|
||||
responses.add(new RequestResponse(request, response));
|
||||
requestResponse = new RequestResponse(request, response);
|
||||
} catch (Exception e) {
|
||||
responses.add(new RequestResponse(request, null));
|
||||
requestResponse = new RequestResponse(request, null);
|
||||
}
|
||||
responses.add(requestResponse);
|
||||
publishProgress(requestResponse);
|
||||
}
|
||||
return responses;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(RequestResponse... values) {
|
||||
if (listener != null) {
|
||||
listener.onRequestSent(values[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(@NonNull List<RequestResponse> results) {
|
||||
if (listener != null) {
|
||||
listener.onResult(results);
|
||||
listener.onRequestsSent(results);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,7 +167,7 @@ public class AndroidNetworkUtils {
|
|||
|
||||
@Override
|
||||
protected String doInBackground(Void... params) {
|
||||
return downloadFile(url, fileToSave);
|
||||
return downloadFile(url, fileToSave, false, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -158,8 +179,80 @@ public class AndroidNetworkUtils {
|
|||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
|
||||
}
|
||||
|
||||
public static String sendRequest(OsmandApplication ctx, String url, Map<String, String> parameters,
|
||||
String userOperation, boolean toastAllowed, boolean post) {
|
||||
public static void downloadFilesAsync(final @NonNull String url,
|
||||
final @NonNull List<File> files,
|
||||
final @NonNull Map<String, String> parameters,
|
||||
final @Nullable OnFilesDownloadCallback callback) {
|
||||
|
||||
new AsyncTask<Void, Object, Map<File, String>>() {
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
protected Map<File, String> doInBackground(Void... v) {
|
||||
Map<File, String> errors = new HashMap<>();
|
||||
for (final File file : files) {
|
||||
final int[] progressValue = {0};
|
||||
publishProgress(file, 0);
|
||||
IProgress progress = null;
|
||||
if (callback != null) {
|
||||
progress = new NetworkProgress() {
|
||||
@Override
|
||||
public void progress(int deltaWork) {
|
||||
progressValue[0] += deltaWork;
|
||||
publishProgress(file, progressValue[0]);
|
||||
}
|
||||
};
|
||||
}
|
||||
try {
|
||||
Map<String, String> params = new HashMap<>(parameters);
|
||||
if (callback != null) {
|
||||
Map<String, String> additionalParams = callback.getAdditionalParams(file);
|
||||
if (additionalParams != null) {
|
||||
params.putAll(additionalParams);
|
||||
}
|
||||
}
|
||||
boolean firstPrm = !url.contains("?");
|
||||
StringBuilder sb = new StringBuilder(url);
|
||||
for (Entry<String, String> entry : params.entrySet()) {
|
||||
sb.append(firstPrm ? "?" : "&").append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), "UTF-8"));
|
||||
firstPrm = false;
|
||||
}
|
||||
String res = downloadFile(sb.toString(), file, true, progress);
|
||||
if (res != null) {
|
||||
errors.put(file, res);
|
||||
} else {
|
||||
if (callback != null) {
|
||||
callback.onFileDownloadedAsync(file);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
errors.put(file, e.getMessage());
|
||||
}
|
||||
publishProgress(file, Integer.MAX_VALUE);
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Object... objects) {
|
||||
if (callback != null) {
|
||||
callback.onFileDownloadProgress((File) objects[0], (Integer) objects[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(@NonNull Map<File, String> errors) {
|
||||
if (callback != null) {
|
||||
callback.onFilesDownloadDone(errors);
|
||||
}
|
||||
}
|
||||
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
|
||||
}
|
||||
|
||||
public static String sendRequest(@Nullable OsmandApplication ctx, @NonNull String url,
|
||||
@Nullable Map<String, String> parameters,
|
||||
@Nullable String userOperation, boolean toastAllowed, boolean post) {
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
|
||||
|
@ -177,7 +270,7 @@ public class AndroidNetworkUtils {
|
|||
String paramsSeparator = url.indexOf('?') == -1 ? "?" : "&";
|
||||
connection = NetworkUtils.getHttpURLConnection(params == null || post ? url : url + paramsSeparator + params);
|
||||
connection.setRequestProperty("Accept-Charset", "UTF-8");
|
||||
connection.setRequestProperty("User-Agent", Version.getFullVersion(ctx));
|
||||
connection.setRequestProperty("User-Agent", ctx != null ? Version.getFullVersion(ctx) : "OsmAnd");
|
||||
connection.setConnectTimeout(15000);
|
||||
if (params != null && post) {
|
||||
connection.setDoInput(true);
|
||||
|
@ -200,9 +293,10 @@ public class AndroidNetworkUtils {
|
|||
}
|
||||
|
||||
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||
if (toastAllowed) {
|
||||
String msg = userOperation
|
||||
+ " " + ctx.getString(R.string.failed_op) + ": " + connection.getResponseMessage();
|
||||
if (toastAllowed && ctx != null) {
|
||||
String msg = (!Algorithms.isEmpty(userOperation) ? userOperation + " " : "")
|
||||
+ ctx.getString(R.string.failed_op) + ": "
|
||||
+ connection.getResponseMessage();
|
||||
showToast(ctx, msg);
|
||||
}
|
||||
} else {
|
||||
|
@ -233,17 +327,17 @@ public class AndroidNetworkUtils {
|
|||
|
||||
} catch (NullPointerException e) {
|
||||
// that's tricky case why NPE is thrown to fix that problem httpClient could be used
|
||||
if (toastAllowed) {
|
||||
if (toastAllowed && ctx != null) {
|
||||
String msg = ctx.getString(R.string.auth_failed);
|
||||
showToast(ctx, msg);
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
if (toastAllowed) {
|
||||
if (toastAllowed && ctx != null) {
|
||||
showToast(ctx, MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template)
|
||||
+ ": " + ctx.getResources().getString(R.string.shared_string_unexpected_error), userOperation));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (toastAllowed) {
|
||||
if (toastAllowed && ctx != null) {
|
||||
showToast(ctx, MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template)
|
||||
+ ": " + ctx.getResources().getString(R.string.shared_string_io_error), userOperation));
|
||||
}
|
||||
|
@ -277,18 +371,23 @@ public class AndroidNetworkUtils {
|
|||
return res;
|
||||
}
|
||||
|
||||
public static String downloadFile(@NonNull String url, @NonNull File fileToSave) {
|
||||
public static String downloadFile(@NonNull String url, @NonNull File fileToSave, boolean gzip, @Nullable IProgress progress) {
|
||||
String error = null;
|
||||
try {
|
||||
URLConnection connection = NetworkUtils.getHttpURLConnection(url);
|
||||
connection.setConnectTimeout(CONNECTION_TIMEOUT);
|
||||
connection.setReadTimeout(CONNECTION_TIMEOUT);
|
||||
BufferedInputStream inputStream = new BufferedInputStream(connection.getInputStream(), 8 * 1024);
|
||||
if (gzip) {
|
||||
connection.setRequestProperty("Accept-Encoding", "deflate, gzip");
|
||||
}
|
||||
InputStream inputStream = gzip
|
||||
? new GZIPInputStream(connection.getInputStream())
|
||||
: new BufferedInputStream(connection.getInputStream(), 8 * 1024);
|
||||
fileToSave.getParentFile().mkdirs();
|
||||
OutputStream stream = null;
|
||||
try {
|
||||
stream = new FileOutputStream(fileToSave);
|
||||
Algorithms.streamCopy(inputStream, stream);
|
||||
Algorithms.streamCopy(inputStream, stream, progress, 1024);
|
||||
stream.flush();
|
||||
} finally {
|
||||
Algorithms.closeStream(inputStream);
|
||||
|
@ -307,12 +406,17 @@ public class AndroidNetworkUtils {
|
|||
private static final String BOUNDARY = "CowMooCowMooCowCowCow";
|
||||
|
||||
public static String uploadFile(@NonNull String urlText, @NonNull File file, boolean gzip,
|
||||
@NonNull Map<String, String> additionalParams, @Nullable Map<String, String> headers) throws IOException {
|
||||
return uploadFile(urlText, new FileInputStream(file), file.getName(), gzip, additionalParams, headers);
|
||||
@NonNull Map<String, String> additionalParams,
|
||||
@Nullable Map<String, String> headers,
|
||||
@Nullable IProgress progress) throws IOException {
|
||||
return uploadFile(urlText, new FileInputStream(file), file.getName(), gzip, additionalParams, headers, progress);
|
||||
}
|
||||
|
||||
public static String uploadFile(@NonNull String urlText, @NonNull InputStream inputStream, @NonNull String fileName, boolean gzip,
|
||||
Map<String, String> additionalParams, @Nullable Map<String, String> headers) {
|
||||
public static String uploadFile(@NonNull String urlText, @NonNull InputStream inputStream,
|
||||
@NonNull String fileName, boolean gzip,
|
||||
@NonNull Map<String, String> additionalParams,
|
||||
@Nullable Map<String, String> headers,
|
||||
@Nullable IProgress progress) {
|
||||
URL url;
|
||||
try {
|
||||
boolean firstPrm = !urlText.contains("?");
|
||||
|
@ -350,11 +454,11 @@ public class AndroidNetworkUtils {
|
|||
ous.flush();
|
||||
if (gzip) {
|
||||
GZIPOutputStream gous = new GZIPOutputStream(ous, 1024);
|
||||
Algorithms.streamCopy(bis, gous);
|
||||
Algorithms.streamCopy(bis, gous, progress, 1024);
|
||||
gous.flush();
|
||||
gous.finish();
|
||||
} else {
|
||||
Algorithms.streamCopy(bis, ous);
|
||||
Algorithms.streamCopy(bis, ous, progress, 1024);
|
||||
}
|
||||
|
||||
ous.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes());
|
||||
|
@ -406,8 +510,19 @@ public class AndroidNetworkUtils {
|
|||
@NonNull
|
||||
protected Map<File, String> doInBackground(Void... v) {
|
||||
Map<File, String> errors = new HashMap<>();
|
||||
for (File file : files) {
|
||||
for (final File file : files) {
|
||||
final int[] progressValue = {0};
|
||||
publishProgress(file, 0);
|
||||
IProgress progress = null;
|
||||
if (callback != null) {
|
||||
progress = new NetworkProgress() {
|
||||
@Override
|
||||
public void progress(int deltaWork) {
|
||||
progressValue[0] += deltaWork;
|
||||
publishProgress(file, progressValue[0]);
|
||||
}
|
||||
};
|
||||
}
|
||||
try {
|
||||
Map<String, String> params = new HashMap<>(parameters);
|
||||
if (callback != null) {
|
||||
|
@ -416,14 +531,14 @@ public class AndroidNetworkUtils {
|
|||
params.putAll(additionalParams);
|
||||
}
|
||||
}
|
||||
String res = uploadFile(url, file, gzip, params, headers);
|
||||
String res = uploadFile(url, file, gzip, params, headers, progress);
|
||||
if (res != null) {
|
||||
errors.put(file, res);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
errors.put(file, e.getMessage());
|
||||
}
|
||||
publishProgress(file, 100);
|
||||
publishProgress(file, Integer.MAX_VALUE);
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
@ -484,4 +599,39 @@ public class AndroidNetworkUtils {
|
|||
return post;
|
||||
}
|
||||
}
|
||||
|
||||
private abstract static class NetworkProgress implements IProgress {
|
||||
@Override
|
||||
public void startTask(String taskName, int work) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startWork(int work) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void progress(int deltaWork);
|
||||
|
||||
@Override
|
||||
public void remaining(int remainingWork) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishTask() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIndeterminate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInterrupted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGeneralProgress(String genProgress) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ import android.graphics.drawable.ShapeDrawable;
|
|||
import android.graphics.drawable.StateListDrawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import android.os.StatFs;
|
||||
|
@ -264,6 +266,11 @@ public class AndroidUtils {
|
|||
return "";
|
||||
}
|
||||
|
||||
public static String getFreeSpace(Context ctx, File dir) {
|
||||
long size = AndroidUtils.getAvailableSpace(dir);
|
||||
return AndroidUtils.formatSize(ctx, size);
|
||||
}
|
||||
|
||||
public static View findParentViewById(View view, int id) {
|
||||
ViewParent viewParent = view.getParent();
|
||||
|
||||
|
@ -856,11 +863,39 @@ public class AndroidUtils {
|
|||
return result;
|
||||
}
|
||||
|
||||
public static long getAvailableSpace(@NonNull OsmandApplication app) {
|
||||
return getAvailableSpace(app.getAppPath(null));
|
||||
}
|
||||
|
||||
public static long getTotalSpace(@NonNull OsmandApplication app) {
|
||||
return getTotalSpace(app.getAppPath(null));
|
||||
}
|
||||
|
||||
public static long getAvailableSpace(@Nullable File dir) {
|
||||
if (dir != null && dir.canRead()) {
|
||||
try {
|
||||
StatFs fs = new StatFs(dir.getAbsolutePath());
|
||||
return fs.getAvailableBlocksLong() * fs.getBlockSize();
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
return fs.getAvailableBlocksLong() * fs.getBlockSizeLong();
|
||||
} else {
|
||||
return fs.getAvailableBlocks() * fs.getBlockSize();
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static long getTotalSpace(@Nullable File dir) {
|
||||
if (dir != null && dir.canRead()) {
|
||||
try {
|
||||
StatFs fs = new StatFs(dir.getAbsolutePath());
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
return fs.getBlockCountLong() * fs.getBlockSizeLong();
|
||||
} else {
|
||||
return fs.getBlockCount() * fs.getBlockSize();
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
|
@ -887,13 +922,6 @@ public class AndroidUtils {
|
|||
return -1;
|
||||
}
|
||||
|
||||
public static float getUsedSpaceGb(File dir) {
|
||||
if (dir.canRead()) {
|
||||
return getTotalSpaceGb(dir) - getFreeSpaceGb(dir);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static CharSequence getStyledString(CharSequence baseString, CharSequence stringToInsertAndStyle,
|
||||
CharacterStyle baseStyle, CharacterStyle replaceStyle) {
|
||||
int indexOfPlaceholder = baseString.toString().indexOf(STRING_PLACEHOLDER);
|
||||
|
|
|
@ -184,7 +184,8 @@ public class AnalyticsHelper extends SQLiteOpenHelper {
|
|||
|
||||
String jsonStr = json.toString();
|
||||
InputStream inputStream = new ByteArrayInputStream(jsonStr.getBytes());
|
||||
String res = AndroidNetworkUtils.uploadFile(ANALYTICS_UPLOAD_URL, inputStream, ANALYTICS_FILE_NAME, true, additionalData, null);
|
||||
String res = AndroidNetworkUtils.uploadFile(ANALYTICS_UPLOAD_URL, inputStream,
|
||||
ANALYTICS_FILE_NAME, true, additionalData, null, null);
|
||||
if (res != null) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import net.osmand.osm.MapPoiTypes;
|
|||
import net.osmand.plus.activities.LocalIndexHelper;
|
||||
import net.osmand.plus.activities.LocalIndexInfo;
|
||||
import net.osmand.plus.activities.SavingTrackHelper;
|
||||
import net.osmand.plus.backup.BackupHelper;
|
||||
import net.osmand.plus.base.MapViewTrackingUtilities;
|
||||
import net.osmand.plus.download.DownloadActivity;
|
||||
import net.osmand.plus.download.ui.AbstractLoadLocalIndexTask;
|
||||
|
@ -473,6 +474,7 @@ public class AppInitializer implements IProgress {
|
|||
app.oprAuthHelper = startupInit(new OprAuthHelper(app), OprAuthHelper.class);
|
||||
app.onlineRoutingHelper = startupInit(new OnlineRoutingHelper(app), OnlineRoutingHelper.class);
|
||||
app.itineraryHelper = startupInit(new ItineraryHelper(app), ItineraryHelper.class);
|
||||
app.backupHelper = startupInit(new BackupHelper(app), BackupHelper.class);
|
||||
|
||||
initOpeningHoursParser();
|
||||
}
|
||||
|
|
|
@ -146,6 +146,14 @@ public class FavouritesDbHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public long getLastUploadedTime() {
|
||||
return context.getSettings().FAVORITES_LAST_UPLOADED_TIME.get();
|
||||
}
|
||||
|
||||
public void setLastUploadedTime(long time) {
|
||||
context.getSettings().FAVORITES_LAST_UPLOADED_TIME.set(time);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Drawable getColoredIconForGroup(String groupName) {
|
||||
String groupIdName = FavoriteGroup.convertDisplayNameToGroupIdName(context, groupName);
|
||||
|
|
|
@ -18,7 +18,7 @@ import androidx.annotation.Nullable;
|
|||
|
||||
public class GPXDatabase {
|
||||
|
||||
private static final int DB_VERSION = 11;
|
||||
private static final int DB_VERSION = 12;
|
||||
private static final String DB_NAME = "gpx_database";
|
||||
|
||||
private static final String GPX_TABLE_NAME = "gpxTable";
|
||||
|
@ -48,6 +48,7 @@ public class GPXDatabase {
|
|||
|
||||
private static final String GPX_COL_COLOR = "color";
|
||||
private static final String GPX_COL_FILE_LAST_MODIFIED_TIME = "fileLastModifiedTime";
|
||||
private static final String GPX_COL_FILE_LAST_UPLOADED_TIME = "fileLastUploadedTime";
|
||||
|
||||
private static final String GPX_COL_SPLIT_TYPE = "splitType";
|
||||
private static final String GPX_COL_SPLIT_INTERVAL = "splitInterval";
|
||||
|
@ -98,6 +99,7 @@ public class GPXDatabase {
|
|||
GPX_COL_WPT_POINTS + " int, " +
|
||||
GPX_COL_COLOR + " TEXT, " +
|
||||
GPX_COL_FILE_LAST_MODIFIED_TIME + " long, " +
|
||||
GPX_COL_FILE_LAST_UPLOADED_TIME + " long, " +
|
||||
GPX_COL_SPLIT_TYPE + " int, " +
|
||||
GPX_COL_SPLIT_INTERVAL + " double, " +
|
||||
GPX_COL_API_IMPORTED + " int, " + // 1 = true, 0 = false
|
||||
|
@ -133,6 +135,7 @@ public class GPXDatabase {
|
|||
GPX_COL_WPT_POINTS + ", " +
|
||||
GPX_COL_COLOR + ", " +
|
||||
GPX_COL_FILE_LAST_MODIFIED_TIME + ", " +
|
||||
GPX_COL_FILE_LAST_UPLOADED_TIME + ", " +
|
||||
GPX_COL_SPLIT_TYPE + ", " +
|
||||
GPX_COL_SPLIT_INTERVAL + ", " +
|
||||
GPX_COL_API_IMPORTED + ", " +
|
||||
|
@ -184,6 +187,7 @@ public class GPXDatabase {
|
|||
private int splitType;
|
||||
private double splitInterval;
|
||||
private long fileLastModifiedTime;
|
||||
private long fileLastUploadedTime;
|
||||
private boolean apiImported;
|
||||
private boolean showAsMarkers;
|
||||
private boolean joinSegments;
|
||||
|
@ -200,6 +204,11 @@ public class GPXDatabase {
|
|||
this.color = color;
|
||||
}
|
||||
|
||||
public GpxDataItem(File file, long fileLastUploadedTime) {
|
||||
this.file = file;
|
||||
this.fileLastUploadedTime = fileLastUploadedTime;
|
||||
}
|
||||
|
||||
public GpxDataItem(File file, @NonNull GPXFile gpxFile) {
|
||||
this.file = file;
|
||||
readGpxParams(gpxFile);
|
||||
|
@ -263,6 +272,10 @@ public class GPXDatabase {
|
|||
return fileLastModifiedTime;
|
||||
}
|
||||
|
||||
public long getFileLastUploadedTime() {
|
||||
return fileLastUploadedTime;
|
||||
}
|
||||
|
||||
public int getSplitType() {
|
||||
return splitType;
|
||||
}
|
||||
|
@ -441,10 +454,13 @@ public class GPXDatabase {
|
|||
db.execSQL("UPDATE " + GPX_TABLE_NAME + " SET " + GPX_COL_SHOW_START_FINISH + " = ? " +
|
||||
"WHERE " + GPX_COL_SHOW_START_FINISH + " IS NULL", new Object[]{1});
|
||||
}
|
||||
if (oldVersion < 12) {
|
||||
db.execSQL("ALTER TABLE " + GPX_TABLE_NAME + " ADD " + GPX_COL_FILE_LAST_UPLOADED_TIME + " long");
|
||||
}
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS " + GPX_INDEX_NAME_DIR + " ON " + GPX_TABLE_NAME + " (" + GPX_COL_NAME + ", " + GPX_COL_DIR + ");");
|
||||
}
|
||||
|
||||
private boolean updateLastModifiedTime(GpxDataItem item) {
|
||||
private boolean updateLastModifiedTime(@NonNull GpxDataItem item) {
|
||||
SQLiteConnection db = openConnection(false);
|
||||
if (db != null) {
|
||||
try {
|
||||
|
@ -464,6 +480,25 @@ public class GPXDatabase {
|
|||
return false;
|
||||
}
|
||||
|
||||
public boolean updateLastUploadedTime(@NonNull GpxDataItem item, long fileLastUploadedTime) {
|
||||
SQLiteConnection db = openConnection(false);
|
||||
if (db != null) {
|
||||
try {
|
||||
String fileName = getFileName(item.file);
|
||||
String fileDir = getFileDir(item.file);
|
||||
db.execSQL("UPDATE " + GPX_TABLE_NAME + " SET " +
|
||||
GPX_COL_FILE_LAST_UPLOADED_TIME + " = ? " +
|
||||
" WHERE " + GPX_COL_NAME + " = ? AND " + GPX_COL_DIR + " = ?",
|
||||
new Object[] { fileLastUploadedTime, fileName, fileDir });
|
||||
item.fileLastUploadedTime = fileLastUploadedTime;
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean rename(@Nullable GpxDataItem item, File currentFile, File newFile) {
|
||||
SQLiteConnection db = openConnection(false);
|
||||
if (db != null){
|
||||
|
@ -721,11 +756,11 @@ public class GPXDatabase {
|
|||
String gradientScaleType = item.gradientScaleType != null ? item.gradientScaleType.getTypeName() : null;
|
||||
if (a != null) {
|
||||
db.execSQL(
|
||||
"INSERT INTO " + GPX_TABLE_NAME + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
"INSERT INTO " + GPX_TABLE_NAME + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
new Object[] {fileName, fileDir, a.totalDistance, a.totalTracks, a.startTime, a.endTime,
|
||||
a.timeSpan, a.timeMoving, a.totalDistanceMoving, a.diffElevationUp, a.diffElevationDown,
|
||||
a.avgElevation, a.minElevation, a.maxElevation, a.maxSpeed, a.avgSpeed, a.points, a.wptPoints,
|
||||
color, item.file.lastModified(), item.splitType, item.splitInterval, item.apiImported ? 1 : 0,
|
||||
color, item.file.lastModified(), item.fileLastUploadedTime, item.splitType, item.splitInterval, item.apiImported ? 1 : 0,
|
||||
Algorithms.encodeStringSet(item.analysis.wptCategoryNames), item.showAsMarkers ? 1 : 0,
|
||||
item.joinSegments ? 1 : 0, item.showArrows ? 1 : 0, item.showStartFinish ? 1 : 0, item.width,
|
||||
item.gradientSpeedPalette, item.gradientAltitudePalette, item.gradientSlopePalette, gradientScaleType});
|
||||
|
@ -735,6 +770,7 @@ public class GPXDatabase {
|
|||
GPX_COL_DIR + ", " +
|
||||
GPX_COL_COLOR + ", " +
|
||||
GPX_COL_FILE_LAST_MODIFIED_TIME + ", " +
|
||||
GPX_COL_FILE_LAST_UPLOADED_TIME + ", " +
|
||||
GPX_COL_SPLIT_TYPE + ", " +
|
||||
GPX_COL_SPLIT_INTERVAL + ", " +
|
||||
GPX_COL_API_IMPORTED + ", " +
|
||||
|
@ -747,8 +783,8 @@ public class GPXDatabase {
|
|||
GPX_COL_GRADIENT_ALTITUDE_COLOR + ", " +
|
||||
GPX_COL_GRADIENT_SLOPE_COLOR + ", " +
|
||||
GPX_COL_GRADIENT_SCALE_TYPE +
|
||||
") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
new Object[] {fileName, fileDir, color, 0, item.splitType, item.splitInterval,
|
||||
") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
new Object[] {fileName, fileDir, color, 0, item.fileLastUploadedTime, item.splitType, item.splitInterval,
|
||||
item.apiImported ? 1 : 0, item.showAsMarkers ? 1 : 0, item.joinSegments ? 1 : 0,
|
||||
item.showArrows ? 1 : 0, item.showStartFinish ? 1 : 0, item.width,
|
||||
Algorithms.gradientPaletteToString(item.gradientSpeedPalette),
|
||||
|
@ -828,19 +864,20 @@ public class GPXDatabase {
|
|||
int wptPoints = (int)query.getInt(17);
|
||||
String color = query.getString(18);
|
||||
long fileLastModifiedTime = query.getLong(19);
|
||||
int splitType = (int)query.getInt(20);
|
||||
double splitInterval = query.getDouble(21);
|
||||
boolean apiImported = query.getInt(22) == 1;
|
||||
String wptCategoryNames = query.getString(23);
|
||||
boolean showAsMarkers = query.getInt(24) == 1;
|
||||
boolean joinSegments = query.getInt(25) == 1;
|
||||
boolean showArrows = query.getInt(26) == 1;
|
||||
boolean showStartFinish = query.getInt(27) == 1;
|
||||
String width = query.getString(28);
|
||||
String gradientSpeedPalette = query.getString(29);
|
||||
String gradientAltitudePalette = query.getString(30);
|
||||
String gradientSlopePalette = query.getString(31);
|
||||
String gradientScaleType = query.getString(32);
|
||||
long fileLastUploadedTime = query.getLong(20);
|
||||
int splitType = (int)query.getInt(21);
|
||||
double splitInterval = query.getDouble(22);
|
||||
boolean apiImported = query.getInt(23) == 1;
|
||||
String wptCategoryNames = query.getString(24);
|
||||
boolean showAsMarkers = query.getInt(25) == 1;
|
||||
boolean joinSegments = query.getInt(26) == 1;
|
||||
boolean showArrows = query.getInt(27) == 1;
|
||||
boolean showStartFinish = query.getInt(28) == 1;
|
||||
String width = query.getString(29);
|
||||
String gradientSpeedPalette = query.getString(30);
|
||||
String gradientAltitudePalette = query.getString(31);
|
||||
String gradientSlopePalette = query.getString(32);
|
||||
String gradientScaleType = query.getString(33);
|
||||
|
||||
GPXTrackAnalysis a = new GPXTrackAnalysis();
|
||||
a.totalDistance = totalDistance;
|
||||
|
@ -873,6 +910,7 @@ public class GPXDatabase {
|
|||
GpxDataItem item = new GpxDataItem(new File(dir, fileName), a);
|
||||
item.color = parseColor(color);
|
||||
item.fileLastModifiedTime = fileLastModifiedTime;
|
||||
item.fileLastUploadedTime = fileLastUploadedTime;
|
||||
item.splitType = splitType;
|
||||
item.splitInterval = splitInterval;
|
||||
item.apiImported = apiImported;
|
||||
|
|
|
@ -78,6 +78,12 @@ public class GpxDbHelper {
|
|||
return res;
|
||||
}
|
||||
|
||||
public boolean updateLastUploadedTime(GpxDataItem item, long fileLastUploadedTime) {
|
||||
boolean res = db.updateLastUploadedTime(item, fileLastUploadedTime);
|
||||
putToCache(item);
|
||||
return res;
|
||||
}
|
||||
|
||||
public boolean updateGradientScalePalette(@NonNull GpxDataItem item, @NonNull GradientScaleType gradientScaleType, int[] palette) {
|
||||
boolean res = db.updateGradientScaleColor(item, gradientScaleType, palette);
|
||||
putToCache(item);
|
||||
|
|
|
@ -291,10 +291,12 @@ public class GpxSelectionHelper {
|
|||
return group;
|
||||
}
|
||||
|
||||
private String getGroupName(GPXFile g) {
|
||||
public String getGroupName(GPXFile g) {
|
||||
String name = g.path;
|
||||
if (g.showCurrentTrack) {
|
||||
name = getString(R.string.shared_string_currently_recording_track);
|
||||
} else if (Algorithms.isEmpty(name)) {
|
||||
name = getString(R.string.current_route);
|
||||
} else {
|
||||
int i = name.lastIndexOf('/');
|
||||
if (i >= 0) {
|
||||
|
|
|
@ -52,6 +52,7 @@ import net.osmand.plus.activities.SavingTrackHelper;
|
|||
import net.osmand.plus.activities.actions.OsmAndDialogs;
|
||||
import net.osmand.plus.api.SQLiteAPI;
|
||||
import net.osmand.plus.api.SQLiteAPIImpl;
|
||||
import net.osmand.plus.backup.BackupHelper;
|
||||
import net.osmand.plus.base.MapViewTrackingUtilities;
|
||||
import net.osmand.plus.download.DownloadIndexesThread;
|
||||
import net.osmand.plus.download.DownloadService;
|
||||
|
@ -169,6 +170,7 @@ public class OsmandApplication extends MultiDexApplication {
|
|||
MeasurementEditingContext measurementEditingContext;
|
||||
OnlineRoutingHelper onlineRoutingHelper;
|
||||
ItineraryHelper itineraryHelper;
|
||||
BackupHelper backupHelper;
|
||||
|
||||
private Map<String, Builder> customRoutingConfigs = new ConcurrentHashMap<>();
|
||||
private File externalStorageDirectory;
|
||||
|
@ -474,6 +476,10 @@ public class OsmandApplication extends MultiDexApplication {
|
|||
return itineraryHelper;
|
||||
}
|
||||
|
||||
public BackupHelper getBackupHelper() {
|
||||
return backupHelper;
|
||||
}
|
||||
|
||||
public TransportRoutingHelper getTransportRoutingHelper() {
|
||||
return transportRoutingHelper;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import android.app.ProgressDialog;
|
|||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnCancelListener;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.widget.ProgressBar;
|
||||
|
@ -204,7 +205,8 @@ public class ProgressImplementation implements IProgress {
|
|||
work = -1;
|
||||
progress = 0;
|
||||
if (taskName != null) {
|
||||
message = context.getResources().getString(R.string.finished_task) +" : "+ taskName; //$NON-NLS-1$
|
||||
Resources resources = context.getResources();
|
||||
message = resources.getString(R.string.ltr_or_rtl_combine_via_colon, resources.getString(R.string.finished_task), taskName);
|
||||
mViewUpdateHandler.sendEmptyMessage(HANDLER_START_TASK);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -442,15 +442,14 @@ public class UiUtilities {
|
|||
} catch (Throwable e) { }
|
||||
}
|
||||
|
||||
public static void rotateImageByLayoutDirection(ImageView image, int layoutDirection) {
|
||||
public static void rotateImageByLayoutDirection(ImageView image) {
|
||||
if (image == null) {
|
||||
return;
|
||||
}
|
||||
int rotation = layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL ? 180 : 0;
|
||||
int rotation = AndroidUtils.getLayoutDirection(image.getContext()) == ViewCompat.LAYOUT_DIRECTION_RTL ? 180 : 0;
|
||||
image.setRotationY(rotation);
|
||||
}
|
||||
|
||||
|
||||
public static void updateCustomRadioButtons(Context app, View buttonsView, boolean nightMode,
|
||||
CustomRadioButtonType buttonType) {
|
||||
int activeColor = ContextCompat.getColor(app, nightMode
|
||||
|
|
|
@ -13,6 +13,7 @@ import net.osmand.plus.OsmandApplication;
|
|||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.SQLiteTileSource;
|
||||
import net.osmand.plus.Version;
|
||||
import net.osmand.plus.download.SrtmDownloadItem;
|
||||
import net.osmand.plus.download.ui.AbstractLoadLocalIndexTask;
|
||||
import net.osmand.plus.voice.JSMediaCommandPlayerImpl;
|
||||
import net.osmand.plus.voice.JSTTSCommandPlayerImpl;
|
||||
|
@ -143,8 +144,6 @@ public class LocalIndexHelper {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public List<LocalIndexInfo> getLocalIndexInfos(String downloadName) {
|
||||
List<LocalIndexInfo> list = new ArrayList<>();
|
||||
LocalIndexInfo info = getLocalIndexInfo(LocalIndexType.MAP_DATA, downloadName, false, false);
|
||||
|
@ -333,14 +332,15 @@ public class LocalIndexHelper {
|
|||
if (mapPath.canRead()) {
|
||||
for (File mapFile : listFilesSorted(mapPath)) {
|
||||
if (mapFile.isFile() && mapFile.getName().endsWith(IndexConstants.BINARY_MAP_INDEX_EXT)) {
|
||||
String fileName = mapFile.getName();
|
||||
LocalIndexType lt = LocalIndexType.MAP_DATA;
|
||||
if (mapFile.getName().endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)) {
|
||||
if (SrtmDownloadItem.isSrtmFile(fileName)) {
|
||||
lt = LocalIndexType.SRTM_DATA;
|
||||
} else if (mapFile.getName().endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) {
|
||||
} else if (fileName.endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) {
|
||||
lt = LocalIndexType.WIKI_DATA;
|
||||
}
|
||||
LocalIndexInfo info = new LocalIndexInfo(lt, mapFile, backup, app);
|
||||
if (loadedMaps.containsKey(mapFile.getName()) && !backup) {
|
||||
if (loadedMaps.containsKey(fileName) && !backup) {
|
||||
info.setLoaded(true);
|
||||
}
|
||||
updateDescription(info);
|
||||
|
@ -430,5 +430,4 @@ public class LocalIndexHelper {
|
|||
return fileName;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -94,6 +94,12 @@ public class MapActivityKeyListener implements KeyEvent.Callback {
|
|||
mapActivity.getMapViewTrackingUtilities().backToLocationImpl();
|
||||
} else if (keyCode == KeyEvent.KEYCODE_D) {
|
||||
mapActivity.getMapViewTrackingUtilities().switchRotateMapMode();
|
||||
} else if (keyCode == KeyEvent.KEYCODE_MINUS) {
|
||||
mapActivity.changeZoom(-1);
|
||||
return true;
|
||||
} else if (keyCode == KeyEvent.KEYCODE_PLUS || keyCode == KeyEvent.KEYCODE_EQUALS) {
|
||||
mapActivity.changeZoom(1);
|
||||
return true;
|
||||
} else if (mapScrollHelper.isAvailableKeyCode(keyCode)) {
|
||||
return mapScrollHelper.onKeyUp(keyCode, event);
|
||||
} else if (settings.EXTERNAL_INPUT_DEVICE.get() == PARROT_EXTERNAL_DEVICE) {
|
||||
|
@ -121,13 +127,7 @@ public class MapActivityKeyListener implements KeyEvent.Callback {
|
|||
return true;
|
||||
}
|
||||
} else if (settings.EXTERNAL_INPUT_DEVICE.get() == GENERIC_EXTERNAL_DEVICE) {
|
||||
if (keyCode == KeyEvent.KEYCODE_MINUS) {
|
||||
mapActivity.changeZoom(-1);
|
||||
return true;
|
||||
} else if (keyCode == KeyEvent.KEYCODE_PLUS || keyCode == KeyEvent.KEYCODE_EQUALS) {
|
||||
mapActivity.changeZoom(1);
|
||||
return true;
|
||||
}
|
||||
// currently doesn't process specific commands
|
||||
} else if (OsmandPlugin.onMapActivityKeyUp(mapActivity, keyCode)) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ public class PluginInfoFragment extends BaseOsmAndFragment implements PluginStat
|
|||
}
|
||||
}
|
||||
});
|
||||
UiUtilities.rotateImageByLayoutDirection(closeButton, AndroidUtils.getLayoutDirection(app));
|
||||
UiUtilities.rotateImageByLayoutDirection(closeButton);
|
||||
|
||||
Drawable pluginImage = plugin.getAssetResourceImage();
|
||||
if (pluginImage != null) {
|
||||
|
|
|
@ -101,7 +101,7 @@ public class PluginsFragment extends BaseOsmAndFragment implements PluginStateLi
|
|||
}
|
||||
}
|
||||
});
|
||||
UiUtilities.rotateImageByLayoutDirection(closeButton, AndroidUtils.getLayoutDirection(app));
|
||||
UiUtilities.rotateImageByLayoutDirection(closeButton);
|
||||
|
||||
adapter = new PluginsListAdapter(requireContext());
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ import android.media.MediaRecorder;
|
|||
import android.media.SoundPool;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.StatFs;
|
||||
import android.provider.MediaStore;
|
||||
import android.view.Display;
|
||||
import android.view.KeyEvent;
|
||||
|
@ -1607,13 +1606,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
|
|||
double bitrate = (((p.videoBitRate + p.audioBitRate) / 8f) * 60f) / (1 << 30); // gigabytes per minute
|
||||
double clipSpace = bitrate * AV_RS_CLIP_LENGTH.get();
|
||||
double storageSize = AV_RS_STORAGE_SIZE.get();
|
||||
|
||||
double availableSpace = storageSize;
|
||||
File dir = app.getAppPath("").getParentFile();
|
||||
if (dir.canRead()) {
|
||||
StatFs fs = new StatFs(dir.getAbsolutePath());
|
||||
availableSpace = (double) (fs.getAvailableBlocks()) * fs.getBlockSize() / (1 << 30) - clipSpace;
|
||||
}
|
||||
double availableSpace = (double) AndroidUtils.getAvailableSpace(app) / (1 << 30) - clipSpace;
|
||||
|
||||
if (usedSpace + clipSpace > storageSize || clipSpace > availableSpace) {
|
||||
Arrays.sort(files, new Comparator<File>() {
|
||||
|
|
|
@ -11,7 +11,6 @@ import android.media.CamcorderProfile;
|
|||
import android.media.MediaRecorder;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.StatFs;
|
||||
import android.text.SpannableString;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -42,7 +41,6 @@ import net.osmand.plus.widgets.style.CustomTypefaceSpan;
|
|||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -381,16 +379,7 @@ public class MultimediaNotesFragment extends BaseSettingsFragment implements Cop
|
|||
private void setupStorageSizePref(AudioVideoNotesPlugin plugin) {
|
||||
ListPreferenceEx storageSize = (ListPreferenceEx) findPreference(plugin.AV_RS_STORAGE_SIZE.getId());
|
||||
|
||||
File dir = app.getAppPath("").getParentFile();
|
||||
long size = 0;
|
||||
if (dir.canRead()) {
|
||||
try {
|
||||
StatFs fs = new StatFs(dir.getAbsolutePath());
|
||||
size = ((long) fs.getBlockSize() * (long) fs.getBlockCount()) / (1 << 30);
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.error(e);
|
||||
}
|
||||
}
|
||||
long size = AndroidUtils.getTotalSpace(app) / (1 << 30);
|
||||
if (size > 0) {
|
||||
int value = 1;
|
||||
ArrayList<Integer> gbList = new ArrayList<>();
|
||||
|
|
581
OsmAnd/src/net/osmand/plus/backup/BackupHelper.java
Normal file
581
OsmAnd/src/net/osmand/plus/backup/BackupHelper.java
Normal file
|
@ -0,0 +1,581 @@
|
|||
package net.osmand.plus.backup;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.AsyncTask;
|
||||
import android.provider.Settings;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import net.osmand.AndroidNetworkUtils;
|
||||
import net.osmand.AndroidNetworkUtils.OnFilesDownloadCallback;
|
||||
import net.osmand.AndroidNetworkUtils.OnFilesUploadCallback;
|
||||
import net.osmand.AndroidNetworkUtils.OnRequestResultListener;
|
||||
import net.osmand.AndroidNetworkUtils.OnSendRequestsListener;
|
||||
import net.osmand.AndroidNetworkUtils.Request;
|
||||
import net.osmand.AndroidNetworkUtils.RequestResponse;
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.plus.FavouritesDbHelper;
|
||||
import net.osmand.plus.GPXDatabase.GpxDataItem;
|
||||
import net.osmand.plus.GpxDbHelper;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.inapp.InAppPurchaseHelper;
|
||||
import net.osmand.plus.inapp.InAppPurchases.InAppSubscription;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class BackupHelper {
|
||||
|
||||
private final OsmandApplication app;
|
||||
private final OsmandSettings settings;
|
||||
private final FavouritesDbHelper favouritesHelper;
|
||||
private final GpxDbHelper gpxHelper;
|
||||
|
||||
private static final String SERVER_URL = "https://osmand.net";
|
||||
|
||||
private static final String USER_REGISTER_URL = SERVER_URL + "/userdata/user-register";
|
||||
private static final String DEVICE_REGISTER_URL = SERVER_URL + "/userdata/device-register";
|
||||
private static final String UPLOAD_FILE_URL = SERVER_URL + "/userdata/upload-file";
|
||||
private static final String LIST_FILES_URL = SERVER_URL + "/userdata/list-files";
|
||||
private static final String DOWNLOAD_FILE_URL = SERVER_URL + "/userdata/download-file";
|
||||
private static final String DELETE_FILE_URL = SERVER_URL + "/userdata/delete-file";
|
||||
|
||||
public final static int STATUS_SUCCESS = 0;
|
||||
public final static int STATUS_PARSE_JSON_ERROR = 1;
|
||||
public final static int STATUS_EMPTY_RESPONSE_ERROR = 2;
|
||||
public final static int STATUS_SERVER_ERROR = 3;
|
||||
|
||||
public interface OnResultListener {
|
||||
void onResult(int status, @Nullable String message, @Nullable JSONObject json);
|
||||
}
|
||||
|
||||
public interface OnRegisterUserListener {
|
||||
void onRegisterUser(int status, @Nullable String message);
|
||||
}
|
||||
|
||||
public interface OnRegisterDeviceListener {
|
||||
void onRegisterDevice(int status, @Nullable String message);
|
||||
}
|
||||
|
||||
public interface OnDownloadFileListListener {
|
||||
void onDownloadFileList(int status, @Nullable String message, @NonNull List<UserFile> userFiles);
|
||||
}
|
||||
|
||||
public interface OnCollectLocalFilesListener {
|
||||
void onFileCollected(@NonNull GpxFileInfo fileInfo);
|
||||
|
||||
void onFilesCollected(@NonNull List<GpxFileInfo> fileInfos);
|
||||
}
|
||||
|
||||
public interface OnGenerateBackupInfoListener {
|
||||
void onBackupInfoGenerated(@Nullable BackupInfo backupInfo, @Nullable String error);
|
||||
}
|
||||
|
||||
public interface OnUploadFilesListener {
|
||||
void onFileUploadProgress(@NonNull File file, int progress);
|
||||
|
||||
void onFilesUploadDone(@NonNull Map<File, String> errors);
|
||||
}
|
||||
|
||||
public interface OnDeleteFilesListener {
|
||||
void onFileDeleteProgress(@NonNull UserFile file);
|
||||
|
||||
void onFilesDeleteDone(@NonNull Map<UserFile, String> errors);
|
||||
}
|
||||
|
||||
public interface OnDownloadFileListener {
|
||||
void onFileDownloadProgress(@NonNull UserFile userFile, int progress);
|
||||
@WorkerThread
|
||||
void onFileDownloadedAsync(@NonNull File file);
|
||||
void onFilesDownloadDone(@NonNull Map<File, String> errors);
|
||||
}
|
||||
|
||||
public static class BackupInfo {
|
||||
public List<UserFile> filesToDownload = new ArrayList<>();
|
||||
public List<GpxFileInfo> filesToUpload = new ArrayList<>();
|
||||
public List<UserFile> filesToDelete = new ArrayList<>();
|
||||
public List<Pair<GpxFileInfo, UserFile>> filesToMerge = new ArrayList<>();
|
||||
}
|
||||
|
||||
public BackupHelper(@NonNull OsmandApplication app) {
|
||||
this.app = app;
|
||||
this.settings = app.getSettings();
|
||||
this.favouritesHelper = app.getFavorites();
|
||||
this.gpxHelper = app.getGpxDbHelper();
|
||||
}
|
||||
|
||||
@SuppressLint("HardwareIds")
|
||||
private String getAndroidId() {
|
||||
try {
|
||||
return Settings.Secure.getString(app.getContentResolver(), Settings.Secure.ANDROID_ID);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isTokenValid(@NonNull String token) {
|
||||
return token.matches("[0-9]+");
|
||||
}
|
||||
|
||||
public boolean hasOsmLiveUpdates() {
|
||||
return InAppPurchaseHelper.isSubscribedToLiveUpdates(app);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getOrderId() {
|
||||
InAppPurchaseHelper purchaseHelper = app.getInAppPurchaseHelper();
|
||||
InAppSubscription purchasedSubscription = purchaseHelper.getAnyPurchasedSubscription();
|
||||
return purchasedSubscription != null ? purchasedSubscription.getOrderId() : null;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return settings.BACKUP_DEVICE_ID.get();
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
return settings.BACKUP_ACCESS_TOKEN.get();
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return settings.BACKUP_USER_EMAIL.get();
|
||||
}
|
||||
|
||||
public boolean isRegistered() {
|
||||
return !Algorithms.isEmpty(getDeviceId()) && !Algorithms.isEmpty(getAccessToken());
|
||||
}
|
||||
|
||||
private void checkRegistered() throws UserNotRegisteredException {
|
||||
if (Algorithms.isEmpty(getDeviceId()) || Algorithms.isEmpty(getAccessToken())) {
|
||||
throw new UserNotRegisteredException();
|
||||
}
|
||||
}
|
||||
|
||||
public void registerUser(@NonNull String email, @Nullable final OnRegisterUserListener listener) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("email", email);
|
||||
params.put("orderid", getOrderId());
|
||||
params.put("deviceid", app.getUserAndroidId());
|
||||
AndroidNetworkUtils.sendRequestAsync(app, USER_REGISTER_URL, params, "Register user", true, true, new OnRequestResultListener() {
|
||||
@Override
|
||||
public void onResult(String resultJson) {
|
||||
int status;
|
||||
String message;
|
||||
if (!Algorithms.isEmpty(resultJson)) {
|
||||
try {
|
||||
JSONObject result = new JSONObject(resultJson);
|
||||
String statusStr = result.getString("status");
|
||||
if (statusStr.equals("ok")) {
|
||||
message = "You have been registered successfully. Please check for email with activation code.";
|
||||
status = STATUS_SUCCESS;
|
||||
} else {
|
||||
message = "User registration error: " + statusStr;
|
||||
status = STATUS_SERVER_ERROR;
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
message = "User registration error: json parsing";
|
||||
status = STATUS_PARSE_JSON_ERROR;
|
||||
}
|
||||
} else {
|
||||
message = "User registration error: empty response";
|
||||
status = STATUS_EMPTY_RESPONSE_ERROR;
|
||||
}
|
||||
if (listener != null) {
|
||||
listener.onRegisterUser(status, message);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void registerDevice(String token, @Nullable final OnRegisterDeviceListener listener) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("email", getEmail());
|
||||
String orderId = getOrderId();
|
||||
if (orderId != null) {
|
||||
params.put("orderid", orderId);
|
||||
}
|
||||
String androidId = getAndroidId();
|
||||
if (!Algorithms.isEmpty(androidId)) {
|
||||
params.put("deviceid", androidId);
|
||||
}
|
||||
params.put("token", token);
|
||||
AndroidNetworkUtils.sendRequestAsync(app, DEVICE_REGISTER_URL, params, "Register device", true, true, new OnRequestResultListener() {
|
||||
@Override
|
||||
public void onResult(String resultJson) {
|
||||
int status;
|
||||
String message;
|
||||
if (!Algorithms.isEmpty(resultJson)) {
|
||||
try {
|
||||
JSONObject result = new JSONObject(resultJson);
|
||||
settings.BACKUP_DEVICE_ID.set(result.getString("id"));
|
||||
settings.BACKUP_USER_ID.set(result.getString("userid"));
|
||||
settings.BACKUP_NATIVE_DEVICE_ID.set(result.getString("deviceid"));
|
||||
settings.BACKUP_ACCESS_TOKEN.set(result.getString("accesstoken"));
|
||||
settings.BACKUP_ACCESS_TOKEN_UPDATE_TIME.set(result.getString("udpatetime"));
|
||||
status = STATUS_SUCCESS;
|
||||
message = "Device have been registered successfully";
|
||||
} catch (JSONException e) {
|
||||
message = "Device registration error: json parsing";
|
||||
status = STATUS_PARSE_JSON_ERROR;
|
||||
}
|
||||
} else {
|
||||
message = "Device registration error: empty response";
|
||||
status = STATUS_EMPTY_RESPONSE_ERROR;
|
||||
}
|
||||
if (listener != null) {
|
||||
listener.onRegisterDevice(status, message);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void uploadFiles(@NonNull List<GpxFileInfo> gpxFiles, @Nullable final OnUploadFilesListener listener) throws UserNotRegisteredException {
|
||||
checkRegistered();
|
||||
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("deviceid", getDeviceId());
|
||||
params.put("accessToken", getAccessToken());
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Accept-Encoding", "deflate, gzip");
|
||||
|
||||
final Map<File, GpxFileInfo> gpxInfos = new HashMap<>();
|
||||
for (GpxFileInfo gpxFile : gpxFiles) {
|
||||
gpxInfos.put(gpxFile.file, gpxFile);
|
||||
}
|
||||
final File favoritesFile = favouritesHelper.getExternalFile();
|
||||
AndroidNetworkUtils.uploadFilesAsync(UPLOAD_FILE_URL, new ArrayList<>(gpxInfos.keySet()), true, params, headers, new OnFilesUploadCallback() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Map<String, String> getAdditionalParams(@NonNull File file) {
|
||||
Map<String, String> additionaParams = new HashMap<>();
|
||||
GpxFileInfo gpxFileInfo = gpxInfos.get(file);
|
||||
if (gpxFileInfo != null) {
|
||||
additionaParams.put("name", gpxFileInfo.getFileName(true));
|
||||
additionaParams.put("type", Algorithms.getFileExtension(file));
|
||||
gpxFileInfo.uploadTime = System.currentTimeMillis();
|
||||
if (file.equals(favoritesFile)) {
|
||||
favouritesHelper.setLastUploadedTime(gpxFileInfo.uploadTime);
|
||||
} else {
|
||||
GpxDataItem gpxItem = gpxHelper.getItem(file);
|
||||
if (gpxItem != null) {
|
||||
gpxHelper.updateLastUploadedTime(gpxItem, gpxFileInfo.uploadTime);
|
||||
}
|
||||
}
|
||||
additionaParams.put("clienttime", String.valueOf(gpxFileInfo.uploadTime));
|
||||
}
|
||||
return additionaParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileUploadProgress(@NonNull File file, int progress) {
|
||||
if (listener != null) {
|
||||
listener.onFileUploadProgress(file, progress);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilesUploadDone(@NonNull Map<File, String> errors) {
|
||||
if (errors.isEmpty()) {
|
||||
settings.BACKUP_LAST_UPLOADED_TIME.set(System.currentTimeMillis() + 1);
|
||||
}
|
||||
if (listener != null) {
|
||||
listener.onFilesUploadDone(errors);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void deleteFiles(@NonNull List<UserFile> userFiles, @Nullable final OnDeleteFilesListener listener) throws UserNotRegisteredException {
|
||||
checkRegistered();
|
||||
|
||||
Map<String, String> commonParameters = new HashMap<>();
|
||||
commonParameters.put("deviceid", getDeviceId());
|
||||
commonParameters.put("accessToken", getAccessToken());
|
||||
|
||||
final List<Request> requests = new ArrayList<>();
|
||||
final Map<Request, UserFile> filesMap = new HashMap<>();
|
||||
for (UserFile userFile : userFiles) {
|
||||
Map<String, String> parameters = new HashMap<>(commonParameters);
|
||||
parameters.put("name", userFile.getName());
|
||||
parameters.put("type", userFile.getType());
|
||||
Request r = new Request(DELETE_FILE_URL, parameters, null, false, true);
|
||||
requests.add(r);
|
||||
filesMap.put(r, userFile);
|
||||
}
|
||||
AndroidNetworkUtils.sendRequestsAsync(null, requests, new OnSendRequestsListener() {
|
||||
@Override
|
||||
public void onRequestSent(@NonNull RequestResponse response) {
|
||||
if (listener != null) {
|
||||
UserFile userFile = filesMap.get(response.getRequest());
|
||||
if (userFile != null) {
|
||||
listener.onFileDeleteProgress(userFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestsSent(@NonNull List<RequestResponse> results) {
|
||||
if (listener != null) {
|
||||
Map<UserFile, String> errors = new HashMap<>();
|
||||
for (RequestResponse response : results) {
|
||||
UserFile userFile = filesMap.get(response.getRequest());
|
||||
if (userFile != null) {
|
||||
String responseStr = response.getResponse();
|
||||
boolean success;
|
||||
try {
|
||||
JSONObject json = new JSONObject(responseStr);
|
||||
String status = json.getString("status");
|
||||
success = status.equalsIgnoreCase("ok");
|
||||
} catch (JSONException e) {
|
||||
success = false;
|
||||
}
|
||||
if (!success) {
|
||||
errors.put(userFile, responseStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
listener.onFilesDeleteDone(errors);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void downloadFileList(@Nullable final OnDownloadFileListListener listener) throws UserNotRegisteredException {
|
||||
checkRegistered();
|
||||
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("deviceid", getDeviceId());
|
||||
params.put("accessToken", getAccessToken());
|
||||
AndroidNetworkUtils.sendRequestAsync(app, LIST_FILES_URL, params, "Download file list", true, false, new OnRequestResultListener() {
|
||||
@Override
|
||||
public void onResult(String resultJson) {
|
||||
int status;
|
||||
String message;
|
||||
List<UserFile> userFiles = new ArrayList<>();
|
||||
if (!Algorithms.isEmpty(resultJson)) {
|
||||
try {
|
||||
JSONObject result = new JSONObject(resultJson);
|
||||
String totalZipSize = result.getString("totalZipSize");
|
||||
String totalFiles = result.getString("totalFiles");
|
||||
String totalFileVersions = result.getString("totalFileVersions");
|
||||
JSONArray files = result.getJSONArray("uniqueFiles");
|
||||
for (int i = 0; i < files.length(); i++) {
|
||||
userFiles.add(new UserFile(files.getJSONObject(i)));
|
||||
}
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
message = "Total files: " + totalFiles + "\n" +
|
||||
"Total zip size: " + AndroidUtils.formatSize(app, Long.parseLong(totalZipSize)) + "\n" +
|
||||
"Total file versions: " + totalFileVersions;
|
||||
} catch (JSONException | ParseException e) {
|
||||
status = STATUS_PARSE_JSON_ERROR;
|
||||
message = "Download file list error: json parsing";
|
||||
}
|
||||
} else {
|
||||
status = STATUS_EMPTY_RESPONSE_ERROR;
|
||||
message = "Download file list error: empty response";
|
||||
}
|
||||
if (listener != null) {
|
||||
listener.onDownloadFileList(status, message, userFiles);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void downloadFiles(@NonNull final Map<File, UserFile> filesMap, @Nullable final OnDownloadFileListener listener) throws UserNotRegisteredException {
|
||||
checkRegistered();
|
||||
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("deviceid", getDeviceId());
|
||||
params.put("accessToken", getAccessToken());
|
||||
AndroidNetworkUtils.downloadFilesAsync(DOWNLOAD_FILE_URL,
|
||||
new ArrayList<>(filesMap.keySet()), params, new OnFilesDownloadCallback() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Map<String, String> getAdditionalParams(@NonNull File file) {
|
||||
UserFile userFile = filesMap.get(file);
|
||||
Map<String, String> additionaParams = new HashMap<>();
|
||||
additionaParams.put("name", userFile.getName());
|
||||
additionaParams.put("type", userFile.getType());
|
||||
return additionaParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileDownloadProgress(@NonNull File file, int percent) {
|
||||
if (listener != null) {
|
||||
listener.onFileDownloadProgress(filesMap.get(file), percent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileDownloadedAsync(@NonNull File file) {
|
||||
if (listener != null) {
|
||||
listener.onFileDownloadedAsync(file);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilesDownloadDone(@NonNull Map<File, String> errors) {
|
||||
if (listener != null) {
|
||||
listener.onFilesDownloadDone(errors);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
public void collectLocalFiles(@Nullable final OnCollectLocalFilesListener listener) {
|
||||
AsyncTask<Void, GpxFileInfo, List<GpxFileInfo>> task = new AsyncTask<Void, GpxFileInfo, List<GpxFileInfo>>() {
|
||||
|
||||
private final OnCollectLocalFilesListener internalListener = new OnCollectLocalFilesListener() {
|
||||
@Override
|
||||
public void onFileCollected(@NonNull GpxFileInfo fileInfo) {
|
||||
publishProgress(fileInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilesCollected(@NonNull List<GpxFileInfo> fileInfos) {
|
||||
}
|
||||
};
|
||||
|
||||
private void loadGPXData(@NonNull File mapPath, @NonNull List<GpxFileInfo> result,
|
||||
@Nullable OnCollectLocalFilesListener listener) {
|
||||
if (mapPath.canRead()) {
|
||||
loadGPXFolder(mapPath, result, "", listener);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadGPXFolder(@NonNull File mapPath, @NonNull List<GpxFileInfo> result,
|
||||
@NonNull String gpxSubfolder, @Nullable OnCollectLocalFilesListener listener) {
|
||||
File[] listFiles = mapPath.listFiles();
|
||||
if (listFiles != null) {
|
||||
for (File gpxFile : listFiles) {
|
||||
if (gpxFile.isDirectory()) {
|
||||
String sub = gpxSubfolder.length() == 0 ? gpxFile.getName() : gpxSubfolder + "/"
|
||||
+ gpxFile.getName();
|
||||
loadGPXFolder(gpxFile, result, sub, listener);
|
||||
} else if (gpxFile.isFile() && gpxFile.getName().toLowerCase().endsWith(IndexConstants.GPX_FILE_EXT)) {
|
||||
GpxFileInfo info = new GpxFileInfo();
|
||||
info.subfolder = gpxSubfolder;
|
||||
info.file = gpxFile;
|
||||
GpxDataItem gpxItem = gpxHelper.getItem(gpxFile);
|
||||
if (gpxItem != null) {
|
||||
info.uploadTime = gpxItem.getFileLastUploadedTime();
|
||||
}
|
||||
result.add(info);
|
||||
if (listener != null) {
|
||||
listener.onFileCollected(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<GpxFileInfo> doInBackground(Void... voids) {
|
||||
List<GpxFileInfo> result = new ArrayList<>();
|
||||
|
||||
GpxFileInfo favInfo = new GpxFileInfo();
|
||||
favInfo.subfolder = "";
|
||||
favInfo.file = favouritesHelper.getExternalFile();
|
||||
favInfo.uploadTime = favouritesHelper.getLastUploadedTime();
|
||||
result.add(favInfo);
|
||||
if (listener != null) {
|
||||
listener.onFileCollected(favInfo);
|
||||
}
|
||||
|
||||
loadGPXData(app.getAppPath(IndexConstants.GPX_INDEX_DIR), result, internalListener);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(GpxFileInfo... fileInfos) {
|
||||
if (listener != null) {
|
||||
listener.onFileCollected(fileInfos[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(List<GpxFileInfo> fileInfos) {
|
||||
if (listener != null) {
|
||||
listener.onFilesCollected(fileInfos);
|
||||
}
|
||||
}
|
||||
};
|
||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
public void generateBackupInfo(@NonNull final List<GpxFileInfo> localFiles, @NonNull final List<UserFile> remoteFiles,
|
||||
@Nullable final OnGenerateBackupInfoListener listener) {
|
||||
|
||||
final long backupLastUploadedTime = settings.BACKUP_LAST_UPLOADED_TIME.get();
|
||||
|
||||
AsyncTask<Void, Void, BackupInfo> task = new AsyncTask<Void, Void, BackupInfo>() {
|
||||
@Override
|
||||
protected BackupInfo doInBackground(Void... voids) {
|
||||
BackupInfo info = new BackupInfo();
|
||||
for (UserFile remoteFile : remoteFiles) {
|
||||
boolean hasLocalFile = false;
|
||||
for (GpxFileInfo localFile : localFiles) {
|
||||
if (remoteFile.getName().equals(localFile.getFileName(true))) {
|
||||
hasLocalFile = true;
|
||||
long remoteUploadTime = remoteFile.getClienttimems();
|
||||
long localUploadTime = localFile.uploadTime;
|
||||
long localModifiedTime = localFile.file.lastModified();
|
||||
if (remoteUploadTime == localUploadTime) {
|
||||
if (localUploadTime < localModifiedTime) {
|
||||
info.filesToUpload.add(localFile);
|
||||
}
|
||||
} else {
|
||||
info.filesToMerge.add(new Pair<>(localFile, remoteFile));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasLocalFile) {
|
||||
if (backupLastUploadedTime > 0 && backupLastUploadedTime >= remoteFile.getClienttimems()) {
|
||||
info.filesToDelete.add(remoteFile);
|
||||
} else {
|
||||
info.filesToDownload.add(remoteFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (GpxFileInfo localFile : localFiles) {
|
||||
boolean hasRemoteFile = false;
|
||||
for (UserFile remoteFile : remoteFiles) {
|
||||
if (localFile.getFileName(true).equals(remoteFile.getName())) {
|
||||
hasRemoteFile = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasRemoteFile) {
|
||||
info.filesToUpload.add(localFile);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(BackupInfo backupInfo) {
|
||||
if (listener != null) {
|
||||
listener.onBackupInfoGenerated(backupInfo, null);
|
||||
}
|
||||
}
|
||||
};
|
||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
}
|
335
OsmAnd/src/net/osmand/plus/backup/BackupTask.java
Normal file
335
OsmAnd/src/net/osmand/plus/backup/BackupTask.java
Normal file
|
@ -0,0 +1,335 @@
|
|||
package net.osmand.plus.backup;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.GPXUtilities;
|
||||
import net.osmand.GPXUtilities.GPXFile;
|
||||
import net.osmand.plus.GPXDatabase.GpxDataItem;
|
||||
import net.osmand.plus.GpxDbHelper;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.ProgressImplementation;
|
||||
import net.osmand.plus.backup.BackupHelper.BackupInfo;
|
||||
import net.osmand.plus.backup.BackupHelper.OnDeleteFilesListener;
|
||||
import net.osmand.plus.backup.BackupHelper.OnDownloadFileListener;
|
||||
import net.osmand.plus.backup.BackupHelper.OnUploadFilesListener;
|
||||
import net.osmand.plus.importfiles.FavoritesImportTask;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
import static net.osmand.IndexConstants.GPX_INDEX_DIR;
|
||||
import static net.osmand.IndexConstants.TEMP_DIR;
|
||||
|
||||
public class BackupTask {
|
||||
|
||||
private final OsmandApplication app;
|
||||
private final BackupHelper backupHelper;
|
||||
|
||||
private final OnBackupListener listener;
|
||||
private final WeakReference<Context> contextRef;
|
||||
private ProgressImplementation progress;
|
||||
|
||||
private final BackupInfo backupInfo;
|
||||
private Map<File, String> uploadErrors;
|
||||
private Map<File, String> downloadErrors;
|
||||
private Map<UserFile, String> deleteErrors;
|
||||
private String error;
|
||||
|
||||
private final TaskType[] backupTasks = {TaskType.UPLOAD_FILES, TaskType.DELETE_FILES};
|
||||
private final TaskType[] restoreTasks = {TaskType.DOWNLOAD_FILES};
|
||||
|
||||
private Stack<TaskType> runningTasks = new Stack<>();
|
||||
|
||||
private enum TaskType {
|
||||
UPLOAD_FILES,
|
||||
DOWNLOAD_FILES,
|
||||
DELETE_FILES
|
||||
}
|
||||
|
||||
public interface OnBackupListener {
|
||||
void onBackupDone(@Nullable Map<File, String> uploadErrors,
|
||||
@Nullable Map<File, String> downloadErrors,
|
||||
@Nullable Map<UserFile, String> deleteErrors, @Nullable String error);
|
||||
}
|
||||
|
||||
public BackupTask(@NonNull BackupInfo backupInfo, @NonNull Context context, @Nullable OnBackupListener listener) {
|
||||
this.contextRef = new WeakReference<>(context);
|
||||
this.app = (OsmandApplication) context.getApplicationContext();
|
||||
this.backupHelper = app.getBackupHelper();
|
||||
this.backupInfo = backupInfo;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public BackupInfo getBackupInfo() {
|
||||
return backupInfo;
|
||||
}
|
||||
|
||||
public Map<File, String> getUploadErrors() {
|
||||
return uploadErrors;
|
||||
}
|
||||
|
||||
public Map<File, String> getDownloadErrors() {
|
||||
return downloadErrors;
|
||||
}
|
||||
|
||||
public Map<UserFile, String> getDeleteErrors() {
|
||||
return deleteErrors;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public boolean runBackup() {
|
||||
if (!runningTasks.empty()) {
|
||||
return false;
|
||||
}
|
||||
initBackupTasks();
|
||||
return runTasks();
|
||||
}
|
||||
|
||||
public boolean runRestore() {
|
||||
if (!runningTasks.empty()) {
|
||||
return false;
|
||||
}
|
||||
initRestoreTasks();
|
||||
return runTasks();
|
||||
}
|
||||
|
||||
private void initBackupTasks() {
|
||||
initData();
|
||||
Stack<TaskType> tasks = new Stack<>();
|
||||
for (int i = backupTasks.length - 1; i >= 0; i--) {
|
||||
tasks.push(backupTasks[i]);
|
||||
}
|
||||
this.runningTasks = tasks;
|
||||
onTasksInit();
|
||||
}
|
||||
|
||||
private void initRestoreTasks() {
|
||||
initData();
|
||||
Stack<TaskType> tasks = new Stack<>();
|
||||
for (int i = restoreTasks.length - 1; i >= 0; i--) {
|
||||
tasks.push(restoreTasks[i]);
|
||||
}
|
||||
this.runningTasks = tasks;
|
||||
onTasksInit();
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
uploadErrors = null;
|
||||
downloadErrors = null;
|
||||
deleteErrors = null;
|
||||
error = null;
|
||||
}
|
||||
|
||||
private boolean runTasks() {
|
||||
if (runningTasks.empty()) {
|
||||
return false;
|
||||
} else {
|
||||
TaskType taskType = runningTasks.pop();
|
||||
runTask(taskType);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void runTask(@NonNull TaskType taskType) {
|
||||
switch (taskType) {
|
||||
case UPLOAD_FILES:
|
||||
doUploadFiles();
|
||||
break;
|
||||
case DOWNLOAD_FILES:
|
||||
doDownloadFiles();
|
||||
break;
|
||||
case DELETE_FILES:
|
||||
doDeleteFiles();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void onTaskFinished(@NonNull TaskType taskType) {
|
||||
if (!runTasks()) {
|
||||
onTasksDone();
|
||||
}
|
||||
}
|
||||
|
||||
private void doUploadFiles() {
|
||||
if (Algorithms.isEmpty(backupInfo.filesToUpload)) {
|
||||
onTaskFinished(TaskType.UPLOAD_FILES);
|
||||
return;
|
||||
}
|
||||
onTaskProgressUpdate("Upload files...");
|
||||
try {
|
||||
backupHelper.uploadFiles(backupInfo.filesToUpload, new OnUploadFilesListener() {
|
||||
@Override
|
||||
public void onFileUploadProgress(@NonNull File file, int progress) {
|
||||
if (progress == 0) {
|
||||
onTaskProgressUpdate(file.getName(), (int) (file.length() / 1024));
|
||||
} else {
|
||||
onTaskProgressUpdate(progress);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilesUploadDone(@NonNull Map<File, String> errors) {
|
||||
uploadErrors = errors;
|
||||
onTaskFinished(TaskType.UPLOAD_FILES);
|
||||
}
|
||||
});
|
||||
} catch (UserNotRegisteredException e) {
|
||||
onError("User is not registered");
|
||||
}
|
||||
}
|
||||
|
||||
private void doDownloadFiles() {
|
||||
if (Algorithms.isEmpty(backupInfo.filesToDownload)) {
|
||||
onTaskFinished(TaskType.DOWNLOAD_FILES);
|
||||
return;
|
||||
}
|
||||
onTaskProgressUpdate("Download files...");
|
||||
File favoritesFile = app.getFavorites().getExternalFile();
|
||||
String favoritesFileName = favoritesFile.getName();
|
||||
File tempFavoritesFile = null;
|
||||
final Map<File, UserFile> filesMap = new HashMap<>();
|
||||
for (UserFile userFile : backupInfo.filesToDownload) {
|
||||
File file;
|
||||
String fileName = userFile.getName();
|
||||
if (favoritesFileName.equals(fileName)) {
|
||||
file = new File(app.getAppPath(TEMP_DIR), fileName);
|
||||
tempFavoritesFile = file;
|
||||
} else {
|
||||
file = new File(app.getAppPath(GPX_INDEX_DIR), fileName);
|
||||
}
|
||||
filesMap.put(file, userFile);
|
||||
}
|
||||
final File finalTempFavoritesFile = tempFavoritesFile;
|
||||
try {
|
||||
backupHelper.downloadFiles(filesMap, new OnDownloadFileListener() {
|
||||
@Override
|
||||
public void onFileDownloadProgress(@NonNull UserFile userFile, int progress) {
|
||||
if (progress == 0) {
|
||||
onTaskProgressUpdate(new File(userFile.getName()).getName(), userFile.getFilesize() / 1024);
|
||||
} else {
|
||||
onTaskProgressUpdate(progress);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileDownloadedAsync(@NonNull File file) {
|
||||
UserFile userFile = filesMap.get(file);
|
||||
long userFileTime = userFile.getClienttimems();
|
||||
if (file.equals(finalTempFavoritesFile)) {
|
||||
GPXFile gpxFile = GPXUtilities.loadGPXFile(finalTempFavoritesFile);
|
||||
FavoritesImportTask.mergeFavorites(app, gpxFile, "", false);
|
||||
finalTempFavoritesFile.delete();
|
||||
app.getFavorites().getExternalFile().setLastModified(userFileTime);
|
||||
} else {
|
||||
file.setLastModified(userFileTime);
|
||||
GpxDataItem item = new GpxDataItem(file, userFileTime);
|
||||
app.getGpxDbHelper().add(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilesDownloadDone(@NonNull Map<File, String> errors) {
|
||||
downloadErrors = errors;
|
||||
onTaskFinished(TaskType.DOWNLOAD_FILES);
|
||||
}
|
||||
});
|
||||
} catch (UserNotRegisteredException e) {
|
||||
onError("User is not registered");
|
||||
}
|
||||
}
|
||||
|
||||
private void doDeleteFiles() {
|
||||
if (Algorithms.isEmpty(backupInfo.filesToDelete)) {
|
||||
onTaskFinished(TaskType.DELETE_FILES);
|
||||
return;
|
||||
}
|
||||
onTaskProgressUpdate("Delete files...");
|
||||
try {
|
||||
backupHelper.deleteFiles(backupInfo.filesToDelete, new OnDeleteFilesListener() {
|
||||
@Override
|
||||
public void onFileDeleteProgress(@NonNull UserFile userFile) {
|
||||
onTaskProgressUpdate(userFile.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilesDeleteDone(@NonNull Map<UserFile, String> errors) {
|
||||
deleteErrors = errors;
|
||||
onTaskFinished(TaskType.DELETE_FILES);
|
||||
}
|
||||
});
|
||||
} catch (UserNotRegisteredException e) {
|
||||
onError("User is not registered");
|
||||
}
|
||||
}
|
||||
|
||||
private void onTasksInit() {
|
||||
Context ctx = contextRef.get();
|
||||
if (ctx instanceof Activity && AndroidUtils.isActivityNotDestroyed((Activity) ctx) && progress != null) {
|
||||
progress = ProgressImplementation.createProgressDialog(ctx,
|
||||
"Backup data", "Initializing...", ProgressDialog.STYLE_HORIZONTAL);
|
||||
}
|
||||
}
|
||||
|
||||
private void onTaskProgressUpdate(Object... objects) {
|
||||
Context ctx = contextRef.get();
|
||||
if (ctx instanceof Activity && AndroidUtils.isActivityNotDestroyed((Activity) ctx) && progress != null) {
|
||||
if (objects != null) {
|
||||
if (objects.length == 1) {
|
||||
if (objects[0] instanceof String) {
|
||||
progress.startTask((String) objects[0], -1);
|
||||
} else if (objects[0] instanceof Integer) {
|
||||
int progressValue = (Integer) objects[0];
|
||||
if (progressValue < Integer.MAX_VALUE) {
|
||||
progress.progress(progressValue);
|
||||
} else {
|
||||
progress.finishTask();
|
||||
}
|
||||
}
|
||||
} else if (objects.length == 2) {
|
||||
progress.startTask((String) objects[0], (Integer) objects[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onError(@NonNull String message) {
|
||||
this.error = message;
|
||||
runningTasks.clear();
|
||||
onTasksDone();
|
||||
}
|
||||
|
||||
private void onTasksDone() {
|
||||
if (listener != null) {
|
||||
listener.onBackupDone(uploadErrors, downloadErrors, deleteErrors, error);
|
||||
}
|
||||
Context ctx = contextRef.get();
|
||||
if (ctx instanceof Activity && AndroidUtils.isActivityNotDestroyed((Activity) ctx) && progress != null) {
|
||||
progress.finishTask();
|
||||
app.runInUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (progress.getDialog().isShowing()) {
|
||||
progress.getDialog().dismiss();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//ignored
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
}
|
65
OsmAnd/src/net/osmand/plus/backup/GpxFileInfo.java
Normal file
65
OsmAnd/src/net/osmand/plus/backup/GpxFileInfo.java
Normal file
|
@ -0,0 +1,65 @@
|
|||
package net.osmand.plus.backup;
|
||||
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class GpxFileInfo {
|
||||
public File file;
|
||||
public String subfolder;
|
||||
public long uploadTime = 0;
|
||||
|
||||
private String name = null;
|
||||
private int sz = -1;
|
||||
private String fileName = null;
|
||||
|
||||
public String getName() {
|
||||
if (name == null) {
|
||||
name = formatName(file.getName());
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private String formatName(String name) {
|
||||
int ext = name.lastIndexOf('.');
|
||||
if (ext != -1) {
|
||||
name = name.substring(0, ext);
|
||||
}
|
||||
return name.replace('_', ' ');
|
||||
}
|
||||
|
||||
// Usage: AndroidUtils.formatSize(v.getContext(), getSize() * 1024l);
|
||||
public int getSize() {
|
||||
if (sz == -1) {
|
||||
if (file == null) {
|
||||
return -1;
|
||||
}
|
||||
sz = (int) ((file.length() + 512) >> 10);
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
public long getFileDate() {
|
||||
if (file == null) {
|
||||
return 0;
|
||||
}
|
||||
return file.lastModified();
|
||||
}
|
||||
|
||||
public String getFileName(boolean includeSubfolder) {
|
||||
String result;
|
||||
if (fileName != null) {
|
||||
result = fileName;
|
||||
} else {
|
||||
if (file == null) {
|
||||
result = "";
|
||||
} else {
|
||||
result = fileName = file.getName();
|
||||
}
|
||||
}
|
||||
if (includeSubfolder && !Algorithms.isEmpty(subfolder)) {
|
||||
result = subfolder + "/" + result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
211
OsmAnd/src/net/osmand/plus/backup/PrepareBackupTask.java
Normal file
211
OsmAnd/src/net/osmand/plus/backup/PrepareBackupTask.java
Normal file
|
@ -0,0 +1,211 @@
|
|||
package net.osmand.plus.backup;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.ProgressImplementation;
|
||||
import net.osmand.plus.backup.BackupHelper.BackupInfo;
|
||||
import net.osmand.plus.backup.BackupHelper.OnCollectLocalFilesListener;
|
||||
import net.osmand.plus.backup.BackupHelper.OnDownloadFileListListener;
|
||||
import net.osmand.plus.backup.BackupHelper.OnGenerateBackupInfoListener;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class PrepareBackupTask {
|
||||
|
||||
private final OsmandApplication app;
|
||||
private final BackupHelper backupHelper;
|
||||
|
||||
private final OnPrepareBackupListener listener;
|
||||
private final WeakReference<Context> contextRef;
|
||||
private ProgressImplementation progress;
|
||||
|
||||
private BackupInfo result;
|
||||
private List<UserFile> userFiles;
|
||||
private List<GpxFileInfo> fileInfos;
|
||||
private String error;
|
||||
|
||||
private Stack<TaskType> runningTasks = new Stack<>();
|
||||
|
||||
private enum TaskType {
|
||||
COLLECT_LOCAL_FILES,
|
||||
COLLECT_REMOTE_FILES,
|
||||
GENERATE_BACKUP_INFO
|
||||
}
|
||||
|
||||
public interface OnPrepareBackupListener {
|
||||
void onBackupPrepared(@Nullable BackupInfo backupInfo, @Nullable String error);
|
||||
}
|
||||
|
||||
public PrepareBackupTask(@NonNull Context context, @Nullable OnPrepareBackupListener listener) {
|
||||
this.contextRef = new WeakReference<>(context);
|
||||
this.app = (OsmandApplication) context.getApplicationContext();
|
||||
this.backupHelper = app.getBackupHelper();
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public BackupInfo getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public boolean prepare() {
|
||||
if (!runningTasks.empty()) {
|
||||
return false;
|
||||
}
|
||||
initTasks();
|
||||
return runTasks();
|
||||
}
|
||||
|
||||
private void initTasks() {
|
||||
result = null;
|
||||
userFiles = null;
|
||||
fileInfos = null;
|
||||
error = null;
|
||||
Stack<TaskType> tasks = new Stack<>();
|
||||
TaskType[] types = TaskType.values();
|
||||
for (int i = types.length - 1; i >= 0; i--) {
|
||||
tasks.push(types[i]);
|
||||
}
|
||||
this.runningTasks = tasks;
|
||||
onTasksInit();
|
||||
}
|
||||
|
||||
private boolean runTasks() {
|
||||
if (runningTasks.empty()) {
|
||||
return false;
|
||||
} else {
|
||||
TaskType taskType = runningTasks.pop();
|
||||
runTask(taskType);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void runTask(@NonNull TaskType taskType) {
|
||||
switch (taskType) {
|
||||
case COLLECT_LOCAL_FILES:
|
||||
doCollectLocalFiles();
|
||||
break;
|
||||
case COLLECT_REMOTE_FILES:
|
||||
doCollectRemoteFiles();
|
||||
break;
|
||||
case GENERATE_BACKUP_INFO:
|
||||
doGenerateBackupInfo();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void onTaskFinished(@NonNull TaskType taskType) {
|
||||
if (!runTasks()) {
|
||||
onTasksDone();
|
||||
}
|
||||
}
|
||||
|
||||
private void doCollectLocalFiles() {
|
||||
onTaskProgressUpdate("Collecting local info...");
|
||||
backupHelper.collectLocalFiles(new OnCollectLocalFilesListener() {
|
||||
@Override
|
||||
public void onFileCollected(@NonNull GpxFileInfo fileInfo) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilesCollected(@NonNull List<GpxFileInfo> fileInfos) {
|
||||
PrepareBackupTask.this.fileInfos = fileInfos;
|
||||
onTaskFinished(TaskType.COLLECT_LOCAL_FILES);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void doCollectRemoteFiles() {
|
||||
onTaskProgressUpdate("Downloading remote info...");
|
||||
try {
|
||||
backupHelper.downloadFileList(new OnDownloadFileListListener() {
|
||||
@Override
|
||||
public void onDownloadFileList(int status, @Nullable String message, @NonNull List<UserFile> userFiles) {
|
||||
if (status == BackupHelper.STATUS_SUCCESS) {
|
||||
PrepareBackupTask.this.userFiles = userFiles;
|
||||
} else {
|
||||
onError(!Algorithms.isEmpty(message) ? message : "Download file list error: " + status);
|
||||
}
|
||||
onTaskFinished(TaskType.COLLECT_REMOTE_FILES);
|
||||
}
|
||||
});
|
||||
} catch (UserNotRegisteredException e) {
|
||||
onError("User is not registered");
|
||||
}
|
||||
}
|
||||
|
||||
private void doGenerateBackupInfo() {
|
||||
if (fileInfos == null || userFiles == null) {
|
||||
onTaskFinished(TaskType.GENERATE_BACKUP_INFO);
|
||||
return;
|
||||
}
|
||||
onTaskProgressUpdate("Generating backup info...");
|
||||
backupHelper.generateBackupInfo(fileInfos, userFiles, new OnGenerateBackupInfoListener() {
|
||||
@Override
|
||||
public void onBackupInfoGenerated(@Nullable BackupInfo backupInfo, @Nullable String error) {
|
||||
if (Algorithms.isEmpty(error)) {
|
||||
PrepareBackupTask.this.result = backupInfo;
|
||||
} else {
|
||||
onError(error);
|
||||
}
|
||||
onTaskFinished(TaskType.GENERATE_BACKUP_INFO);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void onTasksInit() {
|
||||
Context ctx = contextRef.get();
|
||||
if (ctx instanceof Activity && AndroidUtils.isActivityNotDestroyed((Activity) ctx)) {
|
||||
progress = ProgressImplementation.createProgressDialog(ctx,
|
||||
"Prepare backup", "Initializing...", ProgressDialog.STYLE_HORIZONTAL);
|
||||
}
|
||||
}
|
||||
|
||||
private void onTaskProgressUpdate(String message) {
|
||||
Context ctx = contextRef.get();
|
||||
if (ctx instanceof Activity && AndroidUtils.isActivityNotDestroyed((Activity) ctx) && progress != null) {
|
||||
progress.startTask(message, -1);
|
||||
}
|
||||
}
|
||||
|
||||
private void onError(@NonNull String message) {
|
||||
this.error = message;
|
||||
runningTasks.clear();
|
||||
onTasksDone();
|
||||
}
|
||||
|
||||
private void onTasksDone() {
|
||||
if (listener != null) {
|
||||
listener.onBackupPrepared(result, error);
|
||||
}
|
||||
Context ctx = contextRef.get();
|
||||
if (ctx instanceof Activity && AndroidUtils.isActivityNotDestroyed((Activity) ctx) && progress != null) {
|
||||
progress.finishTask();
|
||||
app.runInUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (progress.getDialog().isShowing()) {
|
||||
progress.getDialog().dismiss();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//ignored
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
}
|
102
OsmAnd/src/net/osmand/plus/backup/UserFile.java
Normal file
102
OsmAnd/src/net/osmand/plus/backup/UserFile.java
Normal file
|
@ -0,0 +1,102 @@
|
|||
package net.osmand.plus.backup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
public class UserFile {
|
||||
|
||||
private int userid;
|
||||
private long id;
|
||||
private int deviceid;
|
||||
private int filesize;
|
||||
private String type;
|
||||
private String name;
|
||||
private Date updatetime;
|
||||
private long updatetimems;
|
||||
private Date clienttime;
|
||||
private long clienttimems;
|
||||
private int zipSize;
|
||||
|
||||
public UserFile(@NonNull JSONObject json) throws JSONException, ParseException {
|
||||
if (json.has("userid")) {
|
||||
userid = json.getInt("userid");
|
||||
}
|
||||
if (json.has("id")) {
|
||||
id = json.getLong("id");
|
||||
}
|
||||
if (json.has("deviceid")) {
|
||||
deviceid = json.getInt("deviceid");
|
||||
}
|
||||
if (json.has("filesize")) {
|
||||
filesize = json.getInt("filesize");
|
||||
}
|
||||
if (json.has("type")) {
|
||||
type = json.getString("type");
|
||||
}
|
||||
if (json.has("name")) {
|
||||
name = json.getString("name");
|
||||
}
|
||||
if (json.has("updatetimems")) {
|
||||
updatetimems = json.getLong("updatetimems");
|
||||
updatetime = new Date(updatetimems);
|
||||
}
|
||||
if (json.has("clienttimems")) {
|
||||
clienttimems = json.getLong("clienttimems");
|
||||
clienttime = new Date(clienttimems);
|
||||
}
|
||||
if (json.has("zipSize")) {
|
||||
zipSize = json.getInt("zipSize");
|
||||
}
|
||||
}
|
||||
|
||||
public int getUserid() {
|
||||
return userid;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getDeviceid() {
|
||||
return deviceid;
|
||||
}
|
||||
|
||||
public int getFilesize() {
|
||||
return filesize;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Date getUpdatetime() {
|
||||
return updatetime;
|
||||
}
|
||||
|
||||
public long getUpdatetimems() {
|
||||
return updatetimems;
|
||||
}
|
||||
|
||||
public Date getClienttime() {
|
||||
return clienttime;
|
||||
}
|
||||
|
||||
public long getClienttimems() {
|
||||
return clienttimems;
|
||||
}
|
||||
|
||||
public int getZipSize() {
|
||||
return zipSize;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package net.osmand.plus.backup;
|
||||
|
||||
public class UserNotRegisteredException extends Exception {
|
||||
private static final long serialVersionUID = -8005954380280822845L;
|
||||
|
||||
public UserNotRegisteredException() {
|
||||
super("User is not resistered");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package net.osmand.plus.base;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.widgets.multistatetoggle.RadioItem;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ModeSelectionBottomSheet extends SelectionBottomSheet {
|
||||
|
||||
public static final String TAG = ModeSelectionBottomSheet.class.getSimpleName();
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
showElements(primaryDescription, toggleContainer);
|
||||
hideElements(checkBox, checkBoxTitle, titleDescription,
|
||||
secondaryDescription, selectedSize, selectAllButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateItemView(SelectableItem item, View view) {
|
||||
ImageView ivIcon = view.findViewById(R.id.icon);
|
||||
TextView tvTitle = view.findViewById(R.id.title);
|
||||
TextView tvDescr = view.findViewById(R.id.description);
|
||||
|
||||
Drawable icon = uiUtilities.getIcon(item.getIconId(), activeColorRes);
|
||||
ivIcon.setImageDrawable(icon);
|
||||
tvTitle.setText(item.getTitle());
|
||||
tvDescr.setText(item.getDescription());
|
||||
tvDescr.setTextColor(ContextCompat.getColor(app, AndroidUtils.getSecondaryTextColorId(nightMode)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getItemLayoutId() {
|
||||
return R.layout.bottom_sheet_item_with_descr_56dp;
|
||||
}
|
||||
|
||||
public void setItem(SelectableItem item) {
|
||||
setItems(Collections.singletonList(item));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public List<SelectableItem> getSelectedItems() {
|
||||
return allItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldShowDivider() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static ModeSelectionBottomSheet showInstance(@NonNull AppCompatActivity activity,
|
||||
@NonNull SelectableItem previewItem,
|
||||
@NonNull List<RadioItem> radioItems,
|
||||
boolean usedOnMap) {
|
||||
ModeSelectionBottomSheet fragment = new ModeSelectionBottomSheet();
|
||||
fragment.setUsedOnMap(usedOnMap);
|
||||
fragment.setModes(radioItems);
|
||||
fragment.setItems(Collections.singletonList(previewItem));
|
||||
FragmentManager fm = activity.getSupportFragmentManager();
|
||||
fragment.show(fm, TAG);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
package net.osmand.plus.base;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.widget.CompoundButtonCompat;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.helpers.AndroidUiHelper;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static net.osmand.view.ThreeStateCheckbox.State.CHECKED;
|
||||
import static net.osmand.view.ThreeStateCheckbox.State.MISC;
|
||||
import static net.osmand.view.ThreeStateCheckbox.State.UNCHECKED;
|
||||
|
||||
public class MultipleSelectionBottomSheet extends SelectionBottomSheet {
|
||||
|
||||
public static final String TAG = MultipleSelectionBottomSheet.class.getSimpleName();
|
||||
|
||||
private final List<SelectableItem> selectedItems = new ArrayList<>();
|
||||
private SelectionUpdateListener selectionUpdateListener;
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
selectAllButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
checkBox.performClick();
|
||||
boolean checked = checkBox.getState() == CHECKED;
|
||||
if (checked) {
|
||||
selectedItems.addAll(allItems);
|
||||
} else {
|
||||
selectedItems.clear();
|
||||
}
|
||||
onSelectedItemsChanged();
|
||||
updateItemsSelection(checked);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldShowDivider() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateItemView(final SelectableItem item, View view) {
|
||||
boolean checked = selectedItems.contains(item);
|
||||
ImageView imageView = view.findViewById(R.id.icon);
|
||||
TextView title = view.findViewById(R.id.title);
|
||||
TextView description = view.findViewById(R.id.description);
|
||||
final CheckBox checkBox = view.findViewById(R.id.compound_button);
|
||||
AndroidUiHelper.setVisibility(View.VISIBLE, imageView, title, description, checkBox);
|
||||
|
||||
checkBox.setChecked(checked);
|
||||
CompoundButtonCompat.setButtonTintList(checkBox, AndroidUtils.createCheckedColorStateList(app, secondaryColorRes, activeColorRes));
|
||||
|
||||
view.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
boolean checked = !checkBox.isChecked();
|
||||
checkBox.setChecked(checked);
|
||||
if (checked) {
|
||||
selectedItems.add(item);
|
||||
} else {
|
||||
selectedItems.remove(item);
|
||||
}
|
||||
onSelectedItemsChanged();
|
||||
}
|
||||
});
|
||||
title.setText(item.getTitle());
|
||||
description.setText(item.getDescription());
|
||||
imageView.setImageDrawable(uiUtilities.getIcon(item.getIconId(), activeColorRes));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getItemLayoutId() {
|
||||
return R.layout.bottom_sheet_item_with_descr_and_checkbox_56dp;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyUiCreated() {
|
||||
onSelectedItemsChanged();
|
||||
super.notifyUiCreated();
|
||||
}
|
||||
|
||||
private void onSelectedItemsChanged() {
|
||||
updateSelectAllButton();
|
||||
updateSelectedSizeView();
|
||||
updateApplyButtonEnable();
|
||||
if (selectionUpdateListener != null) {
|
||||
selectionUpdateListener.onSelectionUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSelectAllButton() {
|
||||
String checkBoxTitle;
|
||||
if (Algorithms.isEmpty(selectedItems)) {
|
||||
checkBox.setState(UNCHECKED);
|
||||
checkBoxTitle = getString(R.string.shared_string_select_all);
|
||||
} else {
|
||||
checkBox.setState(selectedItems.containsAll(allItems) ? CHECKED : MISC);
|
||||
checkBoxTitle = getString(R.string.shared_string_deselect_all);
|
||||
}
|
||||
int checkBoxColor = checkBox.getState() == UNCHECKED ? secondaryColorRes : activeColorRes;
|
||||
CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, checkBoxColor)));
|
||||
this.checkBoxTitle.setText(checkBoxTitle);
|
||||
}
|
||||
|
||||
private void updateSelectedSizeView() {
|
||||
String selected = String.valueOf(selectedItems.size());
|
||||
String all = String.valueOf(allItems.size());
|
||||
selectedSize.setText(getString(R.string.ltr_or_rtl_combine_via_slash, selected, all));
|
||||
}
|
||||
|
||||
private void updateApplyButtonEnable() {
|
||||
boolean noEmptySelection = !Algorithms.isEmpty(selectedItems);
|
||||
rightButton.setEnabled(noEmptySelection);
|
||||
}
|
||||
|
||||
private void updateItemsSelection(boolean checked) {
|
||||
for (SelectableItem item : allItems) {
|
||||
View v = listViews.get(item);
|
||||
CheckBox checkBox = v != null ? (CheckBox) v.findViewById(R.id.compound_button) : null;
|
||||
if (checkBox != null) {
|
||||
checkBox.setChecked(checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void setSelectedItems(List<SelectableItem> selected) {
|
||||
selectedItems.clear();
|
||||
if (!Algorithms.isEmpty(selected)) {
|
||||
selectedItems.addAll(selected);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public List<SelectableItem> getSelectedItems() {
|
||||
return selectedItems;
|
||||
}
|
||||
|
||||
public void setSelectionUpdateListener(SelectionUpdateListener selectionUpdateListener) {
|
||||
this.selectionUpdateListener = selectionUpdateListener;
|
||||
}
|
||||
|
||||
public static MultipleSelectionBottomSheet showInstance(@NonNull AppCompatActivity activity,
|
||||
@NonNull List<SelectableItem> items,
|
||||
@Nullable List<SelectableItem> selected,
|
||||
boolean usedOnMap) {
|
||||
MultipleSelectionBottomSheet fragment = new MultipleSelectionBottomSheet();
|
||||
fragment.setUsedOnMap(usedOnMap);
|
||||
fragment.setItems(items);
|
||||
fragment.setSelectedItems(selected);
|
||||
FragmentManager fm = activity.getSupportFragmentManager();
|
||||
fragment.show(fm, TAG);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
public interface SelectionUpdateListener {
|
||||
void onSelectionUpdate();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package net.osmand.plus.base;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import net.osmand.plus.widgets.multistatetoggle.RadioItem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MultipleSelectionWithModeBottomSheet extends MultipleSelectionBottomSheet {
|
||||
|
||||
public static final String TAG = MultipleSelectionWithModeBottomSheet.class.getSimpleName();
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
showElements(secondaryDescription, toggleContainer, checkBox,
|
||||
checkBoxTitle, titleDescription, selectedSize, selectAllButton);
|
||||
}
|
||||
|
||||
public static MultipleSelectionWithModeBottomSheet showInstance(@NonNull AppCompatActivity activity,
|
||||
@NonNull List<SelectableItem> items,
|
||||
@Nullable List<SelectableItem> selected,
|
||||
@NonNull List<RadioItem> modes,
|
||||
boolean usedOnMap) {
|
||||
MultipleSelectionWithModeBottomSheet fragment = new MultipleSelectionWithModeBottomSheet();
|
||||
fragment.setUsedOnMap(usedOnMap);
|
||||
fragment.setItems(items);
|
||||
fragment.setSelectedItems(selected);
|
||||
fragment.setModes(modes);
|
||||
FragmentManager fm = activity.getSupportFragmentManager();
|
||||
fragment.show(fm, TAG);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,301 +0,0 @@
|
|||
package net.osmand.plus.base;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.widget.CompoundButtonCompat;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.UiUtilities;
|
||||
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
|
||||
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithCompoundButton;
|
||||
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithCompoundButton.Builder;
|
||||
import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
|
||||
import net.osmand.plus.base.bottomsheetmenu.simpleitems.SimpleDividerItem;
|
||||
import net.osmand.util.Algorithms;
|
||||
import net.osmand.view.ThreeStateCheckbox;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static net.osmand.view.ThreeStateCheckbox.State.CHECKED;
|
||||
import static net.osmand.view.ThreeStateCheckbox.State.MISC;
|
||||
import static net.osmand.view.ThreeStateCheckbox.State.UNCHECKED;
|
||||
|
||||
public class SelectMultipleItemsBottomSheet extends MenuBottomSheetDialogFragment {
|
||||
|
||||
private OsmandApplication app;
|
||||
private UiUtilities uiUtilities;
|
||||
|
||||
private TextView title;
|
||||
private TextView description;
|
||||
private TextView applyButtonTitle;
|
||||
private TextView checkBoxTitle;
|
||||
private TextView selectedSize;
|
||||
private ThreeStateCheckbox checkBox;
|
||||
|
||||
private int activeColorRes;
|
||||
private int secondaryColorRes;
|
||||
|
||||
private final List<SelectableItem> allItems = new ArrayList<>();
|
||||
private final List<SelectableItem> selectedItems = new ArrayList<>();
|
||||
private SelectionUpdateListener selectionUpdateListener;
|
||||
private OnApplySelectionListener onApplySelectionListener;
|
||||
|
||||
public static final String TAG = SelectMultipleItemsBottomSheet.class.getSimpleName();
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
|
||||
View mainView = super.onCreateView(inflater, parent, savedInstanceState);
|
||||
onSelectedItemsChanged();
|
||||
return mainView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createMenuItems(Bundle savedInstanceState) {
|
||||
app = requiredMyApplication();
|
||||
uiUtilities = app.getUIUtilities();
|
||||
activeColorRes = nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light;
|
||||
secondaryColorRes = nightMode ? R.color.icon_color_secondary_dark : R.color.icon_color_secondary_light;
|
||||
|
||||
items.add(createTitleItem());
|
||||
items.add(new SimpleDividerItem(app));
|
||||
createListItems();
|
||||
}
|
||||
|
||||
private BaseBottomSheetItem createTitleItem() {
|
||||
LayoutInflater themedInflater = UiUtilities.getInflater(requireContext(), nightMode);
|
||||
View view = themedInflater.inflate(R.layout.settings_group_title, null);
|
||||
|
||||
checkBox = view.findViewById(R.id.check_box);
|
||||
checkBoxTitle = view.findViewById(R.id.check_box_title);
|
||||
description = view.findViewById(R.id.description);
|
||||
selectedSize = view.findViewById(R.id.selected_size);
|
||||
title = view.findViewById(R.id.title);
|
||||
View selectAllButton = view.findViewById(R.id.select_all_button);
|
||||
selectAllButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
checkBox.performClick();
|
||||
boolean checked = checkBox.getState() == CHECKED;
|
||||
if (checked) {
|
||||
selectedItems.addAll(allItems);
|
||||
} else {
|
||||
selectedItems.clear();
|
||||
}
|
||||
onSelectedItemsChanged();
|
||||
updateItems(checked);
|
||||
}
|
||||
});
|
||||
return new SimpleBottomSheetItem.Builder().setCustomView(view).create();
|
||||
}
|
||||
|
||||
private void createListItems() {
|
||||
for (final SelectableItem item : allItems) {
|
||||
boolean checked = selectedItems.contains(item);
|
||||
final BottomSheetItemWithCompoundButton[] uiItem = new BottomSheetItemWithCompoundButton[1];
|
||||
final Builder builder = (BottomSheetItemWithCompoundButton.Builder) new Builder();
|
||||
builder.setChecked(checked)
|
||||
.setButtonTintList(AndroidUtils.createCheckedColorStateList(app, secondaryColorRes, activeColorRes))
|
||||
.setLayoutId(R.layout.bottom_sheet_item_with_descr_and_checkbox_56dp)
|
||||
.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
boolean checked = !uiItem[0].isChecked();
|
||||
uiItem[0].setChecked(checked);
|
||||
SelectableItem tag = (SelectableItem) uiItem[0].getTag();
|
||||
if (checked) {
|
||||
selectedItems.add(tag);
|
||||
} else {
|
||||
selectedItems.remove(tag);
|
||||
}
|
||||
onSelectedItemsChanged();
|
||||
}
|
||||
})
|
||||
.setTag(item);
|
||||
setupListItem(builder, item);
|
||||
uiItem[0] = builder.create();
|
||||
items.add(uiItem[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupRightButton() {
|
||||
super.setupRightButton();
|
||||
applyButtonTitle = rightButton.findViewById(R.id.button_text);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRightBottomButtonClick() {
|
||||
if (onApplySelectionListener != null) {
|
||||
onApplySelectionListener.onSelectionApplied(selectedItems);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
|
||||
private void onSelectedItemsChanged() {
|
||||
updateSelectAllButton();
|
||||
updateSelectedSizeView();
|
||||
updateApplyButtonEnable();
|
||||
if (selectionUpdateListener != null) {
|
||||
selectionUpdateListener.onSelectionUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getRightBottomButtonTextId() {
|
||||
return R.string.shared_string_apply;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean useVerticalButtons() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void setupListItem(Builder builder, SelectableItem item) {
|
||||
builder.setTitle(item.title);
|
||||
builder.setDescription(item.description);
|
||||
builder.setIcon(uiUtilities.getIcon(item.iconId, activeColorRes));
|
||||
}
|
||||
|
||||
private void updateSelectAllButton() {
|
||||
String checkBoxTitle;
|
||||
if (Algorithms.isEmpty(selectedItems)) {
|
||||
checkBox.setState(UNCHECKED);
|
||||
checkBoxTitle = getString(R.string.shared_string_select_all);
|
||||
} else {
|
||||
checkBox.setState(selectedItems.containsAll(allItems) ? CHECKED : MISC);
|
||||
checkBoxTitle = getString(R.string.shared_string_deselect_all);
|
||||
}
|
||||
int checkBoxColor = checkBox.getState() == UNCHECKED ? secondaryColorRes : activeColorRes;
|
||||
CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, checkBoxColor)));
|
||||
this.checkBoxTitle.setText(checkBoxTitle);
|
||||
}
|
||||
|
||||
private void updateSelectedSizeView() {
|
||||
String selected = String.valueOf(selectedItems.size());
|
||||
String all = String.valueOf(allItems.size());
|
||||
selectedSize.setText(getString(R.string.ltr_or_rtl_combine_via_slash, selected, all));
|
||||
}
|
||||
|
||||
private void updateApplyButtonEnable() {
|
||||
if (Algorithms.isEmpty(selectedItems)) {
|
||||
rightButton.setEnabled(false);
|
||||
} else {
|
||||
rightButton.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateItems(boolean checked) {
|
||||
for (BaseBottomSheetItem item : items) {
|
||||
if (item instanceof BottomSheetItemWithCompoundButton) {
|
||||
((BottomSheetItemWithCompoundButton) item).setChecked(checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setTitle(@NonNull String title) {
|
||||
this.title.setText(title);
|
||||
}
|
||||
|
||||
public void setDescription(@NonNull String description) {
|
||||
this.description.setText(description);
|
||||
}
|
||||
|
||||
public void setConfirmButtonTitle(@NonNull String confirmButtonTitle) {
|
||||
applyButtonTitle.setText(confirmButtonTitle);
|
||||
}
|
||||
|
||||
private void setItems(List<SelectableItem> allItems) {
|
||||
if (!Algorithms.isEmpty(allItems)) {
|
||||
this.allItems.addAll(allItems);
|
||||
}
|
||||
}
|
||||
|
||||
private void setSelectedItems(List<SelectableItem> selected) {
|
||||
if (!Algorithms.isEmpty(selected)) {
|
||||
this.selectedItems.addAll(selected);
|
||||
}
|
||||
}
|
||||
|
||||
public List<SelectableItem> getSelectedItems() {
|
||||
return selectedItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
if (requireActivity().isChangingConfigurations()) {
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
public static SelectMultipleItemsBottomSheet showInstance(@NonNull AppCompatActivity activity,
|
||||
@NonNull List<SelectableItem> items,
|
||||
@Nullable List<SelectableItem> selected,
|
||||
boolean usedOnMap) {
|
||||
SelectMultipleItemsBottomSheet fragment = new SelectMultipleItemsBottomSheet();
|
||||
fragment.setUsedOnMap(usedOnMap);
|
||||
fragment.setItems(items);
|
||||
fragment.setSelectedItems(selected);
|
||||
FragmentManager fm = activity.getSupportFragmentManager();
|
||||
fragment.show(fm, TAG);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
public void setSelectionUpdateListener(SelectionUpdateListener selectionUpdateListener) {
|
||||
this.selectionUpdateListener = selectionUpdateListener;
|
||||
}
|
||||
|
||||
public void setOnApplySelectionListener(OnApplySelectionListener onApplySelectionListener) {
|
||||
this.onApplySelectionListener = onApplySelectionListener;
|
||||
}
|
||||
|
||||
public interface SelectionUpdateListener {
|
||||
void onSelectionUpdate();
|
||||
}
|
||||
|
||||
public interface OnApplySelectionListener {
|
||||
void onSelectionApplied(List<SelectableItem> selectedItems);
|
||||
}
|
||||
|
||||
public static class SelectableItem {
|
||||
private String title;
|
||||
private String description;
|
||||
private int iconId;
|
||||
private Object object;
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public void setIconId(int iconId) {
|
||||
this.iconId = iconId;
|
||||
}
|
||||
|
||||
public void setObject(Object object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
public Object getObject() {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
299
OsmAnd/src/net/osmand/plus/base/SelectionBottomSheet.java
Normal file
299
OsmAnd/src/net/osmand/plus/base/SelectionBottomSheet.java
Normal file
|
@ -0,0 +1,299 @@
|
|||
package net.osmand.plus.base;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.LinearLayout.LayoutParams;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.UiUtilities;
|
||||
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
|
||||
import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
|
||||
import net.osmand.plus.base.bottomsheetmenu.simpleitems.SimpleDividerItem;
|
||||
import net.osmand.plus.helpers.AndroidUiHelper;
|
||||
import net.osmand.plus.widgets.multistatetoggle.MultiStateToggleButton;
|
||||
import net.osmand.plus.widgets.multistatetoggle.RadioItem;
|
||||
import net.osmand.plus.widgets.multistatetoggle.TextToggleButton;
|
||||
import net.osmand.util.Algorithms;
|
||||
import net.osmand.view.ThreeStateCheckbox;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class SelectionBottomSheet extends MenuBottomSheetDialogFragment {
|
||||
|
||||
protected OsmandApplication app;
|
||||
protected LayoutInflater inflater;
|
||||
protected UiUtilities uiUtilities;
|
||||
|
||||
protected TextView title;
|
||||
protected TextView titleDescription;
|
||||
protected TextView primaryDescription;
|
||||
protected TextView secondaryDescription;
|
||||
protected TextView selectedSize;
|
||||
protected LinearLayout toggleContainer;
|
||||
protected MultiStateToggleButton radioGroup;
|
||||
protected View selectAllButton;
|
||||
protected TextView checkBoxTitle;
|
||||
protected ThreeStateCheckbox checkBox;
|
||||
protected LinearLayout listContainer;
|
||||
protected TextView applyButtonTitle;
|
||||
|
||||
protected int activeColorRes;
|
||||
protected int secondaryColorRes;
|
||||
|
||||
private DialogStateListener dialogStateListener;
|
||||
private OnApplySelectionListener onApplySelectionListener;
|
||||
|
||||
protected List<SelectableItem> allItems = new ArrayList<>();
|
||||
protected Map<SelectableItem, View> listViews = new HashMap<>();
|
||||
private List<RadioItem> modes;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
|
||||
View mainView = super.onCreateView(inflater, parent, savedInstanceState);
|
||||
createSelectionListIfPossible();
|
||||
notifyUiCreated();
|
||||
return mainView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createMenuItems(Bundle savedInstanceState) {
|
||||
app = requiredMyApplication();
|
||||
uiUtilities = app.getUIUtilities();
|
||||
inflater = UiUtilities.getInflater(requireContext(), nightMode);
|
||||
activeColorRes = nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light;
|
||||
secondaryColorRes = nightMode ? R.color.icon_color_secondary_dark : R.color.icon_color_secondary_light;
|
||||
|
||||
items.add(createHeaderView());
|
||||
if (shouldShowDivider()) {
|
||||
items.add(new SimpleDividerItem(app));
|
||||
}
|
||||
items.add(createSelectionView());
|
||||
}
|
||||
|
||||
private BaseBottomSheetItem createHeaderView() {
|
||||
View view = inflater.inflate(R.layout.settings_group_title, null);
|
||||
|
||||
title = view.findViewById(R.id.title);
|
||||
titleDescription = view.findViewById(R.id.title_description);
|
||||
primaryDescription = view.findViewById(R.id.primary_description);
|
||||
secondaryDescription = view.findViewById(R.id.secondary_description);
|
||||
selectedSize = view.findViewById(R.id.selected_size);
|
||||
toggleContainer = view.findViewById(R.id.custom_radio_buttons);
|
||||
radioGroup = new TextToggleButton(app, toggleContainer, nightMode);
|
||||
selectAllButton = view.findViewById(R.id.select_all_button);
|
||||
checkBoxTitle = view.findViewById(R.id.check_box_title);
|
||||
checkBox = view.findViewById(R.id.check_box);
|
||||
|
||||
if (modes != null) {
|
||||
radioGroup.setItems(modes);
|
||||
}
|
||||
|
||||
return new SimpleBottomSheetItem.Builder().setCustomView(view).create();
|
||||
}
|
||||
|
||||
private BaseBottomSheetItem createSelectionView() {
|
||||
Context themedCtx = UiUtilities.getThemedContext(requireContext(), nightMode);
|
||||
listContainer = new LinearLayout(themedCtx);
|
||||
listContainer.setLayoutParams(new LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
listContainer.setOrientation(LinearLayout.VERTICAL);
|
||||
return new SimpleBottomSheetItem.Builder().setCustomView(listContainer).create();
|
||||
}
|
||||
|
||||
public void setTitle(@NonNull String title) {
|
||||
this.title.setText(title);
|
||||
}
|
||||
|
||||
public void setTitleDescription(@NonNull String description) {
|
||||
titleDescription.setText(description);
|
||||
}
|
||||
|
||||
public void setPrimaryDescription(@NonNull String description) {
|
||||
primaryDescription.setText(description);
|
||||
}
|
||||
|
||||
public void setSecondaryDescription(@NonNull String description) {
|
||||
secondaryDescription.setText(description);
|
||||
}
|
||||
|
||||
public void setApplyButtonTitle(@NonNull String title) {
|
||||
applyButtonTitle.setText(title);
|
||||
}
|
||||
|
||||
public void setModes(@NonNull List<RadioItem> modes) {
|
||||
this.modes = modes;
|
||||
if (radioGroup != null) {
|
||||
radioGroup.setItems(modes);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSelectedMode(@NonNull RadioItem mode) {
|
||||
radioGroup.setSelectedItem(mode);
|
||||
}
|
||||
|
||||
public void setItems(List<SelectableItem> allItems) {
|
||||
this.allItems.clear();
|
||||
if (!Algorithms.isEmpty(allItems)) {
|
||||
this.allItems.addAll(allItems);
|
||||
createSelectionListIfPossible();
|
||||
}
|
||||
}
|
||||
|
||||
public void setDialogStateListener(DialogStateListener dialogStateListener) {
|
||||
this.dialogStateListener = dialogStateListener;
|
||||
}
|
||||
|
||||
public void setOnApplySelectionListener(OnApplySelectionListener onApplySelectionListener) {
|
||||
this.onApplySelectionListener = onApplySelectionListener;
|
||||
}
|
||||
|
||||
private void createSelectionListIfPossible() {
|
||||
if (listContainer != null && allItems != null) {
|
||||
recreateList();
|
||||
}
|
||||
}
|
||||
|
||||
private void recreateList() {
|
||||
listViews.clear();
|
||||
listContainer.removeAllViews();
|
||||
for (SelectableItem item : allItems) {
|
||||
setupItemView(item, inflater.inflate(getItemLayoutId(), null));
|
||||
}
|
||||
}
|
||||
|
||||
private void setupItemView(SelectableItem item, View view) {
|
||||
updateItemView(item, view);
|
||||
listViews.put(item, view);
|
||||
listContainer.addView(view);
|
||||
}
|
||||
|
||||
public List<SelectableItem> getAllItems() {
|
||||
return allItems;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public abstract List<SelectableItem> getSelectedItems();
|
||||
|
||||
protected abstract void updateItemView(SelectableItem item, View view);
|
||||
|
||||
protected abstract int getItemLayoutId();
|
||||
|
||||
protected abstract boolean shouldShowDivider();
|
||||
|
||||
protected void notifyUiCreated() {
|
||||
if (dialogStateListener != null) {
|
||||
dialogStateListener.onDialogCreated();
|
||||
}
|
||||
}
|
||||
|
||||
protected void showElements(View... views) {
|
||||
AndroidUiHelper.setVisibility(View.VISIBLE, views);
|
||||
}
|
||||
|
||||
protected void hideElements(View... views) {
|
||||
AndroidUiHelper.setVisibility(View.GONE, views);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupRightButton() {
|
||||
super.setupRightButton();
|
||||
applyButtonTitle = rightButton.findViewById(R.id.button_text);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRightBottomButtonClick() {
|
||||
if (onApplySelectionListener != null) {
|
||||
onApplySelectionListener.onSelectionApplied(getSelectedItems());
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getRightBottomButtonTextId() {
|
||||
return R.string.shared_string_apply;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean useVerticalButtons() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
if (requireActivity().isChangingConfigurations()) {
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (dialogStateListener != null) {
|
||||
dialogStateListener.onCloseDialog();
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
public interface DialogStateListener {
|
||||
void onDialogCreated();
|
||||
void onCloseDialog();
|
||||
}
|
||||
|
||||
public interface OnApplySelectionListener {
|
||||
void onSelectionApplied(List<SelectableItem> selectedItems);
|
||||
}
|
||||
|
||||
public static class SelectableItem {
|
||||
private String title;
|
||||
private String description;
|
||||
private int iconId;
|
||||
private Object object;
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public int getIconId() {
|
||||
return iconId;
|
||||
}
|
||||
|
||||
public Object getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public void setIconId(int iconId) {
|
||||
this.iconId = iconId;
|
||||
}
|
||||
|
||||
public void setObject(Object object) {
|
||||
this.object = object;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -32,6 +32,10 @@ public class BaseBottomSheetItem {
|
|||
return tag;
|
||||
}
|
||||
|
||||
public void setTag(Object tag) {
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
public BaseBottomSheetItem(View view,
|
||||
@LayoutRes int layoutId,
|
||||
Object tag,
|
||||
|
|
|
@ -11,7 +11,6 @@ import android.content.DialogInterface;
|
|||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.StatFs;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
|
@ -34,10 +33,10 @@ import net.osmand.FileUtils;
|
|||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.ValueHolder;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.ProgressImplementation;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.download.DownloadActivity;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
@ -93,18 +92,6 @@ public class DashChooseAppDirFragment {
|
|||
selectePathTemp = null;
|
||||
}
|
||||
|
||||
private String getFreeSpace(File dir) {
|
||||
if (dir.canRead()) {
|
||||
try {
|
||||
StatFs fs = new StatFs(dir.getAbsolutePath());
|
||||
return AndroidUtils.formatSize(activity, (long) fs.getAvailableBlocks() * fs.getBlockSize());
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public void updateView() {
|
||||
if (type == OsmandSettings.EXTERNAL_STORAGE_TYPE_INTERNAL_FILE) {
|
||||
locationPath.setText(R.string.storage_directory_internal_app);
|
||||
|
@ -117,7 +104,7 @@ public class DashChooseAppDirFragment {
|
|||
} else if (type == OsmandSettings.EXTERNAL_STORAGE_TYPE_SPECIFIED) {
|
||||
locationPath.setText(R.string.storage_directory_manual);
|
||||
}
|
||||
locationDesc.setText(selectedFile.getAbsolutePath() + " \u2022 " + getFreeSpace(selectedFile));
|
||||
locationDesc.setText(selectedFile.getAbsolutePath() + " \u2022 " + AndroidUtils.getFreeSpace(activity, selectedFile));
|
||||
boolean copyFiles = !currentAppFile.getAbsolutePath().equals(selectedFile.getAbsolutePath()) && !mapsCopied;
|
||||
warningReadonly.setVisibility(copyFiles ? View.VISIBLE : View.GONE);
|
||||
if (copyFiles) {
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
package net.osmand.plus.development;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Patterns;
|
||||
import android.util.Pair;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
|
@ -17,56 +14,58 @@ import androidx.annotation.NonNull;
|
|||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import net.osmand.AndroidNetworkUtils;
|
||||
import net.osmand.AndroidNetworkUtils.OnFilesUploadCallback;
|
||||
import net.osmand.AndroidNetworkUtils.OnRequestResultListener;
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.ProgressImplementation;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.UiUtilities;
|
||||
import net.osmand.plus.UiUtilities.DialogButtonType;
|
||||
import net.osmand.plus.activities.OsmandActionBarActivity;
|
||||
import net.osmand.plus.backup.BackupHelper;
|
||||
import net.osmand.plus.backup.BackupHelper.BackupInfo;
|
||||
import net.osmand.plus.backup.BackupHelper.OnRegisterUserListener;
|
||||
import net.osmand.plus.backup.BackupTask;
|
||||
import net.osmand.plus.backup.BackupTask.OnBackupListener;
|
||||
import net.osmand.plus.backup.GpxFileInfo;
|
||||
import net.osmand.plus.backup.PrepareBackupTask;
|
||||
import net.osmand.plus.backup.PrepareBackupTask.OnPrepareBackupListener;
|
||||
import net.osmand.plus.backup.UserFile;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.widgets.OsmandTextFieldBoxes;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class TestBackupActivity extends OsmandActionBarActivity {
|
||||
|
||||
// TODO pass actual sub order id!
|
||||
private static final String TEST_ORDER_ID = "";
|
||||
private static final DateFormat DF = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
|
||||
|
||||
private OsmandApplication app;
|
||||
private OsmandSettings settings;
|
||||
private BackupHelper backupHelper;
|
||||
|
||||
private ProgressBar progressBar;
|
||||
private View buttonRegister;
|
||||
private View buttonVerify;
|
||||
private View buttonRefresh;
|
||||
private View buttonBackup;
|
||||
private View buttonRestore;
|
||||
private EditText emailEditText;
|
||||
private OsmandTextFieldBoxes tokenEdit;
|
||||
private EditText tokenEditText;
|
||||
private TextView infoView;
|
||||
|
||||
public interface OnResultListener {
|
||||
void onResult(boolean success, @Nullable String result);
|
||||
}
|
||||
private BackupInfo backupInfo;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
app = getMyApplication();
|
||||
settings = app.getSettings();
|
||||
backupHelper = app.getBackupHelper();
|
||||
final WeakReference<TestBackupActivity> activityRef = new WeakReference<>(this);
|
||||
|
||||
boolean nightMode = !app.getSettings().isLightContent();
|
||||
|
@ -90,15 +89,23 @@ public class TestBackupActivity extends OsmandActionBarActivity {
|
|||
}
|
||||
});
|
||||
|
||||
if (!backupHelper.hasOsmLiveUpdates()) {
|
||||
findViewById(R.id.main_view).setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
|
||||
buttonRegister = findViewById(R.id.btn_register);
|
||||
UiUtilities.setupDialogButton(nightMode, buttonRegister, DialogButtonType.PRIMARY, "Register");
|
||||
buttonVerify = findViewById(R.id.btn_verify);
|
||||
UiUtilities.setupDialogButton(nightMode, buttonVerify, DialogButtonType.PRIMARY, "Verify");
|
||||
buttonRefresh = findViewById(R.id.btn_refresh);
|
||||
UiUtilities.setupDialogButton(nightMode, buttonRefresh, DialogButtonType.PRIMARY, "Refresh");
|
||||
buttonBackup = findViewById(R.id.btn_backup);
|
||||
UiUtilities.setupDialogButton(nightMode, buttonBackup, DialogButtonType.PRIMARY, "Backup");
|
||||
buttonRestore = findViewById(R.id.btn_restore);
|
||||
UiUtilities.setupDialogButton(nightMode, buttonRestore, DialogButtonType.PRIMARY, "Restore");
|
||||
|
||||
tokenEdit = findViewById(R.id.edit_token_label);
|
||||
tokenEditText = findViewById(R.id.edit_token);
|
||||
infoView = findViewById(R.id.text_info);
|
||||
progressBar = findViewById(R.id.progress_bar);
|
||||
|
@ -109,22 +116,31 @@ public class TestBackupActivity extends OsmandActionBarActivity {
|
|||
if (!Algorithms.isEmpty(email)) {
|
||||
emailEditText.setText(email);
|
||||
}
|
||||
if (backupHelper.isRegistered()) {
|
||||
tokenEdit.setVisibility(View.GONE);
|
||||
buttonVerify.setVisibility(View.GONE);
|
||||
} else {
|
||||
tokenEdit.setVisibility(View.VISIBLE);
|
||||
buttonVerify.setVisibility(View.VISIBLE);
|
||||
}
|
||||
buttonRegister.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
String email = emailEditText.getText().toString();
|
||||
if (isEmailValid(email)) {
|
||||
if (AndroidUtils.isValidEmail(email)) {
|
||||
buttonRegister.setEnabled(false);
|
||||
settings.BACKUP_USER_EMAIL.set(email);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
registerUser(email, new OnResultListener() {
|
||||
backupHelper.registerUser(email, new OnRegisterUserListener() {
|
||||
@Override
|
||||
public void onResult(boolean success, @Nullable String result) {
|
||||
public void onRegisterUser(int status, @Nullable String message) {
|
||||
TestBackupActivity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
a.progressBar.setVisibility(View.GONE);
|
||||
a.buttonRegister.setEnabled(!success);
|
||||
a.buttonVerify.setEnabled(success);
|
||||
a.buttonRegister.setEnabled(status != BackupHelper.STATUS_SUCCESS);
|
||||
a.tokenEdit.setVisibility(View.VISIBLE);
|
||||
a.buttonVerify.setVisibility(View.VISIBLE);
|
||||
a.buttonVerify.setEnabled(status == BackupHelper.STATUS_SUCCESS);
|
||||
a.tokenEditText.requestFocus();
|
||||
}
|
||||
}
|
||||
|
@ -139,17 +155,22 @@ public class TestBackupActivity extends OsmandActionBarActivity {
|
|||
@Override
|
||||
public void onClick(View v) {
|
||||
String token = tokenEditText.getText().toString();
|
||||
if (isTokenValid(token)) {
|
||||
if (BackupHelper.isTokenValid(token)) {
|
||||
buttonVerify.setEnabled(false);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
registerDevice(token, new OnResultListener() {
|
||||
backupHelper.registerDevice(token, new BackupHelper.OnRegisterDeviceListener() {
|
||||
|
||||
@Override
|
||||
public void onResult(boolean success, @Nullable String result) {
|
||||
public void onRegisterDevice(int status, @Nullable String message) {
|
||||
TestBackupActivity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
a.progressBar.setVisibility(View.GONE);
|
||||
a.buttonVerify.setEnabled(!success);
|
||||
a.loadBackupInfo();
|
||||
a.buttonVerify.setEnabled(status != BackupHelper.STATUS_SUCCESS);
|
||||
if (status == BackupHelper.STATUS_SUCCESS) {
|
||||
tokenEdit.setVisibility(View.GONE);
|
||||
buttonVerify.setVisibility(View.GONE);
|
||||
}
|
||||
a.prepareBackup();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -160,262 +181,163 @@ public class TestBackupActivity extends OsmandActionBarActivity {
|
|||
}
|
||||
}
|
||||
});
|
||||
buttonRefresh.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
prepareBackup();
|
||||
}
|
||||
});
|
||||
buttonBackup.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
uploadFiles();
|
||||
if (backupInfo != null) {
|
||||
BackupTask task = new BackupTask(backupInfo, TestBackupActivity.this, new OnBackupListener() {
|
||||
@Override
|
||||
public void onBackupDone(@Nullable Map<File, String> uploadErrors, @Nullable Map<File, String> downloadErrors,
|
||||
@Nullable Map<UserFile, String> deleteErrors, @Nullable String error) {
|
||||
TestBackupActivity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
String description;
|
||||
if (error != null) {
|
||||
description = error;
|
||||
} else if (uploadErrors == null && downloadErrors == null) {
|
||||
description = "No data";
|
||||
} else {
|
||||
description = getBackupErrorsDescription(uploadErrors, downloadErrors, deleteErrors, error);
|
||||
}
|
||||
a.infoView.setText(description);
|
||||
a.infoView.requestFocus();
|
||||
a.prepareBackup();
|
||||
}
|
||||
}
|
||||
});
|
||||
task.runBackup();
|
||||
}
|
||||
}
|
||||
});
|
||||
buttonRestore.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (backupInfo != null) {
|
||||
BackupTask task = new BackupTask(backupInfo, TestBackupActivity.this, new OnBackupListener() {
|
||||
@Override
|
||||
public void onBackupDone(@Nullable Map<File, String> uploadErrors, @Nullable Map<File, String> downloadErrors,
|
||||
@Nullable Map<UserFile, String> deleteErrors, @Nullable String error) {
|
||||
TestBackupActivity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
String description;
|
||||
if (error != null) {
|
||||
description = error;
|
||||
} else if (uploadErrors == null && downloadErrors == null) {
|
||||
description = "No data";
|
||||
} else {
|
||||
description = getBackupErrorsDescription(uploadErrors, downloadErrors, deleteErrors, error);
|
||||
}
|
||||
a.infoView.setText(description);
|
||||
a.infoView.requestFocus();
|
||||
a.prepareBackup();
|
||||
}
|
||||
}
|
||||
});
|
||||
task.runRestore();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
loadBackupInfo();
|
||||
prepareBackup();
|
||||
}
|
||||
|
||||
private void loadBackupInfo() {
|
||||
if (!Algorithms.isEmpty(getDeviceId()) && !Algorithms.isEmpty(getAccessToken())) {
|
||||
private String getBackupErrorsDescription(@Nullable Map<File, String> uploadErrors, @Nullable Map<File, String> downloadErrors, @Nullable Map<UserFile, String> deleteErrors, @Nullable String error) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (!Algorithms.isEmpty(uploadErrors)) {
|
||||
sb.append("--- Upload errors ---").append("\n");
|
||||
for (Entry<File, String> uploadEntry : uploadErrors.entrySet()) {
|
||||
sb.append(uploadEntry.getKey().getName()).append(": ").append(uploadEntry.getValue()).append("\n");
|
||||
}
|
||||
}
|
||||
if (!Algorithms.isEmpty(downloadErrors)) {
|
||||
sb.append("--- Download errors ---").append("\n");
|
||||
for (Entry<File, String> downloadEntry : downloadErrors.entrySet()) {
|
||||
sb.append(downloadEntry.getKey().getName()).append(": ").append(downloadEntry.getValue()).append("\n");
|
||||
}
|
||||
}
|
||||
if (!Algorithms.isEmpty(deleteErrors)) {
|
||||
sb.append("--- Delete errors ---").append("\n");
|
||||
for (Entry<UserFile, String> deleteEntry : deleteErrors.entrySet()) {
|
||||
sb.append(deleteEntry.getKey().getName()).append(": ").append(deleteEntry.getValue()).append("\n");
|
||||
}
|
||||
}
|
||||
return sb.length() == 0 ? "OK" : sb.toString();
|
||||
}
|
||||
|
||||
private String getBackupDescription(@NonNull BackupInfo backupInfo) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (!Algorithms.isEmpty(backupInfo.filesToUpload)) {
|
||||
sb.append("\n").append("--- Upload ---").append("\n");
|
||||
for (GpxFileInfo info : backupInfo.filesToUpload) {
|
||||
sb.append(info.getFileName(true))
|
||||
.append(" L: ").append(DF.format(new Date(info.getFileDate())))
|
||||
.append(" U: ").append(DF.format(new Date(info.uploadTime)))
|
||||
.append("\n");
|
||||
}
|
||||
}
|
||||
if (!Algorithms.isEmpty(backupInfo.filesToDownload)) {
|
||||
sb.append("\n").append("--- Download ---").append("\n");
|
||||
for (UserFile userFile : backupInfo.filesToDownload) {
|
||||
sb.append(userFile.getName())
|
||||
.append(" R: ").append(DF.format(new Date(userFile.getClienttimems())))
|
||||
.append("\n");
|
||||
}
|
||||
}
|
||||
if (!Algorithms.isEmpty(backupInfo.filesToDelete)) {
|
||||
sb.append("\n").append("--- Delete ---").append("\n");
|
||||
for (UserFile userFile : backupInfo.filesToDelete) {
|
||||
sb.append(userFile.getName())
|
||||
.append(" R: ").append(DF.format(new Date(userFile.getClienttimems())))
|
||||
.append("\n");
|
||||
}
|
||||
}
|
||||
if (!Algorithms.isEmpty(backupInfo.filesToMerge)) {
|
||||
sb.append("\n").append("--- Conflicts ---").append("\n");
|
||||
for (Pair<GpxFileInfo, UserFile> localRemote : backupInfo.filesToMerge) {
|
||||
GpxFileInfo local = localRemote.first;
|
||||
UserFile remote = localRemote.second;
|
||||
sb.append(local.getFileName(true))
|
||||
.append(" L: ").append(DF.format(new Date(local.getFileDate())))
|
||||
.append(" U: ").append(DF.format(new Date(local.uploadTime)))
|
||||
.append(" R: ").append(DF.format(new Date(remote.getClienttimems())))
|
||||
.append("\n");
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void prepareBackup() {
|
||||
final WeakReference<TestBackupActivity> activityRef = new WeakReference<>(this);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
loadBackupInfo(new OnResultListener() {
|
||||
PrepareBackupTask prepareBackupTask = new PrepareBackupTask(this, new OnPrepareBackupListener() {
|
||||
@Override
|
||||
public void onResult(boolean success, @Nullable String result) {
|
||||
public void onBackupPrepared(@Nullable BackupInfo backupInfo, @Nullable String error) {
|
||||
TestBackupActivity.this.backupInfo = backupInfo;
|
||||
TestBackupActivity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
a.progressBar.setVisibility(View.GONE);
|
||||
a.infoView.setText(result);
|
||||
String description = "Last uploaded: " + DF.format(new Date(settings.BACKUP_LAST_UPLOADED_TIME.get())) + "\n\n";
|
||||
if (error != null) {
|
||||
description += error;
|
||||
} else if (backupInfo == null) {
|
||||
description += "No data";
|
||||
} else {
|
||||
description += "Files to upload: " + backupInfo.filesToUpload.size()
|
||||
+ "\nFiles to download: " + backupInfo.filesToDownload.size()
|
||||
+ "\nFiles to delete: " + backupInfo.filesToDelete.size()
|
||||
+ "\nConflicts: " + backupInfo.filesToMerge.size()
|
||||
+ "\n" + getBackupDescription(backupInfo);
|
||||
}
|
||||
a.infoView.setText(description);
|
||||
a.infoView.requestFocus();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEmailValid(CharSequence target) {
|
||||
return (!TextUtils.isEmpty(target) && Patterns.EMAIL_ADDRESS.matcher(target).matches());
|
||||
}
|
||||
|
||||
private String getOrderId() {
|
||||
return TEST_ORDER_ID;
|
||||
}
|
||||
|
||||
private String getDeviceId() {
|
||||
return settings.BACKUP_DEVICE_ID.get();
|
||||
}
|
||||
|
||||
private String getAccessToken() {
|
||||
return settings.BACKUP_ACCESS_TOKEN.get();
|
||||
}
|
||||
|
||||
private void registerUser(@NonNull String email, @Nullable final OnResultListener listener) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("email", email);
|
||||
params.put("orderid", getOrderId());
|
||||
params.put("deviceid", app.getUserAndroidId());
|
||||
AndroidNetworkUtils.sendRequestAsync(app, "https://osmand.net/userdata/user-register", params, "Register user", true, true, new OnRequestResultListener() {
|
||||
@Override
|
||||
public void onResult(String resultJson) {
|
||||
boolean success = false;
|
||||
if (!Algorithms.isEmpty(resultJson)) {
|
||||
try {
|
||||
// {"status":"ok"}
|
||||
JSONObject result = new JSONObject(resultJson);
|
||||
String status = result.getString("status");
|
||||
success = status.equals("ok");
|
||||
app.showToastMessage(success
|
||||
? "You have been registered successfully. Please check for email with activation code."
|
||||
: "User registration error: " + status);
|
||||
} catch (JSONException e) {
|
||||
app.showToastMessage("User registration error: json parsing");
|
||||
}
|
||||
} else {
|
||||
app.showToastMessage("User registration error: empty response");
|
||||
}
|
||||
if (listener != null) {
|
||||
listener.onResult(success, resultJson);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void registerDevice(String token, @Nullable final OnResultListener listener) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("email", settings.BACKUP_USER_EMAIL.get());
|
||||
params.put("orderid", getOrderId());
|
||||
params.put("deviceid", app.getUserAndroidId());
|
||||
params.put("token", token);
|
||||
AndroidNetworkUtils.sendRequestAsync(app, "https://osmand.net/userdata/device-register", params, "Register device", true, true, new OnRequestResultListener() {
|
||||
@Override
|
||||
public void onResult(String resultJson) {
|
||||
boolean success = false;
|
||||
if (!Algorithms.isEmpty(resultJson)) {
|
||||
try {
|
||||
/*
|
||||
{
|
||||
"id": 1034,
|
||||
"userid": 1033,
|
||||
"deviceid": "2fa8080d2985a777",
|
||||
"orderid": "460000687003939",
|
||||
"accesstoken": "4bc0a61f-397a-4c3e-9ffc-db382ec00372",
|
||||
"udpatetime": "Apr 11, 2021, 11:32:20 AM"
|
||||
}
|
||||
*/
|
||||
JSONObject result = new JSONObject(resultJson);
|
||||
settings.BACKUP_DEVICE_ID.set(result.getString("id"));
|
||||
settings.BACKUP_USER_ID.set(result.getString("userid"));
|
||||
settings.BACKUP_NATIVE_DEVICE_ID.set(result.getString("deviceid"));
|
||||
settings.BACKUP_ACCESS_TOKEN.set(result.getString("accesstoken"));
|
||||
settings.BACKUP_ACCESS_TOKEN_UPDATE_TIME.set(result.getString("udpatetime"));
|
||||
success = true;
|
||||
app.showToastMessage("Device have been registered successfully");
|
||||
} catch (JSONException e) {
|
||||
app.showToastMessage("Device registration error: json parsing");
|
||||
}
|
||||
} else {
|
||||
app.showToastMessage("Device registration error: empty response");
|
||||
}
|
||||
if (listener != null) {
|
||||
listener.onResult(success, resultJson);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void uploadFiles() {
|
||||
LoadGpxTask loadGpxTask = new LoadGpxTask(this, new LoadGpxTask.OnLoadGpxListener() {
|
||||
@Override
|
||||
public void onLoadGpxDone(@NonNull List<GpxInfo> result) {
|
||||
uploadFiles(result);
|
||||
}
|
||||
});
|
||||
loadGpxTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, this);
|
||||
}
|
||||
|
||||
private void uploadFiles(List<GpxInfo> gpxFiles) {
|
||||
//{"status":"ok"}
|
||||
final WeakReference<TestBackupActivity> activityRef = new WeakReference<>(this);
|
||||
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("deviceid", getDeviceId());
|
||||
params.put("accessToken", getAccessToken());
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Accept-Encoding", "deflate, gzip");
|
||||
|
||||
final Map<File, GpxInfo> gpxInfos = new HashMap<>();
|
||||
for (GpxInfo gpxFile : gpxFiles) {
|
||||
gpxInfos.put(gpxFile.file, gpxFile);
|
||||
}
|
||||
final List<File> files = new ArrayList<>(gpxInfos.keySet());
|
||||
File favoritesFile = app.getFavorites().getExternalFile();
|
||||
files.add(favoritesFile);
|
||||
|
||||
final ProgressImplementation progress = ProgressImplementation.createProgressDialog(this,
|
||||
"Create backup", "Uploading " + files.size() + " file(s) to server", ProgressDialog.STYLE_HORIZONTAL);
|
||||
|
||||
AndroidNetworkUtils.uploadFilesAsync("https://osmand.net/userdata/upload-file", files, true, params, headers, new OnFilesUploadCallback() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Map<String, String> getAdditionalParams(@NonNull File file) {
|
||||
GpxInfo gpxInfo = gpxInfos.get(file);
|
||||
Map<String, String> additionaParams = new HashMap<>();
|
||||
additionaParams.put("name", gpxInfo == null ? file.getName() : gpxInfo.getFileName(true));
|
||||
additionaParams.put("type", Algorithms.getFileExtension(file));
|
||||
return additionaParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileUploadProgress(@NonNull File file, int percent) {
|
||||
Activity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
if (percent < 100) {
|
||||
progress.startTask(file.getName(), percent);
|
||||
} else {
|
||||
progress.finishTask();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilesUploadDone(@NonNull Map<File, String> errors) {
|
||||
Activity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
app.runInUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (progress.getDialog().isShowing()) {
|
||||
progress.getDialog().dismiss();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//ignored
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
app.showToastMessage("Uploaded " + (files.size() - errors.size() + " files" +
|
||||
(errors.size() > 0 ? ". Errors: " + errors.size() : "")));
|
||||
loadBackupInfo();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadBackupInfo(@Nullable final OnResultListener listener) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("deviceid", getDeviceId());
|
||||
params.put("accessToken", getAccessToken());
|
||||
AndroidNetworkUtils.sendRequestAsync(app, "https://osmand.net/userdata/list-files", params, "Get backup info", true, false, new OnRequestResultListener() {
|
||||
@Override
|
||||
public void onResult(String resultJson) {
|
||||
boolean success = false;
|
||||
StringBuilder resultString = new StringBuilder();
|
||||
if (!Algorithms.isEmpty(resultJson)) {
|
||||
try {
|
||||
/*
|
||||
{
|
||||
"totalZipSize": 21792,
|
||||
"totalFileSize": 185920,
|
||||
"totalFiles": 1,
|
||||
"totalFileVersions": 2,
|
||||
"uniqueFiles": [
|
||||
{
|
||||
"userid": 1033,
|
||||
"id": 7,
|
||||
"deviceid": 1034,
|
||||
"filesize": 92960,
|
||||
"type": "gpx",
|
||||
"name": "test/Day 2.gpx",
|
||||
"updatetime": "Apr 11, 2021, 1:49:01 PM",
|
||||
"updatetimems": 1618141741822,
|
||||
"zipSize": 10896
|
||||
}
|
||||
],
|
||||
"deviceid": 1034
|
||||
}
|
||||
*/
|
||||
JSONObject result = new JSONObject(resultJson);
|
||||
String totalZipSize = result.getString("totalZipSize");
|
||||
String totalFiles = result.getString("totalFiles");
|
||||
String totalFileVersions = result.getString("totalFileVersions");
|
||||
JSONArray files = result.getJSONArray("uniqueFiles");
|
||||
resultString.append("Total files: ").append(totalFiles).append("\n");
|
||||
resultString.append("Total zip size: ").append(AndroidUtils.formatSize(app, Long.parseLong(totalZipSize))).append("\n");
|
||||
resultString.append("Total file versions: ").append(totalFileVersions);
|
||||
|
||||
success = true;
|
||||
} catch (JSONException e) {
|
||||
}
|
||||
}
|
||||
if (listener != null) {
|
||||
listener.onResult(success, resultString.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isTokenValid(String token) {
|
||||
return token.matches("[0-9]+");
|
||||
prepareBackupTask.prepare();
|
||||
}
|
||||
|
||||
private int resolveResourceId(final Activity activity, final int attr) {
|
||||
|
@ -423,173 +345,4 @@ public class TestBackupActivity extends OsmandActionBarActivity {
|
|||
activity.getTheme().resolveAttribute(attr, typedvalueattr, true);
|
||||
return typedvalueattr.resourceId;
|
||||
}
|
||||
|
||||
private static class LoadGpxTask extends AsyncTask<Activity, GpxInfo, List<GpxInfo>> {
|
||||
|
||||
private final OsmandApplication app;
|
||||
private final OnLoadGpxListener listener;
|
||||
private final WeakReference<Activity> activityRef;
|
||||
private List<GpxInfo> result;
|
||||
private ProgressImplementation progress;
|
||||
|
||||
interface OnLoadGpxListener {
|
||||
void onLoadGpxDone(@NonNull List<GpxInfo> result);
|
||||
}
|
||||
|
||||
LoadGpxTask(@NonNull Activity activity, @Nullable OnLoadGpxListener listener) {
|
||||
this.activityRef = new WeakReference<>(activity);
|
||||
this.app = (OsmandApplication) activity.getApplication();
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public List<GpxInfo> getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected List<GpxInfo> doInBackground(Activity... params) {
|
||||
List<GpxInfo> result = new ArrayList<>();
|
||||
loadGPXData(app.getAppPath(IndexConstants.GPX_INDEX_DIR), result, this);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void loadFile(GpxInfo... loaded) {
|
||||
publishProgress(loaded);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
Activity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
progress = ProgressImplementation.createProgressDialog(a,
|
||||
"Create backup", "Collecting gpx files...", ProgressDialog.STYLE_HORIZONTAL);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(GpxInfo... values) {
|
||||
Activity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
progress.startTask(values[0].getFileName(true), -1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(@NonNull List<GpxInfo> result) {
|
||||
this.result = result;
|
||||
if (listener != null) {
|
||||
listener.onLoadGpxDone(result);
|
||||
}
|
||||
Activity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
progress.finishTask();
|
||||
app.runInUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (progress.getDialog().isShowing()) {
|
||||
progress.getDialog().dismiss();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//ignored
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadGPXData(File mapPath, List<GpxInfo> result, LoadGpxTask loadTask) {
|
||||
if (mapPath.canRead()) {
|
||||
List<GpxInfo> progress = new ArrayList<>();
|
||||
loadGPXFolder(mapPath, result, loadTask, progress, "");
|
||||
if (!progress.isEmpty()) {
|
||||
loadTask.loadFile(progress.toArray(new GpxInfo[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadGPXFolder(File mapPath, List<GpxInfo> result, LoadGpxTask loadTask, List<GpxInfo> progress,
|
||||
String gpxSubfolder) {
|
||||
File[] listFiles = mapPath.listFiles();
|
||||
if (listFiles != null) {
|
||||
for (File gpxFile : listFiles) {
|
||||
if (gpxFile.isDirectory()) {
|
||||
String sub = gpxSubfolder.length() == 0 ? gpxFile.getName() : gpxSubfolder + "/"
|
||||
+ gpxFile.getName();
|
||||
loadGPXFolder(gpxFile, result, loadTask, progress, sub);
|
||||
} else if (gpxFile.isFile() && gpxFile.getName().toLowerCase().endsWith(IndexConstants.GPX_FILE_EXT)) {
|
||||
GpxInfo info = new GpxInfo();
|
||||
info.subfolder = gpxSubfolder;
|
||||
info.file = gpxFile;
|
||||
result.add(info);
|
||||
progress.add(info);
|
||||
if (progress.size() > 7) {
|
||||
loadTask.loadFile(progress.toArray(new GpxInfo[0]));
|
||||
progress.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class GpxInfo {
|
||||
public File file;
|
||||
public String subfolder;
|
||||
|
||||
private String name = null;
|
||||
private int sz = -1;
|
||||
private String fileName = null;
|
||||
|
||||
public String getName() {
|
||||
if (name == null) {
|
||||
name = formatName(file.getName());
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private String formatName(String name) {
|
||||
int ext = name.lastIndexOf('.');
|
||||
if (ext != -1) {
|
||||
name = name.substring(0, ext);
|
||||
}
|
||||
return name.replace('_', ' ');
|
||||
}
|
||||
|
||||
// Usage: AndroidUtils.formatSize(v.getContext(), getSize() * 1024l);
|
||||
public int getSize() {
|
||||
if (sz == -1) {
|
||||
if (file == null) {
|
||||
return -1;
|
||||
}
|
||||
sz = (int) ((file.length() + 512) >> 10);
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
public long getFileDate() {
|
||||
if (file == null) {
|
||||
return 0;
|
||||
}
|
||||
return file.lastModified();
|
||||
}
|
||||
|
||||
public String getFileName(boolean includeSubfolder) {
|
||||
String result;
|
||||
if (fileName != null) {
|
||||
result = fileName;
|
||||
} else {
|
||||
if (file == null) {
|
||||
result = "";
|
||||
} else {
|
||||
result = fileName = file.getName();
|
||||
}
|
||||
}
|
||||
if (includeSubfolder && !Algorithms.isEmpty(subfolder)) {
|
||||
result = subfolder + "/" + result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -530,7 +530,7 @@ public class ConfigureMapMenu {
|
|||
TextView switchText = (TextView) v.findViewById(R.id.switchText);
|
||||
switchText.setText(activity.getString(R.string.translit_name_if_miss, txtValues[position]));
|
||||
SwitchCompat check = (SwitchCompat) v.findViewById(R.id.check);
|
||||
check.setChecked(settings.MAP_TRANSLITERATE_NAMES.isSet() ? transliterateNames : txtIds[position].equals("en"));
|
||||
check.setChecked(transliterateNames);
|
||||
check.setOnCheckedChangeListener(translitChangdListener);
|
||||
UiUtilities.setupCompoundButton(nightMode, selectedProfileColor, check);
|
||||
} else {
|
||||
|
@ -548,6 +548,7 @@ public class ConfigureMapMenu {
|
|||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
selectedLanguageIndex = which;
|
||||
transliterateNames = settings.MAP_TRANSLITERATE_NAMES.isSet() ? transliterateNames : txtIds[which].equals("en");
|
||||
((AlertDialog) dialog).getListView().setSelection(which);
|
||||
singleChoiceAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
|
|
@ -652,7 +652,7 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
|
|||
TextView messageTextView = (TextView) view.findViewById(R.id.leftTextView);
|
||||
ProgressBar sizeProgress = (ProgressBar) view.findViewById(R.id.progressBar);
|
||||
|
||||
File dir = activity.getMyApplication().getAppPath("").getParentFile();
|
||||
File dir = activity.getMyApplication().getAppPath(null);
|
||||
String size = "";
|
||||
int percent = 0;
|
||||
if (dir.canRead()) {
|
||||
|
|
|
@ -10,6 +10,7 @@ import net.osmand.map.OsmandRegions;
|
|||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.Version;
|
||||
import net.osmand.plus.activities.LocalIndexInfo;
|
||||
import net.osmand.plus.helpers.FileNameTranslationHelper;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
|
@ -27,6 +28,7 @@ import java.util.Locale;
|
|||
import java.util.Map;
|
||||
|
||||
import static net.osmand.IndexConstants.BINARY_MAP_INDEX_EXT;
|
||||
import static net.osmand.plus.activities.LocalIndexHelper.LocalIndexType.SRTM_DATA;
|
||||
|
||||
public class DownloadActivityType {
|
||||
private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.MM.yyyy", Locale.US);
|
||||
|
@ -145,8 +147,9 @@ public class DownloadActivityType {
|
|||
return fileName.endsWith(addVersionToExt(IndexConstants.BINARY_TRAVEL_GUIDE_MAP_INDEX_EXT_ZIP,
|
||||
IndexConstants.BINARY_MAP_VERSION));
|
||||
} else if (SRTM_COUNTRY_FILE == this) {
|
||||
return fileName.endsWith(addVersionToExt(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT_ZIP,
|
||||
IndexConstants.BINARY_MAP_VERSION));
|
||||
boolean srtm = fileName.endsWith(addVersionToExt(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT_ZIP, IndexConstants.BINARY_MAP_VERSION));
|
||||
boolean srtmf = fileName.endsWith(addVersionToExt(IndexConstants.BINARY_SRTM_FEET_MAP_INDEX_EXT_ZIP, IndexConstants.BINARY_MAP_VERSION));
|
||||
return srtm || srtmf;
|
||||
} else if (HILLSHADE_FILE == this) {
|
||||
return fileName.endsWith(IndexConstants.SQLITE_EXT);
|
||||
} else if (SLOPE_FILE == this) {
|
||||
|
@ -227,7 +230,7 @@ public class DownloadActivityType {
|
|||
} else if (FONT_FILE == this) {
|
||||
return IndexConstants.FONT_INDEX_EXT;
|
||||
} else if (SRTM_COUNTRY_FILE == this) {
|
||||
return IndexConstants.BINARY_SRTM_MAP_INDEX_EXT;
|
||||
return SrtmDownloadItem.getExtension(indexItem);
|
||||
} else if (WIKIPEDIA_FILE == this) {
|
||||
return IndexConstants.BINARY_WIKI_MAP_INDEX_EXT;
|
||||
} else if (WIKIVOYAGE_FILE == this) {
|
||||
|
@ -361,6 +364,9 @@ public class DownloadActivityType {
|
|||
if (basename.endsWith(FileNameTranslationHelper.WIKI_NAME)) {
|
||||
return FileNameTranslationHelper.getWikiName(ctx, basename);
|
||||
}
|
||||
if (basename.endsWith(FileNameTranslationHelper.WIKIVOYAGE_NAME)) {
|
||||
return FileNameTranslationHelper.getWikivoyageName(ctx, basename);
|
||||
}
|
||||
// if (this == HILLSHADE_FILE){
|
||||
// return FileNameTranslationHelper.getHillShadeName(ctx, osmandRegions, bn);
|
||||
// }
|
||||
|
@ -423,7 +429,7 @@ public class DownloadActivityType {
|
|||
}
|
||||
String baseNameWithoutVersion = fileName.substring(0, l);
|
||||
if (this == SRTM_COUNTRY_FILE) {
|
||||
return baseNameWithoutVersion + IndexConstants.BINARY_SRTM_MAP_INDEX_EXT;
|
||||
return baseNameWithoutVersion + SrtmDownloadItem.getExtension(item);
|
||||
}
|
||||
if (this == WIKIPEDIA_FILE) {
|
||||
return baseNameWithoutVersion + IndexConstants.BINARY_WIKI_MAP_INDEX_EXT;
|
||||
|
|
|
@ -7,6 +7,7 @@ import net.osmand.osm.io.NetworkUtils;
|
|||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.Version;
|
||||
import net.osmand.plus.download.IndexItem.DownloadEntry;
|
||||
import net.osmand.plus.helpers.FileNameTranslationHelper;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
|
@ -213,8 +214,8 @@ public class DownloadFileHelper {
|
|||
}
|
||||
unzipFile(de, progress, downloadInputStreams);
|
||||
if (!de.targetFile.getAbsolutePath().equals(de.fileToDownload.getAbsolutePath())) {
|
||||
boolean successfull = Algorithms.removeAllFiles(de.targetFile);
|
||||
if (successfull) {
|
||||
boolean successful = Algorithms.removeAllFiles(de.targetFile);
|
||||
if (successful) {
|
||||
ctx.getResourceManager().closeFile(de.targetFile.getName());
|
||||
}
|
||||
|
||||
|
@ -226,6 +227,8 @@ public class DownloadFileHelper {
|
|||
}
|
||||
if (de.type == DownloadActivityType.VOICE_FILE) {
|
||||
copyVoiceConfig(de);
|
||||
} else if (de.type == DownloadActivityType.SRTM_COUNTRY_FILE) {
|
||||
removePreviousSrtmFile(de);
|
||||
}
|
||||
toReIndex.add(de.targetFile);
|
||||
return true;
|
||||
|
@ -238,6 +241,26 @@ public class DownloadFileHelper {
|
|||
}
|
||||
}
|
||||
|
||||
private void removePreviousSrtmFile(DownloadEntry entry) {
|
||||
String meterExt = IndexConstants.BINARY_SRTM_MAP_INDEX_EXT;
|
||||
String feetExt = IndexConstants.BINARY_SRTM_FEET_MAP_INDEX_EXT;
|
||||
|
||||
String fileName = entry.targetFile.getAbsolutePath();
|
||||
if (fileName.endsWith(meterExt)) {
|
||||
fileName = fileName.replace(meterExt, feetExt);
|
||||
} else if (fileName.endsWith(feetExt)) {
|
||||
fileName = fileName.replace(feetExt, meterExt);
|
||||
}
|
||||
|
||||
File previous = new File(fileName);
|
||||
if (previous != null && previous.exists()) {
|
||||
boolean successful = Algorithms.removeAllFiles(previous);
|
||||
if (successful) {
|
||||
ctx.getResourceManager().closeFile(previous.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void copyVoiceConfig(IndexItem.DownloadEntry de) {
|
||||
File f = ctx.getAppPath("/voice/" + de.baseName + "/_config.p");
|
||||
if (f.exists()) try {
|
||||
|
@ -401,8 +424,5 @@ public class DownloadFileHelper {
|
|||
count = 0;
|
||||
return last;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import android.net.TrafficStats;
|
|||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.AsyncTask.Status;
|
||||
import android.os.StatFs;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
@ -17,13 +16,12 @@ import androidx.annotation.UiThread;
|
|||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import net.osmand.AndroidNetworkUtils;
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.map.WorldRegion;
|
||||
import net.osmand.map.WorldRegion.RegionParams;
|
||||
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.base.BasicProgressAsyncTask;
|
||||
|
@ -31,6 +29,8 @@ import net.osmand.plus.download.DownloadFileHelper.DownloadFileShowWarning;
|
|||
import net.osmand.plus.helpers.DatabaseHelper;
|
||||
import net.osmand.plus.notifications.OsmandNotification;
|
||||
import net.osmand.plus.resources.ResourceManager;
|
||||
import net.osmand.plus.settings.backend.OsmandPreference;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
@ -240,9 +240,12 @@ public class DownloadIndexesThread {
|
|||
}
|
||||
|
||||
public void cancelDownload(DownloadItem item) {
|
||||
if (item instanceof MultipleIndexItem) {
|
||||
MultipleIndexItem multipleIndexItem = (MultipleIndexItem) item;
|
||||
cancelDownload(multipleIndexItem.getAllIndexes());
|
||||
if (item instanceof MultipleDownloadItem) {
|
||||
MultipleDownloadItem multipleDownloadItem = (MultipleDownloadItem) item;
|
||||
cancelDownload(multipleDownloadItem.getAllIndexes());
|
||||
} else if (item instanceof SrtmDownloadItem) {
|
||||
IndexItem indexItem = ((SrtmDownloadItem) item).getIndexItem();
|
||||
cancelDownload(indexItem);
|
||||
} else if (item instanceof IndexItem) {
|
||||
IndexItem indexItem = (IndexItem) item;
|
||||
cancelDownload(indexItem);
|
||||
|
@ -299,19 +302,8 @@ public class DownloadIndexesThread {
|
|||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public double getAvailableSpace() {
|
||||
File dir = app.getAppPath("").getParentFile();
|
||||
double asz = -1;
|
||||
if (dir.canRead()) {
|
||||
try {
|
||||
StatFs fs = new StatFs(dir.getAbsolutePath());
|
||||
asz = (((long) fs.getAvailableBlocks()) * fs.getBlockSize()) / (1 << 20);
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
return asz;
|
||||
return AndroidUtils.getAvailableSpace(app) / (1 << 20);
|
||||
}
|
||||
|
||||
/// PRIVATE IMPL
|
||||
|
|
|
@ -3,12 +3,14 @@ package net.osmand.plus.download;
|
|||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.map.OsmandRegions;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.DateFormat;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
|
@ -55,6 +57,12 @@ public abstract class DownloadItem {
|
|||
return type.getBasename(this);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public abstract List<File> getDownloadedFiles(@NonNull OsmandApplication app);
|
||||
|
||||
@Nullable
|
||||
public abstract String getAdditionalDescription(Context ctx);
|
||||
|
||||
protected abstract double getSizeToDownloadInMb();
|
||||
|
||||
public abstract double getArchiveSizeMB();
|
||||
|
@ -69,8 +77,7 @@ public abstract class DownloadItem {
|
|||
|
||||
public abstract String getFileName();
|
||||
|
||||
@NonNull
|
||||
public abstract List<File> getDownloadedFiles(@NonNull OsmandApplication app);
|
||||
public abstract String getDate(@NonNull DateFormat dateFormat, boolean remote);
|
||||
|
||||
@NonNull
|
||||
public static String getFormattedMb(@NonNull Context ctx, double sizeInMb) {
|
||||
|
|
|
@ -1,5 +1,26 @@
|
|||
package net.osmand.plus.download;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.AssetManager;
|
||||
import android.provider.Settings.Secure;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.osm.io.NetworkUtils;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlPullParserFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -11,26 +32,6 @@ import java.util.Comparator;
|
|||
import java.util.List;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.osm.io.NetworkUtils;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlPullParserFactory;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.AssetManager;
|
||||
import android.provider.Settings.Secure;
|
||||
|
||||
public class DownloadOsmandIndexesHelper {
|
||||
private final static Log log = PlatformUtil.getLog(DownloadOsmandIndexesHelper.class);
|
||||
|
||||
|
|
|
@ -25,12 +25,11 @@ import java.io.InputStream;
|
|||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static net.osmand.plus.download.DownloadResourceGroup.DownloadResourceGroupType.REGION_MAPS;
|
||||
|
||||
|
@ -117,6 +116,16 @@ public class DownloadResources extends DownloadResourceGroup {
|
|||
return res;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<DownloadItem> getDownloadItems(WorldRegion region) {
|
||||
DownloadResourceGroup group = getRegionMapsGroup(region);
|
||||
if (group != null) {
|
||||
return group.getIndividualDownloadItems();
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<IndexItem> getIndexItems(WorldRegion region) {
|
||||
if (groupByRegion != null) {
|
||||
List<IndexItem> res = groupByRegion.get(region);
|
||||
|
@ -124,7 +133,7 @@ public class DownloadResources extends DownloadResourceGroup {
|
|||
return res;
|
||||
}
|
||||
}
|
||||
return new LinkedList<>();
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public void updateLoadedFiles() {
|
||||
|
@ -471,30 +480,60 @@ public class DownloadResources extends DownloadResourceGroup {
|
|||
addGroup(otherGroup);
|
||||
|
||||
createHillshadeSRTMGroups();
|
||||
collectMultipleIndexesItems();
|
||||
replaceIndividualSrtmWithGroups(region);
|
||||
createMultipleDownloadItems(region);
|
||||
trimEmptyGroups();
|
||||
updateLoadedFiles();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void collectMultipleIndexesItems() {
|
||||
collectMultipleIndexesItems(region);
|
||||
private void replaceIndividualSrtmWithGroups(@NonNull WorldRegion region) {
|
||||
DownloadResourceGroup group = getRegionMapsGroup(region);
|
||||
if (group != null) {
|
||||
boolean useMetersByDefault = SrtmDownloadItem.isUseMetricByDefault(app);
|
||||
boolean listModified = false;
|
||||
DownloadActivityType srtmType = DownloadActivityType.SRTM_COUNTRY_FILE;
|
||||
List<DownloadItem> individualItems = group.getIndividualDownloadItems();
|
||||
if (isListContainsType(individualItems, srtmType)) {
|
||||
List<IndexItem> srtmIndexes = new ArrayList<>();
|
||||
for (DownloadItem item : individualItems) {
|
||||
if (item.getType() == srtmType && item instanceof IndexItem) {
|
||||
srtmIndexes.add((IndexItem) item);
|
||||
}
|
||||
}
|
||||
if (srtmIndexes.size() > 1) {
|
||||
individualItems.removeAll(srtmIndexes);
|
||||
group.addItem(new SrtmDownloadItem(srtmIndexes, useMetersByDefault));
|
||||
}
|
||||
listModified = true;
|
||||
}
|
||||
if (listModified) {
|
||||
sortDownloadItems(individualItems);
|
||||
}
|
||||
}
|
||||
|
||||
private void collectMultipleIndexesItems(@NonNull WorldRegion region) {
|
||||
List<WorldRegion> subRegions = region.getSubregions();
|
||||
if (!Algorithms.isEmpty(subRegions)) {
|
||||
for (WorldRegion subRegion : subRegions) {
|
||||
replaceIndividualSrtmWithGroups(subRegion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createMultipleDownloadItems(@NonNull WorldRegion region) {
|
||||
List<WorldRegion> subRegions = region.getSubregions();
|
||||
if (Algorithms.isEmpty(subRegions)) return;
|
||||
|
||||
DownloadResourceGroup group = getRegionMapsGroup(region);
|
||||
if (group != null) {
|
||||
boolean listModified = false;
|
||||
List<IndexItem> indexesList = group.getIndividualResources();
|
||||
List<WorldRegion> regionsToCollect = removeDuplicateRegions(subRegions);
|
||||
List<DownloadItem> downloadItems = group.getIndividualDownloadItems();
|
||||
List<WorldRegion> uniqueSubRegions = WorldRegion.removeDuplicates(subRegions);
|
||||
for (DownloadActivityType type : DownloadActivityType.values()) {
|
||||
if (!doesListContainIndexWithType(indexesList, type)) {
|
||||
List<IndexItem> indexesFromSubRegions = collectIndexesOfType(regionsToCollect, type);
|
||||
if (indexesFromSubRegions != null) {
|
||||
group.addItem(new MultipleIndexItem(region, indexesFromSubRegions, type));
|
||||
if (!isListContainsType(downloadItems, type)) {
|
||||
List<DownloadItem> itemsFromSubRegions = collectItemsOfType(uniqueSubRegions, type);
|
||||
if (itemsFromSubRegions != null) {
|
||||
group.addItem(new MultipleDownloadItem(region, itemsFromSubRegions, type));
|
||||
listModified = true;
|
||||
}
|
||||
}
|
||||
|
@ -504,7 +543,7 @@ public class DownloadResources extends DownloadResourceGroup {
|
|||
}
|
||||
}
|
||||
for (WorldRegion subRegion : subRegions) {
|
||||
collectMultipleIndexesItems(subRegion);
|
||||
createMultipleDownloadItems(subRegion);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -517,43 +556,21 @@ public class DownloadResources extends DownloadResourceGroup {
|
|||
}
|
||||
|
||||
@Nullable
|
||||
private List<IndexItem> collectIndexesOfType(@NonNull List<WorldRegion> regions,
|
||||
private List<DownloadItem> collectItemsOfType(@NonNull List<WorldRegion> regions,
|
||||
@NonNull DownloadActivityType type) {
|
||||
List<IndexItem> collectedIndexes = new ArrayList<>();
|
||||
List<DownloadItem> collectedItems = new ArrayList<>();
|
||||
for (WorldRegion region : regions) {
|
||||
List<IndexItem> regionIndexes = getIndexItems(region);
|
||||
boolean found = false;
|
||||
if (regionIndexes != null) {
|
||||
for (IndexItem index : regionIndexes) {
|
||||
if (index.getType() == type) {
|
||||
for (DownloadItem item : getDownloadItems(region)) {
|
||||
if (item.getType() == type) {
|
||||
found = true;
|
||||
collectedIndexes.add(index);
|
||||
collectedItems.add(item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) return null;
|
||||
}
|
||||
return collectedIndexes;
|
||||
}
|
||||
|
||||
private List<WorldRegion> removeDuplicateRegions(List<WorldRegion> regions) {
|
||||
Set<WorldRegion> duplicates = new HashSet<>();
|
||||
for (int i = 0; i < regions.size() - 1; i++) {
|
||||
WorldRegion r1 = regions.get(i);
|
||||
for (int j = i + 1; j < regions.size(); j++) {
|
||||
WorldRegion r2 = regions.get(j);
|
||||
if (r1.containsRegion(r2)) {
|
||||
duplicates.add(r2);
|
||||
} else if (r2.containsRegion(r1)) {
|
||||
duplicates.add(r1);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (WorldRegion region : duplicates) {
|
||||
regions.remove(region);
|
||||
}
|
||||
return regions;
|
||||
return collectedItems;
|
||||
}
|
||||
|
||||
private void buildRegionsGroups(WorldRegion region, DownloadResourceGroup group) {
|
||||
|
@ -680,11 +697,11 @@ public class DownloadResources extends DownloadResourceGroup {
|
|||
&& isIndexItemDownloaded(downloadThread, type, downloadRegion.getSuperregion(), res);
|
||||
}
|
||||
|
||||
private boolean doesListContainIndexWithType(List<IndexItem> indexItems,
|
||||
private boolean isListContainsType(List<DownloadItem> items,
|
||||
DownloadActivityType type) {
|
||||
if (indexItems != null) {
|
||||
for (IndexItem indexItem : indexItems) {
|
||||
if (indexItem.getType() == type) {
|
||||
if (items != null) {
|
||||
for (DownloadItem item : items) {
|
||||
if (item.getType() == type) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package net.osmand.plus.download;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.PlatformUtil;
|
||||
|
@ -19,6 +22,7 @@ import java.util.Date;
|
|||
import java.util.List;
|
||||
|
||||
public class IndexItem extends DownloadItem implements Comparable<IndexItem> {
|
||||
|
||||
private static final Log log = PlatformUtil.getLog(IndexItem.class);
|
||||
|
||||
String description;
|
||||
|
@ -226,6 +230,15 @@ public class IndexItem extends DownloadItem implements Comparable<IndexItem> {
|
|||
return format.format(new Date(timestamp));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getAdditionalDescription(Context ctx) {
|
||||
if (getType() == DownloadActivityType.SRTM_COUNTRY_FILE) {
|
||||
return SrtmDownloadItem.getAbbreviationInScopes(ctx, this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class DownloadEntry {
|
||||
public long dateModified;
|
||||
public double sizeMB;
|
||||
|
@ -254,5 +267,4 @@ public class IndexItem extends DownloadItem implements Comparable<IndexItem> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,32 +1,47 @@
|
|||
package net.osmand.plus.download;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.map.WorldRegion;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MultipleIndexItem extends DownloadItem {
|
||||
public class MultipleDownloadItem extends DownloadItem {
|
||||
|
||||
private final List<IndexItem> items;
|
||||
private final List<DownloadItem> items;
|
||||
|
||||
public MultipleIndexItem(@NonNull WorldRegion region,
|
||||
@NonNull List<IndexItem> items,
|
||||
public MultipleDownloadItem(@NonNull WorldRegion region,
|
||||
@NonNull List<DownloadItem> items,
|
||||
@NonNull DownloadActivityType type) {
|
||||
super(type);
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
public List<IndexItem> getAllIndexes() {
|
||||
List<IndexItem> indexes = new ArrayList<>();
|
||||
for (DownloadItem item : items) {
|
||||
IndexItem index = getIndexItem(item);
|
||||
if (index != null) {
|
||||
indexes.add(index);
|
||||
}
|
||||
}
|
||||
return indexes;
|
||||
}
|
||||
|
||||
public List<DownloadItem> getAllItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOutdated() {
|
||||
for (IndexItem item : items) {
|
||||
for (DownloadItem item : items) {
|
||||
if (item.isOutdated()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -36,7 +51,7 @@ public class MultipleIndexItem extends DownloadItem {
|
|||
|
||||
@Override
|
||||
public boolean isDownloaded() {
|
||||
for (IndexItem item : items) {
|
||||
for (DownloadItem item : items) {
|
||||
if (item.isDownloaded()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -46,8 +61,8 @@ public class MultipleIndexItem extends DownloadItem {
|
|||
|
||||
@Override
|
||||
public boolean isDownloading(@NonNull DownloadIndexesThread thread) {
|
||||
for (IndexItem item : items) {
|
||||
if (thread.isDownloading(item)) {
|
||||
for (DownloadItem item : items) {
|
||||
if (item.isDownloading(thread)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -78,31 +93,31 @@ public class MultipleIndexItem extends DownloadItem {
|
|||
@Override
|
||||
public List<File> getDownloadedFiles(@NonNull OsmandApplication app) {
|
||||
List<File> result = new ArrayList<>();
|
||||
for (IndexItem item : items) {
|
||||
for (DownloadItem item : items) {
|
||||
result.addAll(item.getDownloadedFiles(app));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<IndexItem> getIndexesToDownload() {
|
||||
List<IndexItem> indexesToDownload = new ArrayList<>();
|
||||
for (IndexItem item : items) {
|
||||
public List<DownloadItem> getItemsToDownload() {
|
||||
List<DownloadItem> itemsToDownload = new ArrayList<>();
|
||||
for (DownloadItem item : getAllItems()) {
|
||||
if (item.hasActualDataToDownload()) {
|
||||
indexesToDownload.add(item);
|
||||
itemsToDownload.add(item);
|
||||
}
|
||||
}
|
||||
return indexesToDownload;
|
||||
return itemsToDownload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActualDataToDownload() {
|
||||
return getIndexesToDownload().size() > 0;
|
||||
return getItemsToDownload().size() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSizeToDownloadInMb() {
|
||||
double totalSizeMb = 0.0d;
|
||||
for (IndexItem item : items) {
|
||||
for (DownloadItem item : items) {
|
||||
if (item.hasActualDataToDownload()) {
|
||||
totalSizeMb += item.getSizeToDownloadInMb();
|
||||
}
|
||||
|
@ -113,10 +128,30 @@ public class MultipleIndexItem extends DownloadItem {
|
|||
@Override
|
||||
public double getArchiveSizeMB() {
|
||||
double result = 0.0d;
|
||||
for (IndexItem item : items) {
|
||||
for (DownloadItem item : items) {
|
||||
result += item.getArchiveSizeMB();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static IndexItem getIndexItem(@NonNull DownloadItem obj) {
|
||||
if (obj instanceof IndexItem) {
|
||||
return (IndexItem) obj;
|
||||
} else if (obj instanceof SrtmDownloadItem) {
|
||||
return ((SrtmDownloadItem) obj).getDefaultIndexItem();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getAdditionalDescription(Context ctx) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDate(@NonNull DateFormat dateFormat, boolean remote) {
|
||||
return "";
|
||||
}
|
||||
}
|
|
@ -1,113 +0,0 @@
|
|||
package net.osmand.plus.download;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import net.osmand.map.OsmandRegions;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.base.SelectMultipleItemsBottomSheet;
|
||||
import net.osmand.plus.base.SelectMultipleItemsBottomSheet.OnApplySelectionListener;
|
||||
import net.osmand.plus.base.SelectMultipleItemsBottomSheet.SelectableItem;
|
||||
import net.osmand.plus.base.SelectMultipleItemsBottomSheet.SelectionUpdateListener;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MultipleIndexesUiHelper {
|
||||
|
||||
public static void showDialog(@NonNull MultipleIndexItem multipleIndexItem,
|
||||
@NonNull AppCompatActivity activity,
|
||||
@NonNull final OsmandApplication app,
|
||||
@NonNull DateFormat dateFormat,
|
||||
boolean showRemoteDate,
|
||||
@NonNull final SelectItemsToDownloadListener listener) {
|
||||
List<IndexItem> indexesToDownload = getIndexesToDownload(multipleIndexItem);
|
||||
List<SelectableItem> allItems = new ArrayList<>();
|
||||
List<SelectableItem> selectedItems = new ArrayList<>();
|
||||
OsmandRegions osmandRegions = app.getRegions();
|
||||
for (IndexItem indexItem : multipleIndexItem.getAllIndexes()) {
|
||||
SelectableItem selectableItem = new SelectableItem();
|
||||
selectableItem.setTitle(indexItem.getVisibleName(app, osmandRegions, false));
|
||||
|
||||
String size = indexItem.getSizeDescription(app);
|
||||
String date = indexItem.getDate(dateFormat, showRemoteDate);
|
||||
String description = app.getString(R.string.ltr_or_rtl_combine_via_bold_point, size, date);
|
||||
selectableItem.setDescription(description);
|
||||
|
||||
selectableItem.setIconId(indexItem.getType().getIconResource());
|
||||
selectableItem.setObject(indexItem);
|
||||
allItems.add(selectableItem);
|
||||
|
||||
if (indexesToDownload.contains(indexItem)) {
|
||||
selectedItems.add(selectableItem);
|
||||
}
|
||||
}
|
||||
|
||||
final SelectMultipleItemsBottomSheet dialog =
|
||||
SelectMultipleItemsBottomSheet.showInstance(activity, allItems, selectedItems, true);
|
||||
|
||||
dialog.setSelectionUpdateListener(new SelectionUpdateListener() {
|
||||
@Override
|
||||
public void onSelectionUpdate() {
|
||||
dialog.setTitle(app.getString(R.string.welmode_download_maps));
|
||||
String total = app.getString(R.string.shared_string_total);
|
||||
double sizeToDownload = getDownloadSizeInMb(dialog.getSelectedItems());
|
||||
String size = DownloadItem.getFormattedMb(app, sizeToDownload);
|
||||
String description =
|
||||
app.getString(R.string.ltr_or_rtl_combine_via_colon, total, size);
|
||||
dialog.setDescription(description);
|
||||
String btnTitle = app.getString(R.string.shared_string_download);
|
||||
if (sizeToDownload > 0) {
|
||||
btnTitle = app.getString(R.string.ltr_or_rtl_combine_via_dash, btnTitle, size);
|
||||
}
|
||||
dialog.setConfirmButtonTitle(btnTitle);
|
||||
}
|
||||
});
|
||||
|
||||
dialog.setOnApplySelectionListener(new OnApplySelectionListener() {
|
||||
@Override
|
||||
public void onSelectionApplied(List<SelectableItem> selectedItems) {
|
||||
List<IndexItem> indexItems = new ArrayList<>();
|
||||
for (SelectableItem item : selectedItems) {
|
||||
Object obj = item.getObject();
|
||||
if (obj instanceof IndexItem) {
|
||||
indexItems.add((IndexItem) obj);
|
||||
}
|
||||
}
|
||||
listener.onItemsToDownloadSelected(indexItems);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static List<IndexItem> getIndexesToDownload(MultipleIndexItem multipleIndexItem) {
|
||||
if (multipleIndexItem.hasActualDataToDownload()) {
|
||||
// download left regions
|
||||
return multipleIndexItem.getIndexesToDownload();
|
||||
} else {
|
||||
// download all regions again
|
||||
return multipleIndexItem.getAllIndexes();
|
||||
}
|
||||
}
|
||||
|
||||
private static double getDownloadSizeInMb(@NonNull List<SelectableItem> selectableItems) {
|
||||
List<IndexItem> indexItems = new ArrayList<>();
|
||||
for (SelectableItem i : selectableItems) {
|
||||
Object obj = i.getObject();
|
||||
if (obj instanceof IndexItem) {
|
||||
indexItems.add((IndexItem) obj);
|
||||
}
|
||||
}
|
||||
double totalSizeMb = 0.0d;
|
||||
for (IndexItem item : indexItems) {
|
||||
totalSizeMb += item.getSizeToDownloadInMb();
|
||||
}
|
||||
return totalSizeMb;
|
||||
}
|
||||
|
||||
public interface SelectItemsToDownloadListener {
|
||||
void onItemsToDownloadSelected(List<IndexItem> items);
|
||||
}
|
||||
|
||||
}
|
330
OsmAnd/src/net/osmand/plus/download/SelectIndexesHelper.java
Normal file
330
OsmAnd/src/net/osmand/plus/download/SelectIndexesHelper.java
Normal file
|
@ -0,0 +1,330 @@
|
|||
package net.osmand.plus.download;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.base.MultipleSelectionBottomSheet;
|
||||
import net.osmand.plus.base.MultipleSelectionBottomSheet.SelectionUpdateListener;
|
||||
import net.osmand.plus.base.ModeSelectionBottomSheet;
|
||||
import net.osmand.plus.base.MultipleSelectionWithModeBottomSheet;
|
||||
import net.osmand.plus.base.SelectionBottomSheet;
|
||||
import net.osmand.plus.base.SelectionBottomSheet.OnApplySelectionListener;
|
||||
import net.osmand.plus.base.SelectionBottomSheet.DialogStateListener;
|
||||
import net.osmand.plus.base.SelectionBottomSheet.SelectableItem;
|
||||
import net.osmand.plus.widgets.multistatetoggle.RadioItem;
|
||||
import net.osmand.plus.widgets.multistatetoggle.RadioItem.OnRadioItemClickListener;
|
||||
import net.osmand.plus.widgets.multistatetoggle.TextToggleButton.TextRadioItem;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static net.osmand.plus.download.MultipleDownloadItem.getIndexItem;
|
||||
|
||||
public class SelectIndexesHelper {
|
||||
|
||||
private final OsmandApplication app;
|
||||
private final AppCompatActivity activity;
|
||||
|
||||
private final ItemsToDownloadSelectedListener listener;
|
||||
private final DateFormat dateFormat;
|
||||
private final boolean showRemoteDate;
|
||||
private final List<DownloadItem> itemsToDownload;
|
||||
private final DownloadItem downloadItem;
|
||||
private final boolean useMetricByDefault;
|
||||
|
||||
private SelectionBottomSheet dialog;
|
||||
|
||||
private SelectIndexesHelper(@NonNull DownloadItem downloadItem,
|
||||
@NonNull AppCompatActivity activity,
|
||||
@NonNull DateFormat dateFormat,
|
||||
boolean showRemoteDate,
|
||||
@NonNull ItemsToDownloadSelectedListener listener) {
|
||||
this.app = (OsmandApplication) activity.getApplicationContext();
|
||||
this.activity = activity;
|
||||
this.dateFormat = dateFormat;
|
||||
this.showRemoteDate = showRemoteDate;
|
||||
this.listener = listener;
|
||||
this.downloadItem = downloadItem;
|
||||
this.itemsToDownload = getItemsToDownload(downloadItem);
|
||||
this.useMetricByDefault = SrtmDownloadItem.isUseMetricByDefault(app);
|
||||
}
|
||||
|
||||
public static void showDialog(@NonNull DownloadItem di,
|
||||
@NonNull AppCompatActivity a,
|
||||
@NonNull DateFormat df,
|
||||
boolean showRemoteDate,
|
||||
@NonNull ItemsToDownloadSelectedListener l) {
|
||||
|
||||
SelectIndexesHelper h = new SelectIndexesHelper(di, a, df, showRemoteDate, l);
|
||||
if (di.getType() == DownloadActivityType.SRTM_COUNTRY_FILE) {
|
||||
if (di instanceof MultipleDownloadItem) {
|
||||
h.showSrtmMultipleSelectionDialog();
|
||||
} else {
|
||||
h.showSrtmTypeSelectionDialog();
|
||||
}
|
||||
} else if (di instanceof MultipleDownloadItem) {
|
||||
h.showMultipleSelectionDialog();
|
||||
}
|
||||
}
|
||||
|
||||
private void showMultipleSelectionDialog() {
|
||||
MultipleDownloadItem mdi = (MultipleDownloadItem) downloadItem;
|
||||
List<SelectableItem> allItems = new ArrayList<>();
|
||||
List<SelectableItem> selectedItems = new ArrayList<>();
|
||||
|
||||
for (DownloadItem di : mdi.getAllItems()) {
|
||||
SelectableItem si = createSelectableItem(di);
|
||||
allItems.add(si);
|
||||
if (itemsToDownload.contains(di)) {
|
||||
selectedItems.add(si);
|
||||
}
|
||||
}
|
||||
|
||||
MultipleSelectionBottomSheet msDialog =
|
||||
MultipleSelectionBottomSheet.showInstance(activity, allItems, selectedItems, true);
|
||||
this.dialog = msDialog;
|
||||
|
||||
msDialog.setDialogStateListener(new DialogStateListener() {
|
||||
@Override
|
||||
public void onDialogCreated() {
|
||||
dialog.setTitle(app.getString(R.string.welmode_download_maps));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseDialog() { }
|
||||
});
|
||||
|
||||
msDialog.setSelectionUpdateListener(new SelectionUpdateListener() {
|
||||
@Override
|
||||
public void onSelectionUpdate() {
|
||||
updateSize();
|
||||
}
|
||||
});
|
||||
|
||||
msDialog.setOnApplySelectionListener(getOnApplySelectionListener(listener));
|
||||
}
|
||||
|
||||
private void showSrtmMultipleSelectionDialog() {
|
||||
MultipleDownloadItem mdi = (MultipleDownloadItem) downloadItem;
|
||||
List<SelectableItem> allItems = new ArrayList<>();
|
||||
List<SelectableItem> selectedItems = new ArrayList<>();
|
||||
|
||||
for (DownloadItem di : mdi.getAllItems()) {
|
||||
SelectableItem si = createSrtmSelectableItem((SrtmDownloadItem) di);
|
||||
allItems.add(si);
|
||||
if (itemsToDownload.contains(di)) {
|
||||
selectedItems.add(si);
|
||||
}
|
||||
}
|
||||
|
||||
final RadioItem meterBtn = createSrtmRadioBtn(true);
|
||||
final RadioItem feetBtn = createSrtmRadioBtn(false);
|
||||
List<RadioItem> radioItems = new ArrayList<>();
|
||||
radioItems.add(meterBtn);
|
||||
radioItems.add(feetBtn);
|
||||
|
||||
MultipleSelectionBottomSheet msDialog = MultipleSelectionWithModeBottomSheet.showInstance(
|
||||
activity, allItems, selectedItems, radioItems, true);
|
||||
this.dialog = msDialog;
|
||||
|
||||
msDialog.setDialogStateListener(new DialogStateListener() {
|
||||
@Override
|
||||
public void onDialogCreated() {
|
||||
dialog.setTitle(app.getString(R.string.welmode_download_maps));
|
||||
dialog.setSelectedMode(useMetricByDefault ? meterBtn : feetBtn);
|
||||
dialog.setSecondaryDescription(app.getString(R.string.srtm_download_list_help_message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseDialog() {
|
||||
resetUseMeters();
|
||||
}
|
||||
});
|
||||
|
||||
msDialog.setSelectionUpdateListener(new SelectionUpdateListener() {
|
||||
@Override
|
||||
public void onSelectionUpdate() {
|
||||
updateSize();
|
||||
}
|
||||
});
|
||||
|
||||
msDialog.setOnApplySelectionListener(getOnApplySelectionListener(listener));
|
||||
}
|
||||
|
||||
private void showSrtmTypeSelectionDialog() {
|
||||
SrtmDownloadItem srtmItem = (SrtmDownloadItem) downloadItem;
|
||||
|
||||
final RadioItem meterBtn = createSrtmRadioBtn(true);
|
||||
final RadioItem feetBtn = createSrtmRadioBtn(false);
|
||||
List<RadioItem> radioItems = new ArrayList<>();
|
||||
radioItems.add(meterBtn);
|
||||
radioItems.add(feetBtn);
|
||||
|
||||
SelectableItem preview = createSrtmSelectableItem(srtmItem);
|
||||
|
||||
dialog = ModeSelectionBottomSheet.showInstance(activity, preview, radioItems, true);
|
||||
|
||||
dialog.setDialogStateListener(new DialogStateListener() {
|
||||
@Override
|
||||
public void onDialogCreated() {
|
||||
ModeSelectionBottomSheet dialog = (ModeSelectionBottomSheet) SelectIndexesHelper.this.dialog;
|
||||
dialog.setTitle(app.getString(R.string.srtm_unit_format));
|
||||
dialog.setPrimaryDescription(app.getString(R.string.srtm_download_single_help_message));
|
||||
updateSize();
|
||||
dialog.setSelectedMode(useMetricByDefault ? meterBtn : feetBtn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseDialog() {
|
||||
resetUseMeters();
|
||||
}
|
||||
});
|
||||
|
||||
dialog.setOnApplySelectionListener(getOnApplySelectionListener(listener));
|
||||
}
|
||||
|
||||
private RadioItem createSrtmRadioBtn(final boolean useMeters) {
|
||||
int titleId = useMeters ? R.string.shared_string_meters : R.string.shared_string_feet;
|
||||
String title = Algorithms.capitalizeFirstLetter(app.getString(titleId));
|
||||
RadioItem radioItem = new TextRadioItem(title);
|
||||
radioItem.setOnClickListener(new OnRadioItemClickListener() {
|
||||
@Override
|
||||
public boolean onRadioItemClick(RadioItem radioItem, View view) {
|
||||
setUseMetersForAllItems(useMeters);
|
||||
updateListItems();
|
||||
updateSize();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return radioItem;
|
||||
}
|
||||
|
||||
private SelectableItem createSelectableItem(DownloadItem item) {
|
||||
SelectableItem selectableItem = new SelectableItem();
|
||||
updateSelectableItem(selectableItem, item);
|
||||
selectableItem.setObject(item);
|
||||
return selectableItem;
|
||||
}
|
||||
|
||||
private SelectableItem createSrtmSelectableItem(SrtmDownloadItem item) {
|
||||
SelectableItem selectableItem = new SelectableItem();
|
||||
updateSelectableItem(selectableItem, item.getDefaultIndexItem());
|
||||
selectableItem.setObject(item);
|
||||
return selectableItem;
|
||||
}
|
||||
|
||||
private void updateListItems() {
|
||||
List<SelectableItem> items = new ArrayList<>(dialog.getAllItems());
|
||||
for (SelectableItem selectableItem : items) {
|
||||
DownloadItem di = (DownloadItem) selectableItem.getObject();
|
||||
if (di instanceof SrtmDownloadItem) {
|
||||
di = ((SrtmDownloadItem) di).getDefaultIndexItem();
|
||||
}
|
||||
updateSelectableItem(selectableItem, di);
|
||||
}
|
||||
dialog.setItems(items);
|
||||
}
|
||||
|
||||
private void resetUseMeters() {
|
||||
boolean useMeters = SrtmDownloadItem.isUseMetricByDefault(app);
|
||||
setUseMetersForAllItems(useMeters);
|
||||
}
|
||||
|
||||
private void setUseMetersForAllItems(boolean useMeters) {
|
||||
for (SelectableItem item : dialog.getAllItems()) {
|
||||
DownloadItem downloadItem = (DownloadItem) item.getObject();
|
||||
if (downloadItem instanceof SrtmDownloadItem) {
|
||||
SrtmDownloadItem srtmItem = (SrtmDownloadItem) downloadItem;
|
||||
srtmItem.setUseMetric(useMeters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSelectableItem(SelectableItem selectableItem,
|
||||
DownloadItem downloadItem) {
|
||||
selectableItem.setTitle(downloadItem.getVisibleName(app, app.getRegions(), false));
|
||||
|
||||
String size = downloadItem.getSizeDescription(app);
|
||||
String addDescr = downloadItem.getAdditionalDescription(app);
|
||||
if (addDescr != null) {
|
||||
size += " " + addDescr;
|
||||
}
|
||||
String date = downloadItem.getDate(dateFormat, showRemoteDate);
|
||||
String description = app.getString(R.string.ltr_or_rtl_combine_via_bold_point, size, date);
|
||||
selectableItem.setDescription(description);
|
||||
|
||||
selectableItem.setIconId(downloadItem.getType().getIconResource());
|
||||
}
|
||||
|
||||
private OnApplySelectionListener getOnApplySelectionListener(final ItemsToDownloadSelectedListener listener) {
|
||||
return new OnApplySelectionListener() {
|
||||
@Override
|
||||
public void onSelectionApplied(List<SelectableItem> selectedItems) {
|
||||
List<IndexItem> indexes = new ArrayList<>();
|
||||
for (SelectableItem item : selectedItems) {
|
||||
IndexItem index = getIndexItem((DownloadItem) item.getObject());
|
||||
if (index != null) {
|
||||
indexes.add(index);
|
||||
}
|
||||
}
|
||||
listener.onItemsToDownloadSelected(indexes);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void updateSize() {
|
||||
double sizeToDownload = getDownloadSizeInMb(dialog.getSelectedItems());
|
||||
String size = DownloadItem.getFormattedMb(app, sizeToDownload);
|
||||
String total = app.getString(R.string.shared_string_total);
|
||||
String description = app.getString(R.string.ltr_or_rtl_combine_via_colon, total, size);
|
||||
dialog.setTitleDescription(description);
|
||||
String btnTitle = app.getString(R.string.shared_string_download);
|
||||
if (sizeToDownload > 0) {
|
||||
btnTitle = app.getString(R.string.ltr_or_rtl_combine_via_dash, btnTitle, size);
|
||||
}
|
||||
dialog.setApplyButtonTitle(btnTitle);
|
||||
}
|
||||
|
||||
private double getDownloadSizeInMb(@NonNull List<SelectableItem> selectableItems) {
|
||||
double totalSizeMb = 0.0d;
|
||||
for (SelectableItem i : selectableItems) {
|
||||
Object obj = i.getObject();
|
||||
if (obj instanceof SrtmDownloadItem) {
|
||||
SrtmDownloadItem srtm = (SrtmDownloadItem) obj;
|
||||
totalSizeMb += srtm.getDefaultIndexItem().getSizeToDownloadInMb();
|
||||
} else if (obj instanceof DownloadItem) {
|
||||
totalSizeMb += ((DownloadItem) obj).getSizeToDownloadInMb();
|
||||
}
|
||||
}
|
||||
return totalSizeMb;
|
||||
}
|
||||
|
||||
private static List<DownloadItem> getItemsToDownload(DownloadItem di) {
|
||||
if (di instanceof MultipleDownloadItem) {
|
||||
return getItemsToDownload((MultipleDownloadItem) di);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static List<DownloadItem> getItemsToDownload(MultipleDownloadItem md) {
|
||||
if (md.hasActualDataToDownload()) {
|
||||
// download left regions
|
||||
return md.getItemsToDownload();
|
||||
} else {
|
||||
// download all regions again
|
||||
return md.getAllItems();
|
||||
}
|
||||
}
|
||||
|
||||
public interface ItemsToDownloadSelectedListener {
|
||||
void onItemsToDownloadSelected(List<IndexItem> items);
|
||||
}
|
||||
|
||||
}
|
196
OsmAnd/src/net/osmand/plus/download/SrtmDownloadItem.java
Normal file
196
OsmAnd/src/net/osmand/plus/download/SrtmDownloadItem.java
Normal file
|
@ -0,0 +1,196 @@
|
|||
package net.osmand.plus.download;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.activities.LocalIndexInfo;
|
||||
import net.osmand.plus.helpers.enums.MetricsConstants;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static net.osmand.IndexConstants.BINARY_SRTM_MAP_INDEX_EXT;
|
||||
import static net.osmand.IndexConstants.BINARY_SRTM_MAP_INDEX_EXT_ZIP;
|
||||
import static net.osmand.plus.activities.LocalIndexHelper.LocalIndexType.SRTM_DATA;
|
||||
import static net.osmand.plus.download.DownloadActivityType.SRTM_COUNTRY_FILE;
|
||||
|
||||
public class SrtmDownloadItem extends DownloadItem {
|
||||
|
||||
private final List<IndexItem> indexes;
|
||||
private boolean useMetric;
|
||||
|
||||
public SrtmDownloadItem(List<IndexItem> indexes, boolean useMetric) {
|
||||
super(SRTM_COUNTRY_FILE);
|
||||
this.indexes = indexes;
|
||||
this.useMetric = useMetric;
|
||||
}
|
||||
|
||||
public void setUseMetric(boolean useMetric) {
|
||||
this.useMetric = useMetric;
|
||||
}
|
||||
|
||||
public boolean isUseMetric() {
|
||||
for (IndexItem index : indexes) {
|
||||
if (index.isDownloaded()) {
|
||||
return isMetricItem(index);
|
||||
}
|
||||
}
|
||||
return useMetric;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public IndexItem getIndexItem() {
|
||||
for (IndexItem index : indexes) {
|
||||
if (index.isDownloaded()) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return getDefaultIndexItem();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public IndexItem getDefaultIndexItem() {
|
||||
for (IndexItem index : indexes) {
|
||||
if (useMetric && isMetricItem(index) || !useMetric && !isMetricItem(index)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return indexes.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double getSizeToDownloadInMb() {
|
||||
return getIndexItem().getSizeToDownloadInMb();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getArchiveSizeMB() {
|
||||
return getIndexItem().getArchiveSizeMB();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOutdated() {
|
||||
for (DownloadItem item : indexes) {
|
||||
if (item.isOutdated()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDownloaded() {
|
||||
for (DownloadItem item : indexes) {
|
||||
if (item.isDownloaded()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActualDataToDownload() {
|
||||
for (IndexItem item : indexes) {
|
||||
if (!item.hasActualDataToDownload()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDownloading(@NonNull DownloadIndexesThread thread) {
|
||||
for (IndexItem item : indexes) {
|
||||
if (thread.isDownloading(item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFileName() {
|
||||
return getIndexItem().getFileName();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public List<File> getDownloadedFiles(@NonNull OsmandApplication app) {
|
||||
List<File> result = new ArrayList<>();
|
||||
for (IndexItem index : indexes) {
|
||||
result.addAll(index.getDownloadedFiles(app));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getDate(@NonNull DateFormat dateFormat, boolean remote) {
|
||||
return getIndexItem().getDate(dateFormat, remote);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getAdditionalDescription(Context ctx) {
|
||||
return getAbbreviationInScopes(ctx, this);
|
||||
}
|
||||
|
||||
public static boolean isUseMetricByDefault(@NonNull OsmandApplication app) {
|
||||
MetricsConstants metricSystem = app.getSettings().METRIC_SYSTEM.get();
|
||||
return metricSystem != MetricsConstants.MILES_AND_FEET;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String getAbbreviationInScopes(Context ctx, Object obj) {
|
||||
String abbreviation = ctx.getString(isMetricItem(obj) ? R.string.m : R.string.foot);
|
||||
return "(" + abbreviation + ")";
|
||||
}
|
||||
|
||||
public static boolean containsSrtmExtension(@NonNull String fileName) {
|
||||
return fileName.contains(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)
|
||||
|| fileName.contains(IndexConstants.BINARY_SRTM_FEET_MAP_INDEX_EXT);
|
||||
}
|
||||
|
||||
public static boolean isSrtmFile(@NonNull String fileName) {
|
||||
return fileName.endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)
|
||||
|| fileName.endsWith(IndexConstants.BINARY_SRTM_FEET_MAP_INDEX_EXT);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String getExtension(IndexItem indexItem) {
|
||||
return isMetricItem(indexItem) ?
|
||||
IndexConstants.BINARY_SRTM_MAP_INDEX_EXT :
|
||||
IndexConstants.BINARY_SRTM_FEET_MAP_INDEX_EXT;
|
||||
}
|
||||
|
||||
public static boolean isSRTMItem(Object item) {
|
||||
if (item instanceof DownloadItem) {
|
||||
return ((DownloadItem) item).getType() == SRTM_COUNTRY_FILE;
|
||||
} else if (item instanceof LocalIndexInfo) {
|
||||
return ((LocalIndexInfo) item).getType() == SRTM_DATA;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isMetricItem(Object item) {
|
||||
if (item instanceof IndexItem) {
|
||||
return ((IndexItem) item).getFileName().endsWith(BINARY_SRTM_MAP_INDEX_EXT_ZIP);
|
||||
} else if (item instanceof LocalIndexInfo) {
|
||||
return ((LocalIndexInfo) item).getFileName().endsWith(BINARY_SRTM_MAP_INDEX_EXT);
|
||||
} else if (item instanceof SrtmDownloadItem) {
|
||||
return isMetricItem(((SrtmDownloadItem) item).getIndexItem());
|
||||
} else if (item instanceof MultipleDownloadItem) {
|
||||
List<DownloadItem> items = ((MultipleDownloadItem) item).getAllItems();
|
||||
if (!Algorithms.isEmpty(items)) {
|
||||
return isMetricItem(items.get(0));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -87,7 +87,7 @@ public class ActiveDownloadsDialogFragment extends DialogFragment implements Dow
|
|||
}
|
||||
ItemViewHolder viewHolder = (ItemViewHolder) convertView.getTag();
|
||||
IndexItem item = getItem(position);
|
||||
viewHolder.bindIndexItem(item);
|
||||
viewHolder.bindDownloadItem(item);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import android.content.DialogInterface;
|
|||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.StatFs;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -17,8 +16,6 @@ import android.widget.ImageView;
|
|||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.ibm.icu.impl.IllegalIcuArgumentException;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
|
@ -28,12 +25,12 @@ import net.osmand.IProgress;
|
|||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.plus.OnDismissDialogFragmentListener;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.base.BottomSheetDialogFragment;
|
||||
import net.osmand.plus.dashboard.DashChooseAppDirFragment;
|
||||
import net.osmand.plus.download.DownloadActivity;
|
||||
import net.osmand.plus.download.DownloadIndexesThread;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
|
@ -119,7 +116,7 @@ public class DataStoragePlaceDialogFragment extends BottomSheetDialogFragment {
|
|||
deviceStorageImageView.setImageDrawable(getContentIcon(R.drawable.ic_action_phone));
|
||||
TextView deviceStorageDescription = (TextView) view.findViewById(R.id.deviceMemoryDescription);
|
||||
deviceStorageDescription.setText(deviceStorageName);
|
||||
deviceStorageDescription.setText(getFreeSpace(deviceStorage));
|
||||
deviceStorageDescription.setText(AndroidUtils.getFreeSpace(activity, deviceStorage));
|
||||
|
||||
View sharedMemoryRow = view.findViewById(R.id.sharedMemoryRow);
|
||||
if (hasExternalStoragePermission && sharedStorage != null) {
|
||||
|
@ -127,7 +124,7 @@ public class DataStoragePlaceDialogFragment extends BottomSheetDialogFragment {
|
|||
ImageView sharedMemoryImageView = (ImageView) view.findViewById(R.id.sharedMemoryImageView);
|
||||
sharedMemoryImageView.setImageDrawable(getContentIcon(R.drawable.ic_action_phone));
|
||||
TextView sharedMemoryDescription = (TextView) view.findViewById(R.id.sharedMemoryDescription);
|
||||
sharedMemoryDescription.setText(getFreeSpace(sharedStorage));
|
||||
sharedMemoryDescription.setText(AndroidUtils.getFreeSpace(activity, sharedStorage));
|
||||
} else {
|
||||
view.findViewById(R.id.divSharedStorage).setVisibility(View.GONE);
|
||||
sharedMemoryRow.setVisibility(View.GONE);
|
||||
|
@ -139,7 +136,7 @@ public class DataStoragePlaceDialogFragment extends BottomSheetDialogFragment {
|
|||
ImageView memoryStickImageView = (ImageView) view.findViewById(R.id.memoryStickImageView);
|
||||
memoryStickImageView.setImageDrawable(getContentIcon(R.drawable.ic_sdcard));
|
||||
TextView memoryStickDescription = (TextView) view.findViewById(R.id.memoryStickDescription);
|
||||
memoryStickDescription.setText(getFreeSpace(cardStorage));
|
||||
memoryStickDescription.setText(AndroidUtils.getFreeSpace(activity, cardStorage));
|
||||
} else {
|
||||
view.findViewById(R.id.divExtStorage).setVisibility(View.GONE);
|
||||
memoryStickRow.setVisibility(View.GONE);
|
||||
|
@ -192,23 +189,6 @@ public class DataStoragePlaceDialogFragment extends BottomSheetDialogFragment {
|
|||
.getDefaultInternalStorage();
|
||||
}
|
||||
|
||||
private String getFreeSpace(File dir) {
|
||||
String sz = "";
|
||||
if (dir != null && dir.canRead()) {
|
||||
try {
|
||||
StatFs fs = new StatFs(dir.getAbsolutePath());
|
||||
@SuppressWarnings("deprecation")
|
||||
long size = (long) fs.getAvailableBlocks() * fs.getBlockSize();
|
||||
if (size > 0) {
|
||||
sz = AndroidUtils.formatSize(getActivity(), size);
|
||||
}
|
||||
} catch (IllegalIcuArgumentException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
private void checkAssets() {
|
||||
getMyApplication().getResourceManager().checkAssets(IProgress.EMPTY_PROGRESS, true);
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ public class DownloadResourceGroupAdapter extends OsmandBaseExpandableListAdapte
|
|||
} else {
|
||||
viewHolder.setShowTypeInDesc(true);
|
||||
}
|
||||
viewHolder.bindIndexItem(item);
|
||||
viewHolder.bindDownloadItem(item);
|
||||
} else {
|
||||
DownloadResourceGroup group = (DownloadResourceGroup) child;
|
||||
DownloadGroupViewHolder viewHolder;
|
||||
|
|
|
@ -41,9 +41,9 @@ import net.osmand.plus.download.DownloadActivityType;
|
|||
import net.osmand.plus.download.DownloadResourceGroup;
|
||||
import net.osmand.plus.download.DownloadResources;
|
||||
import net.osmand.plus.download.IndexItem;
|
||||
import net.osmand.plus.download.MultipleIndexesUiHelper;
|
||||
import net.osmand.plus.download.MultipleIndexesUiHelper.SelectItemsToDownloadListener;
|
||||
import net.osmand.plus.download.MultipleIndexItem;
|
||||
import net.osmand.plus.download.SelectIndexesHelper;
|
||||
import net.osmand.plus.download.SelectIndexesHelper.ItemsToDownloadSelectedListener;
|
||||
import net.osmand.plus.download.MultipleDownloadItem;
|
||||
import net.osmand.plus.download.ui.LocalIndexesFragment.LocalIndexOperationTask;
|
||||
import net.osmand.plus.helpers.FileNameTranslationHelper;
|
||||
import net.osmand.plus.inapp.InAppPurchaseHelper;
|
||||
|
@ -146,11 +146,11 @@ public class ItemViewHolder {
|
|||
depthContoursPurchased = InAppPurchaseHelper.isDepthContoursPurchased(context.getMyApplication());
|
||||
}
|
||||
|
||||
public void bindIndexItem(final DownloadItem downloadItem) {
|
||||
bindIndexItem(downloadItem, null);
|
||||
public void bindDownloadItem(final DownloadItem downloadItem) {
|
||||
bindDownloadItem(downloadItem, null);
|
||||
}
|
||||
|
||||
public void bindIndexItem(final DownloadItem downloadItem, final String cityName) {
|
||||
public void bindDownloadItem(final DownloadItem downloadItem, final String cityName) {
|
||||
initAppStatusVariables();
|
||||
boolean isDownloading = downloadItem.isDownloading(context.getDownloadThread());
|
||||
int progress = -1;
|
||||
|
@ -203,12 +203,12 @@ public class ItemViewHolder {
|
|||
} else {
|
||||
descrTextView.setText(downloadItem.getType().getString(context));
|
||||
}
|
||||
} else if (downloadItem instanceof MultipleIndexItem) {
|
||||
MultipleIndexItem item = (MultipleIndexItem) downloadItem;
|
||||
} else if (downloadItem instanceof MultipleDownloadItem) {
|
||||
MultipleDownloadItem item = (MultipleDownloadItem) downloadItem;
|
||||
String allRegionsHeader = context.getString(R.string.shared_strings_all_regions);
|
||||
String regionsHeader = context.getString(R.string.regions);
|
||||
String allRegionsCount = String.valueOf(item.getAllIndexes().size());
|
||||
String leftToDownloadCount = String.valueOf(item.getIndexesToDownload().size());
|
||||
String allRegionsCount = String.valueOf(item.getAllItems().size());
|
||||
String leftToDownloadCount = String.valueOf(item.getItemsToDownload().size());
|
||||
String header;
|
||||
String count;
|
||||
if (item.hasActualDataToDownload()) {
|
||||
|
@ -226,8 +226,11 @@ public class ItemViewHolder {
|
|||
header = allRegionsHeader;
|
||||
count = allRegionsCount;
|
||||
}
|
||||
String fullDescription =
|
||||
context.getString(R.string.ltr_or_rtl_combine_via_colon, header, count);
|
||||
String fullDescription = context.getString(R.string.ltr_or_rtl_combine_via_colon, header, count);
|
||||
String addDescr = item.getAdditionalDescription(context);
|
||||
if (addDescr != null) {
|
||||
fullDescription += " " + addDescr;
|
||||
}
|
||||
if (item.hasActualDataToDownload()) {
|
||||
fullDescription = context.getString(
|
||||
R.string.ltr_or_rtl_combine_via_bold_point, fullDescription,
|
||||
|
@ -235,11 +238,14 @@ public class ItemViewHolder {
|
|||
}
|
||||
descrTextView.setText(fullDescription);
|
||||
} else {
|
||||
IndexItem item = (IndexItem) downloadItem;
|
||||
String pattern = context.getString(R.string.ltr_or_rtl_combine_via_bold_point);
|
||||
String type = item.getType().getString(context);
|
||||
String size = item.getSizeDescription(context);
|
||||
String date = item.getDate(dateFormat, showRemoteDate);
|
||||
String type = downloadItem.getType().getString(context);
|
||||
String size = downloadItem.getSizeDescription(context);
|
||||
String addDescr = downloadItem.getAdditionalDescription(context);
|
||||
if (addDescr != null) {
|
||||
size += " " + addDescr;
|
||||
}
|
||||
String date = downloadItem.getDate(dateFormat, showRemoteDate);
|
||||
String fullDescription = String.format(pattern, size, date);
|
||||
if (showTypeInDesc) {
|
||||
fullDescription = String.format(pattern, type, fullDescription);
|
||||
|
@ -274,9 +280,9 @@ public class ItemViewHolder {
|
|||
}
|
||||
}
|
||||
|
||||
public void bindIndexItem(final CityItem cityItem) {
|
||||
public void bindDownloadItem(final CityItem cityItem) {
|
||||
if (cityItem.getIndexItem() != null) {
|
||||
bindIndexItem(cityItem.getIndexItem(), cityItem.getName());
|
||||
bindDownloadItem(cityItem.getIndexItem(), cityItem.getName());
|
||||
} else {
|
||||
nameTextView.setText(cityItem.getName());
|
||||
nameTextView.setTextColor(textColorPrimary);
|
||||
|
@ -316,9 +322,9 @@ public class ItemViewHolder {
|
|||
}
|
||||
|
||||
private int getDownloadActionIconId(@NonNull DownloadItem item) {
|
||||
return item instanceof MultipleIndexItem ?
|
||||
return item instanceof MultipleDownloadItem ?
|
||||
R.drawable.ic_action_multi_download :
|
||||
R.drawable.ic_action_import;
|
||||
R.drawable.ic_action_gsave_dark;
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
|
@ -459,6 +465,7 @@ public class ItemViewHolder {
|
|||
startDownload(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void confirmDownload(final DownloadItem item) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(R.string.are_you_sure);
|
||||
|
@ -476,18 +483,17 @@ public class ItemViewHolder {
|
|||
}
|
||||
|
||||
private void startDownload(DownloadItem item) {
|
||||
if (item instanceof MultipleIndexItem) {
|
||||
selectIndexesToDownload((MultipleIndexItem) item);
|
||||
} else if (item instanceof IndexItem) {
|
||||
if (item instanceof IndexItem) {
|
||||
IndexItem indexItem = (IndexItem) item;
|
||||
context.startDownload(indexItem);
|
||||
} else {
|
||||
selectIndexesToDownload(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void selectIndexesToDownload(MultipleIndexItem item) {
|
||||
OsmandApplication app = context.getMyApplication();
|
||||
MultipleIndexesUiHelper.showDialog(item, context, app, dateFormat, showRemoteDate,
|
||||
new SelectItemsToDownloadListener() {
|
||||
private void selectIndexesToDownload(DownloadItem item) {
|
||||
SelectIndexesHelper.showDialog(item, context, dateFormat, showRemoteDate,
|
||||
new ItemsToDownloadSelectedListener() {
|
||||
@Override
|
||||
public void onItemsToDownloadSelected(List<IndexItem> indexes) {
|
||||
IndexItem[] indexesArray = new IndexItem[indexes.size()];
|
||||
|
|
|
@ -55,6 +55,7 @@ import net.osmand.plus.dialogs.DirectionsDialogs;
|
|||
import net.osmand.plus.download.DownloadActivity;
|
||||
import net.osmand.plus.download.DownloadIndexesThread.DownloadEvents;
|
||||
import net.osmand.plus.download.IndexItem;
|
||||
import net.osmand.plus.download.SrtmDownloadItem;
|
||||
import net.osmand.plus.helpers.FileNameTranslationHelper;
|
||||
import net.osmand.plus.inapp.InAppPurchaseHelper;
|
||||
import net.osmand.plus.mapsource.EditMapSourceDialogFragment.OnMapSourceUpdateListener;
|
||||
|
@ -74,6 +75,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class LocalIndexesFragment extends OsmandExpandableListFragment implements DownloadEvents,
|
||||
OnMapSourceUpdateListener, RenameCallback {
|
||||
private LoadLocalIndexTask asyncLoader;
|
||||
|
@ -963,7 +965,7 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
|
|||
return ctx.getString(R.string.download_roads_only_item);
|
||||
} else if (child.isBackupedData() && child.getFileName().endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) {
|
||||
return ctx.getString(R.string.download_wikipedia_maps);
|
||||
} else if (child.isBackupedData() && child.getFileName().endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)) {
|
||||
} else if (child.isBackupedData() && (SrtmDownloadItem.isSrtmFile(child.getFileName()))) {
|
||||
return ctx.getString(R.string.download_srtm_maps);
|
||||
}
|
||||
return "";
|
||||
|
@ -1029,6 +1031,10 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
|
|||
builder.append(AndroidUtils.formatSize(ctx, child.getSize() * 1024l));
|
||||
}
|
||||
|
||||
if (SrtmDownloadItem.isSRTMItem(child)) {
|
||||
builder.append(" ").append(SrtmDownloadItem.getAbbreviationInScopes(ctx, child));
|
||||
}
|
||||
|
||||
if (!Algorithms.isEmpty(child.getDescription())) {
|
||||
if (builder.length() > 0) {
|
||||
builder.append(" • ");
|
||||
|
@ -1150,5 +1156,4 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
|
|||
private DownloadActivity getDownloadActivity() {
|
||||
return (DownloadActivity) getActivity();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -382,10 +382,10 @@ public class SearchDialogFragment extends DialogFragment implements DownloadEven
|
|||
if (obj instanceof IndexItem) {
|
||||
IndexItem item = (IndexItem) obj;
|
||||
viewHolder.setShowTypeInDesc(true);
|
||||
viewHolder.bindIndexItem(item);
|
||||
viewHolder.bindDownloadItem(item);
|
||||
} else {
|
||||
CityItem item = (CityItem) obj;
|
||||
viewHolder.bindIndexItem(item);
|
||||
viewHolder.bindDownloadItem(item);
|
||||
if (item.getIndexItem() == null) {
|
||||
new IndexItemResolverTask(viewHolder, item).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
@ -461,7 +461,7 @@ public class SearchDialogFragment extends DialogFragment implements DownloadEven
|
|||
if (viewHolder != null) {
|
||||
if (indexItem != null) {
|
||||
cityItem.setIndexItem(indexItem);
|
||||
viewHolder.bindIndexItem(indexItem, cityItem.getName());
|
||||
viewHolder.bindDownloadItem(indexItem, cityItem.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -410,7 +410,7 @@ public class UpdatesIndexFragment extends OsmAndListFragment implements Download
|
|||
holder.setShowRemoteDate(true);
|
||||
holder.setShowTypeInDesc(true);
|
||||
holder.setShowParentRegionName(true);
|
||||
holder.bindIndexItem(getItem(position));
|
||||
holder.bindDownloadItem(getItem(position));
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import android.content.DialogInterface;
|
|||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.StatFs;
|
||||
import android.provider.Settings.Secure;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -37,7 +36,6 @@ import net.osmand.plus.AppInitializer.AppInitializeListener;
|
|||
import net.osmand.plus.OsmAndLocationProvider;
|
||||
import net.osmand.plus.OsmAndLocationProvider.OsmAndLocationListener;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.Version;
|
||||
import net.osmand.plus.activities.MapActivity;
|
||||
|
@ -51,12 +49,12 @@ import net.osmand.plus.download.IndexItem;
|
|||
import net.osmand.plus.download.ui.DataStoragePlaceDialogFragment;
|
||||
import net.osmand.plus.helpers.AndroidUiHelper;
|
||||
import net.osmand.plus.resources.ResourceManager;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.util.Algorithms;
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
|
@ -697,7 +695,7 @@ public class FirstUsageWizardFragment extends BaseOsmAndFragment implements OsmA
|
|||
TextView freeSpaceValue = (TextView) storageView.findViewById(R.id.storage_free_space_value);
|
||||
String freeSpaceStr = getString(R.string.storage_free_space) + ": ";
|
||||
freeSpace.setText(freeSpaceStr);
|
||||
freeSpaceValue.setText(getFreeSpace(settings.getExternalStorageDirectory()));
|
||||
freeSpaceValue.setText(AndroidUtils.getFreeSpace(storageView.getContext(), settings.getExternalStorageDirectory()));
|
||||
|
||||
AppCompatButton changeStorageButton = (AppCompatButton) storageView.findViewById(R.id.storage_change_button);
|
||||
if (wizardType == WizardType.MAP_DOWNLOAD) {
|
||||
|
@ -737,18 +735,6 @@ public class FirstUsageWizardFragment extends BaseOsmAndFragment implements OsmA
|
|||
}
|
||||
}
|
||||
|
||||
private String getFreeSpace(File dir) {
|
||||
if (dir.canRead()) {
|
||||
try {
|
||||
StatFs fs = new StatFs(dir.getAbsolutePath());
|
||||
return AndroidUtils.formatSize(getActivity(), (long) fs.getAvailableBlocks() * fs.getBlockSize());
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static void showSearchLocationFragment(FragmentActivity activity, boolean searchByIp) {
|
||||
Fragment fragment = new FirstUsageWizardFragment();
|
||||
Bundle args = new Bundle();
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package net.osmand.plus.helpers;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.map.OsmandRegions;
|
||||
import net.osmand.map.WorldRegion;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.download.DownloadResources;
|
||||
|
@ -19,6 +21,7 @@ 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 WIKIVOYAGE_NAME = "_wikivoyage";
|
||||
public static final String HILL_SHADE = "Hillshade";
|
||||
public static final String SLOPE = "Slope";
|
||||
public static final String SEA_DEPTH = "Depth_";
|
||||
|
@ -31,6 +34,8 @@ public class FileNameTranslationHelper {
|
|||
String basename = getBasename(fileName);
|
||||
if (basename.endsWith(WIKI_NAME)) { //wiki files
|
||||
return getWikiName(ctx, basename);
|
||||
} else if (basename.endsWith(WIKIVOYAGE_NAME)) {
|
||||
return getWikivoyageName(ctx, basename);
|
||||
} else if (fileName.endsWith("tts")) { //tts files
|
||||
return getVoiceName(ctx, fileName);
|
||||
} else if (fileName.endsWith(IndexConstants.FONT_INDEX_EXT)) { //otf files
|
||||
|
@ -90,6 +95,17 @@ public class FileNameTranslationHelper {
|
|||
return wikiName + " " + ctx.getString(R.string.amenity_type_osmwiki);
|
||||
}
|
||||
|
||||
public static String getWikivoyageName(Context ctx, String basename) {
|
||||
String formattedName = basename.substring(0, basename.indexOf(WIKIVOYAGE_NAME)).replaceAll("-", "").replaceAll("all", "");
|
||||
String wikiVoyageName = getSuggestedWikivoyageMaps(ctx, formattedName);
|
||||
if (wikiVoyageName == null) {
|
||||
wikiVoyageName = formattedName;
|
||||
}
|
||||
String wikiVoyageWord = ctx.getString(R.string.shared_string_wikivoyage);
|
||||
|
||||
return ctx.getString(R.string.ltr_or_rtl_combine_via_space, wikiVoyageName, wikiVoyageWord);
|
||||
}
|
||||
|
||||
public static String getVoiceName(Context ctx, String fileName) {
|
||||
try {
|
||||
String nm = fileName.replace('-', '_').replace(' ', '_');
|
||||
|
@ -245,4 +261,27 @@ public class FileNameTranslationHelper {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getSuggestedWikivoyageMaps(Context ctx, String filename) {
|
||||
if (WorldRegion.AFRICA_REGION_ID.equalsIgnoreCase(filename)) {
|
||||
return ctx.getString(R.string.index_name_africa);
|
||||
} else if (WorldRegion.AUSTRALIA_AND_OCEANIA_REGION_ID.replaceAll("-", "").equalsIgnoreCase(filename)) {
|
||||
return ctx.getString(R.string.index_name_oceania);
|
||||
} else if (WorldRegion.ASIA_REGION_ID.equalsIgnoreCase(filename)) {
|
||||
return ctx.getString(R.string.index_name_asia);
|
||||
} else if (WorldRegion.CENTRAL_AMERICA_REGION_ID.equalsIgnoreCase(filename)) {
|
||||
return ctx.getString(R.string.index_name_central_america);
|
||||
} else if (WorldRegion.EUROPE_REGION_ID.equalsIgnoreCase(filename)) {
|
||||
return ctx.getString(R.string.index_name_europe);
|
||||
} else if (WorldRegion.RUSSIA_REGION_ID.equalsIgnoreCase(filename)) {
|
||||
return ctx.getString(R.string.index_name_russia);
|
||||
} else if (WorldRegion.NORTH_AMERICA_REGION_ID.equalsIgnoreCase(filename)) {
|
||||
return ctx.getString(R.string.index_name_north_america);
|
||||
} else if (WorldRegion.SOUTH_AMERICA_REGION_ID.equalsIgnoreCase(filename)) {
|
||||
return ctx.getString(R.string.index_name_south_america);
|
||||
} else if (WorldRegion.ANTARCTICA_REGION_ID.equalsIgnoreCase(filename)) {
|
||||
return ctx.getString(R.string.index_name_antarctica);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ import net.osmand.plus.ContextMenuItem;
|
|||
import net.osmand.plus.GPXDatabase.GpxDataItem;
|
||||
import net.osmand.plus.GpxDbHelper;
|
||||
import net.osmand.plus.GpxDbHelper.GpxDataItemCallback;
|
||||
import net.osmand.plus.GpxSelectionHelper;
|
||||
import net.osmand.plus.GpxSelectionHelper.GpxDisplayGroup;
|
||||
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
|
||||
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
|
||||
|
@ -2228,18 +2229,19 @@ public class GpxUiHelper {
|
|||
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);
|
||||
public static GpxDisplayItem makeGpxDisplayItem(OsmandApplication app, GPXFile gpxFile) {
|
||||
GpxSelectionHelper helper = app.getSelectedGpxHelper();
|
||||
String groupName = helper.getGroupName(gpxFile);
|
||||
GpxDisplayGroup group = helper.buildGpxDisplayGroup(gpxFile, 0, groupName);
|
||||
if (group != null && group.getModifiableList().size() > 0) {
|
||||
gpxItem = group.getModifiableList().get(0);
|
||||
GpxDisplayItem gpxItem = group.getModifiableList().get(0);
|
||||
if (gpxItem != null) {
|
||||
gpxItem.route = true;
|
||||
}
|
||||
}
|
||||
return gpxItem;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void saveAndShareGpx(@NonNull final Context context, @NonNull final GPXFile gpxFile) {
|
||||
OsmandApplication app = (OsmandApplication) context.getApplicationContext();
|
||||
|
|
|
@ -8,6 +8,7 @@ import androidx.fragment.app.FragmentActivity;
|
|||
import net.osmand.GPXUtilities.GPXFile;
|
||||
import net.osmand.data.FavouritePoint;
|
||||
import net.osmand.plus.FavouritesDbHelper;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.base.BaseLoadAsyncTask;
|
||||
|
||||
|
@ -17,7 +18,7 @@ import static net.osmand.plus.importfiles.ImportHelper.asFavourites;
|
|||
import static net.osmand.plus.myplaces.FavoritesActivity.FAV_TAB;
|
||||
import static net.osmand.plus.myplaces.FavoritesActivity.TAB_ID;
|
||||
|
||||
class FavoritesImportTask extends BaseLoadAsyncTask<Void, Void, GPXFile> {
|
||||
public class FavoritesImportTask extends BaseLoadAsyncTask<Void, Void, GPXFile> {
|
||||
|
||||
private GPXFile gpxFile;
|
||||
private String fileName;
|
||||
|
@ -33,6 +34,12 @@ class FavoritesImportTask extends BaseLoadAsyncTask<Void, Void, GPXFile> {
|
|||
|
||||
@Override
|
||||
protected GPXFile doInBackground(Void... nothing) {
|
||||
mergeFavorites(app, gpxFile, fileName, forceImportFavourites);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void mergeFavorites(@NonNull OsmandApplication app, @NonNull GPXFile gpxFile,
|
||||
@NonNull String fileName, boolean forceImportFavourites) {
|
||||
List<FavouritePoint> favourites = asFavourites(app, gpxFile.getPoints(), fileName, forceImportFavourites);
|
||||
FavouritesDbHelper favoritesHelper = app.getFavorites();
|
||||
checkDuplicateNames(favourites);
|
||||
|
@ -42,10 +49,9 @@ class FavoritesImportTask extends BaseLoadAsyncTask<Void, Void, GPXFile> {
|
|||
}
|
||||
favoritesHelper.sortAll();
|
||||
favoritesHelper.saveCurrentPointsIntoFile();
|
||||
return null;
|
||||
}
|
||||
|
||||
public void checkDuplicateNames(List<FavouritePoint> favourites) {
|
||||
public static void checkDuplicateNames(List<FavouritePoint> favourites) {
|
||||
for (FavouritePoint fp : favourites) {
|
||||
int number = 1;
|
||||
String index;
|
||||
|
|
|
@ -10,7 +10,7 @@ import android.util.Log;
|
|||
|
||||
import net.osmand.AndroidNetworkUtils;
|
||||
import net.osmand.AndroidNetworkUtils.OnRequestResultListener;
|
||||
import net.osmand.AndroidNetworkUtils.OnRequestsResultListener;
|
||||
import net.osmand.AndroidNetworkUtils.OnSendRequestsListener;
|
||||
import net.osmand.AndroidNetworkUtils.RequestResponse;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
|
@ -608,9 +608,14 @@ public abstract class InAppPurchaseHelper {
|
|||
addUserInfo(parameters);
|
||||
requests.add(new AndroidNetworkUtils.Request(url, parameters, userOperation, true, true));
|
||||
}
|
||||
AndroidNetworkUtils.sendRequestsAsync(ctx, requests, new OnRequestsResultListener() {
|
||||
AndroidNetworkUtils.sendRequestsAsync(ctx, requests, new OnSendRequestsListener() {
|
||||
|
||||
@Override
|
||||
public void onResult(@NonNull List<RequestResponse> results) {
|
||||
public void onRequestSent(@NonNull RequestResponse response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestsSent(@NonNull List<RequestResponse> results) {
|
||||
for (RequestResponse rr : results) {
|
||||
String sku = rr.getRequest().getParameters().get("sku");
|
||||
PurchaseInfo info = getPurchaseInfo(sku);
|
||||
|
|
|
@ -282,6 +282,9 @@ public class LiveUpdatesFragment extends BaseOsmAndDialogFragment implements OnL
|
|||
dismiss();
|
||||
}
|
||||
});
|
||||
if (closeButton instanceof ImageView) {
|
||||
UiUtilities.rotateImageByLayoutDirection((ImageView) closeButton);
|
||||
}
|
||||
|
||||
FrameLayout iconHelpContainer = toolbar.findViewById(R.id.action_button);
|
||||
int iconColorResId = nightMode ? R.color.active_buttons_and_links_text_dark : R.color.active_buttons_and_links_text_light;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue