Merge pull request #11484 from osmandapp/master

update test branch
This commit is contained in:
Hardy 2021-04-21 08:44:23 +02:00 committed by GitHub
commit 7d5c0daa77
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
131 changed files with 9095 additions and 2695 deletions

View file

@ -16,13 +16,11 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@ -183,7 +181,9 @@ public abstract class MapObject implements Comparable<MapObject> {
public String getName(String lang, boolean transliterate) { public String getName(String lang, boolean transliterate) {
if (lang != null && lang.length() > 0) { if (lang != null && lang.length() > 0) {
if (lang.equals("en")) { 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 { } else {
// get name // get name
if (names != null) { if (names != null) {

View file

@ -5,8 +5,11 @@ import net.osmand.data.QuadRect;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set;
public class WorldRegion implements Serializable { public class WorldRegion implements Serializable {
@ -212,4 +215,22 @@ public class WorldRegion implements Serializable {
} }
return false; 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;
}
} }

View file

@ -55,7 +55,9 @@ public class SearchResult {
public double getSumPhraseMatchWeight() { public double getSumPhraseMatchWeight() {
// if result is a complete match in the search we prioritize it higher // 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); double res = ObjectType.getTypeWeight(match ? objectType : null);
if (parentSearchResult != null) { if (parentSearchResult != null) {
res = res + parentSearchResult.getSumPhraseMatchWeight() / MAX_TYPE_WEIGHT; res = res + parentSearchResult.getSumPhraseMatchWeight() / MAX_TYPE_WEIGHT;

View file

@ -80,9 +80,9 @@ public class SearchUICoreTest {
if (files != null) { if (files != null) {
for (File file : files) { for (File file : files) {
String fileName = file.getName(); String fileName = file.getName();
if(fileName.endsWith(".json")) { if (fileName.endsWith(".json")) {
String name = fileName.substring(0, fileName.length() - ".json".length()); String name = fileName.substring(0, fileName.length() - ".json".length());
arrayList.add(new Object[] {name, file}); arrayList.add(new Object[] { name, file });
} }
} }
} }
@ -191,10 +191,10 @@ public class SearchUICoreTest {
if (!Algorithms.stringsEqual(expected, present)) { if (!Algorithms.stringsEqual(expected, present)) {
System.out.println(String.format("Phrase: %s", phrase)); System.out.println(String.format("Phrase: %s", phrase));
System.out.println(String.format("Mismatch for '%s' != '%s'. Result: ", expected, present)); System.out.println(String.format("Mismatch for '%s' != '%s'. Result: ", expected, present));
}
for (SearchResult r : searchResults) { for (SearchResult r : searchResults) {
System.out.println(String.format("\t\"%s\",", formatResult(false, r, phrase))); System.out.println(String.format("\t\"%s\",", formatResult(false, r, phrase)));
} }
}
Assert.assertEquals(expected, present); Assert.assertEquals(expected, present);
} }
} }

View file

@ -119,4 +119,28 @@
<string name="connecting_to_the_internet">Konektante al Interreto</string> <string name="connecting_to_the_internet">Konektante al Interreto</string>
<string name="initializing">Komencante</string> <string name="initializing">Komencante</string>
<string name="sending_location_messages">Sendante lokon</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> </resources>

View file

@ -22,7 +22,7 @@
<string name="proxy_port">ポート</string> <string name="proxy_port">ポート</string>
<string name="proxy_server">サーバー</string> <string name="proxy_server">サーバー</string>
<string name="shared_string_connection">接続</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_type">プロキシタイプ</string>
<string name="proxy_connected">接続しました</string> <string name="proxy_connected">接続しました</string>
<string name="proxy_disconnected">切断しました</string> <string name="proxy_disconnected">切断しました</string>

View file

@ -16,20 +16,34 @@
android:focusable="true" android:focusable="true"
android:orientation="vertical" android:orientation="vertical"
android:clickable="true" android:clickable="true"
tools:background="@drawable/bg_bottom_menu_dark"> tools:ignore="UselessParent">
<ProgressBar <FrameLayout
android:id="@+id/snap_to_road_progress_bar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content">
android:minHeight="0dp"
android:visibility="gone" <View
tools:visibility="visible" /> 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"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="0dp"
android:background="?attr/list_background_color"
android:visibility="invisible"
tools:visibility="visible" />
</FrameLayout>
<LinearLayout <LinearLayout
android:id="@+id/main_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:background="?attr/list_background_color">
<RelativeLayout <RelativeLayout
android:id="@+id/up_down_row" android:id="@+id/up_down_row"
@ -53,6 +67,19 @@
android:background="@null" android:background="@null"
tools:src="@drawable/ic_action_ruler"/> 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 <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/up_down_button" android:id="@+id/up_down_button"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -65,6 +92,7 @@
android:layout_marginRight="@dimen/bottom_sheet_content_margin" android:layout_marginRight="@dimen/bottom_sheet_content_margin"
android:layout_marginStart="@dimen/bottom_sheet_content_margin" android:layout_marginStart="@dimen/bottom_sheet_content_margin"
android:background="@null" android:background="@null"
android:visibility="gone"
tools:src="@drawable/ic_action_arrow_down"/> tools:src="@drawable/ic_action_arrow_down"/>
<TextView <TextView

View file

@ -659,6 +659,7 @@
<!-- CENTER --> <!-- CENTER -->
<FrameLayout <FrameLayout
android:id="@+id/top_controls_container"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">

View 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>

View 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>

View file

@ -13,293 +13,314 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom" android:layout_gravity="bottom"
android:background="@drawable/bg_bottom_menu_dark"
android:orientation="vertical" android:orientation="vertical"
android:clickable="true" android:clickable="true"
android:focusable="true"> android:focusable="true"
tools:ignore="UselessParent">
<ProgressBar
android:id="@+id/snap_to_road_progress_bar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="0dp"
android:visibility="gone"
tools:visibility="visible" />
<RelativeLayout
android:id="@+id/up_down_row"
android:layout_width="match_parent"
android:layout_height="@dimen/measurement_tool_up_down_row_height"
android:background="?attr/selectableItemBackground">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/main_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/measurement_tool_text_button_padding"
android:layout_marginLeft="@dimen/measurement_tool_text_button_padding"
android:layout_marginRight="@dimen/measurement_tool_text_button_padding"
android:layout_marginStart="@dimen/measurement_tool_text_button_padding"
android:background="@null"
tools:src="@drawable/ic_action_ruler"/>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/up_down_button"
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/bottom_sheet_content_margin"
android:layout_marginLeft="@dimen/bottom_sheet_content_margin"
android:layout_marginRight="@dimen/bottom_sheet_content_margin"
android:layout_marginStart="@dimen/bottom_sheet_content_margin"
android:background="@null"
tools:src="@drawable/ic_action_arrow_down"/>
<TextView
android:id="@+id/measurement_distance_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/measurement_tool_button_padding"
android:layout_marginEnd="@dimen/text_margin_small"
android:layout_marginLeft="@dimen/measurement_tool_text_button_padding"
android:layout_marginRight="@dimen/text_margin_small"
android:layout_marginStart="@dimen/measurement_tool_text_button_padding"
android:layout_toEndOf="@id/main_icon"
android:layout_toRightOf="@id/main_icon"
android:textAppearance="@style/TextAppearance.ListItemCategoryTitle"
tools:text="724 m,"/>
<TextView
android:id="@+id/measurement_points_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/measurement_tool_button_padding"
android:layout_toEndOf="@id/measurement_distance_text_view"
android:layout_toRightOf="@id/measurement_distance_text_view"
android:layout_alignEnd="@id/up_down_button"
android:layout_alignRight="@id/up_down_button"
android:textAppearance="@style/TextAppearance.ListItemCategoryTitle"
tools:text="points: 3" />
<TextView
android:id="@+id/distance_to_center_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/measurement_points_text_view"
android:layout_alignStart="@+id/measurement_distance_text_view"
android:layout_alignLeft="@+id/measurement_distance_text_view"
android:maxLines="1"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
tools:text=" 700 m" />
<TextView
android:id="@+id/move_point_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/text_margin_small"
android:layout_marginLeft="@dimen/measurement_tool_text_margin"
android:layout_marginRight="@dimen/text_margin_small"
android:layout_marginStart="@dimen/measurement_tool_text_margin"
android:layout_toEndOf="@id/main_icon"
android:layout_toRightOf="@id/main_icon"
android:text="@string/move_point"
android:textAppearance="@style/TextAppearance.ListItemTitle"
android:visibility="gone"/>
<TextView
android:id="@+id/add_point_before_after_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/text_margin_small"
android:layout_marginLeft="@dimen/measurement_tool_text_margin"
android:layout_marginRight="@dimen/text_margin_small"
android:layout_marginStart="@dimen/measurement_tool_text_margin"
android:layout_toEndOf="@id/main_icon"
android:layout_toRightOf="@id/main_icon"
android:textAppearance="@style/TextAppearance.ListItemTitle"
android:visibility="gone"
tools:text="@string/add_point_after"/>
</RelativeLayout>
<FrameLayout <FrameLayout
android:id="@+id/info_type_buttons_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<include <View
layout="@layout/custom_radio_buttons"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/measurement_tool_button_height" android:layout_height="0dp"
android:layout_marginStart="@dimen/content_padding" android:background="@drawable/bg_contextmenu_shadow_top_light" />
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginBottom="@dimen/measurement_tool_content_padding_medium" /> <ProgressBar
android:id="@+id/snap_to_road_progress_bar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="0dp"
android:background="?attr/list_background_color"
android:visibility="invisible"
tools:visibility="visible" />
</FrameLayout> </FrameLayout>
<FrameLayout
android:id="@+id/cards_container"
android:layout_width="match_parent"
android:layout_height="@dimen/measurement_tool_info_cards_container_height"
android:visibility="gone" />
<View
android:id="@+id/bottom_panel_divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dashboard_divider" />
<LinearLayout <LinearLayout
android:id="@+id/measure_mode_controls" android:id="@+id/main_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/measurement_tool_controls_height" android:layout_height="wrap_content"
android:paddingTop="@dimen/measurement_tool_button_margin" android:background="?attr/list_background_color"
android:paddingBottom="@dimen/measurement_tool_button_margin" android:orientation="vertical">
android:paddingLeft="@dimen/measurement_tool_button_margin"
android:paddingRight="@dimen/measurement_tool_button_margin"
android:paddingStart="@dimen/measurement_tool_button_margin"
android:paddingEnd="@dimen/measurement_tool_button_margin">
<FrameLayout <RelativeLayout
android:layout_width="0dp" android:id="@+id/up_down_row"
android:layout_height="match_parent" android:layout_width="match_parent"
android:layout_weight="1"> android:layout_height="@dimen/measurement_tool_up_down_row_height"
android:background="?attr/selectableItemBackground">
<net.osmand.plus.widgets.TextViewEx <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/options_button" android:id="@+id/main_icon"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground" android:layout_alignParentLeft="true"
android:ellipsize="end" android:layout_alignParentStart="true"
android:gravity="center_vertical" android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/measurement_tool_text_button_padding"
android:layout_marginLeft="@dimen/measurement_tool_text_button_padding"
android:layout_marginRight="@dimen/measurement_tool_text_button_padding"
android:layout_marginStart="@dimen/measurement_tool_text_button_padding"
android:background="@null"
tools:src="@drawable/ic_action_ruler"/>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/up_down_button"
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/bottom_sheet_content_margin"
android:layout_marginLeft="@dimen/bottom_sheet_content_margin"
android:layout_marginRight="@dimen/bottom_sheet_content_margin"
android:layout_marginStart="@dimen/bottom_sheet_content_margin"
android:background="@null"
tools:src="@drawable/ic_action_arrow_down"/>
<TextView
android:id="@+id/measurement_distance_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/measurement_tool_button_padding"
android:layout_marginEnd="@dimen/text_margin_small"
android:layout_marginLeft="@dimen/measurement_tool_text_button_padding"
android:layout_marginRight="@dimen/text_margin_small"
android:layout_marginStart="@dimen/measurement_tool_text_button_padding"
android:layout_toEndOf="@id/main_icon"
android:layout_toRightOf="@id/main_icon"
android:textAppearance="@style/TextAppearance.ListItemCategoryTitle"
tools:text="724 m,"/>
<TextView
android:id="@+id/measurement_points_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/measurement_tool_button_padding"
android:layout_toEndOf="@id/measurement_distance_text_view"
android:layout_toRightOf="@id/measurement_distance_text_view"
android:layout_alignEnd="@id/up_down_button"
android:layout_alignRight="@id/up_down_button"
android:textAppearance="@style/TextAppearance.ListItemCategoryTitle"
tools:text="points: 3" />
<TextView
android:id="@+id/distance_to_center_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/measurement_points_text_view"
android:layout_alignStart="@+id/measurement_distance_text_view"
android:layout_alignLeft="@+id/measurement_distance_text_view"
android:maxLines="1" android:maxLines="1"
android:paddingStart="@dimen/measurement_tool_text_button_padding_small" android:textColor="?android:textColorSecondary"
android:paddingLeft="@dimen/measurement_tool_text_button_padding_small" android:textSize="@dimen/default_desc_text_size"
android:paddingEnd="@dimen/measurement_tool_text_button_padding_small" tools:text=" 700 m" />
android:paddingRight="@dimen/measurement_tool_text_button_padding_small"
android:text="@string/shared_string_options"
android:textColor="?attr/color_dialog_buttons"
osmand:typeface="@string/font_roboto_medium"/>
</FrameLayout>
<ImageButton <TextView
android:id="@+id/undo_point_button" android:id="@+id/move_point_text"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground" android:layout_centerVertical="true"
android:padding="@dimen/measurement_tool_undo_redo_padding_small" android:layout_marginEnd="@dimen/text_margin_small"
android:contentDescription="@string/shared_string_undo" android:layout_marginLeft="@dimen/measurement_tool_text_margin"
tools:src="@drawable/ic_action_undo_dark"/> android:layout_marginRight="@dimen/text_margin_small"
android:layout_marginStart="@dimen/measurement_tool_text_margin"
android:layout_toEndOf="@id/main_icon"
android:layout_toRightOf="@id/main_icon"
android:text="@string/move_point"
android:textAppearance="@style/TextAppearance.ListItemTitle"
android:visibility="gone"/>
<ImageButton <TextView
android:id="@+id/redo_point_button" android:id="@+id/add_point_before_after_text"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/measurement_tool_button_padding" android:layout_centerVertical="true"
android:layout_marginStart="@dimen/measurement_tool_button_padding" android:layout_marginEnd="@dimen/text_margin_small"
android:background="?attr/selectableItemBackground" android:layout_marginLeft="@dimen/measurement_tool_text_margin"
android:padding="@dimen/measurement_tool_undo_redo_padding_small" android:layout_marginRight="@dimen/text_margin_small"
android:contentDescription="@string/shared_string_redo" android:layout_marginStart="@dimen/measurement_tool_text_margin"
tools:src="@drawable/ic_action_redo_dark"/> android:layout_toEndOf="@id/main_icon"
android:layout_toRightOf="@id/main_icon"
android:textAppearance="@style/TextAppearance.ListItemTitle"
android:visibility="gone"
tools:text="@string/add_point_after"/>
</RelativeLayout>
<FrameLayout <FrameLayout
android:layout_width="0dp" android:id="@+id/info_type_buttons_container"
android:layout_height="match_parent" android:layout_width="match_parent"
android:layout_weight="1"> android:layout_height="wrap_content">
<include <include
android:id="@+id/add_point_button" layout="@layout/custom_radio_buttons"
layout="@layout/bottom_sheet_dialog_button" android:layout_width="match_parent"
android:layout_width="wrap_content" android:layout_height="@dimen/measurement_tool_button_height"
android:layout_height="match_parent" android:layout_marginStart="@dimen/content_padding"
android:layout_gravity="end" android:layout_marginEnd="@dimen/content_padding"
android:minWidth="@dimen/measurement_tool_button_width" /> android:layout_marginBottom="@dimen/measurement_tool_content_padding_medium" />
</FrameLayout> </FrameLayout>
</LinearLayout> <FrameLayout
android:id="@+id/cards_container"
<RelativeLayout android:layout_width="match_parent"
android:id="@+id/move_point_controls" android:layout_height="@dimen/measurement_tool_info_cards_container_height"
android:layout_width="match_parent" android:visibility="gone" />
android:layout_height="@dimen/measurement_tool_controls_height"
android:visibility="gone">
<include
android:id="@+id/apply_move_point_button"
layout="@layout/bottom_sheet_dialog_button"
android:layout_width="wrap_content"
android:layout_height="@dimen/measurement_tool_button_height"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/measurement_tool_button_margin"
android:layout_marginRight="@dimen/measurement_tool_button_margin"
android:minWidth="@dimen/measurement_tool_button_width" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/cancel_move_point_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_margin="@dimen/measurement_tool_button_margin"
android:background="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:padding="@dimen/measurement_tool_text_button_padding_small"
android:text="@string/shared_string_cancel"
android:textColor="?attr/color_dialog_buttons"
osmand:typeface="@string/font_roboto_medium"/>
</RelativeLayout>
<LinearLayout
android:id="@+id/add_point_before_after_controls"
android:layout_width="match_parent"
android:layout_height="@dimen/measurement_tool_controls_height"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/cancel_point_before_after_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_margin="@dimen/measurement_tool_button_margin"
android:background="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:padding="@dimen/measurement_tool_text_button_padding_small"
android:text="@string/shared_string_cancel"
android:textColor="?attr/color_dialog_buttons"
osmand:typeface="@string/font_roboto_medium"/>
<View <View
android:layout_width="0dp" android:id="@+id/bottom_panel_divider"
android:layout_height="match_parent" android:layout_width="match_parent"
android:layout_weight="1"/> android:layout_height="1dp"
android:background="?attr/dashboard_divider" />
<include <LinearLayout
android:id="@+id/apply_point_before_after_point_button" android:id="@+id/measure_mode_controls"
android:layout_height="@dimen/measurement_tool_button_height" android:layout_width="match_parent"
android:layout_gravity="center_vertical" android:layout_height="@dimen/measurement_tool_controls_height"
android:layout_width="@dimen/measurement_tool_button_width" android:paddingTop="@dimen/measurement_tool_button_margin"
android:layout_marginEnd="@dimen/measurement_tool_button_margin" android:paddingBottom="@dimen/measurement_tool_button_margin"
android:layout_marginRight="@dimen/measurement_tool_button_margin" android:paddingLeft="@dimen/measurement_tool_button_margin"
layout="@layout/bottom_sheet_dialog_button" /> android:paddingRight="@dimen/measurement_tool_button_margin"
android:paddingStart="@dimen/measurement_tool_button_margin"
android:paddingEnd="@dimen/measurement_tool_button_margin">
<include <FrameLayout
android:id="@+id/add_point_before_after_button" android:layout_width="0dp"
android:layout_height="@dimen/measurement_tool_button_height" android:layout_height="match_parent"
android:layout_gravity="center_vertical" android:layout_weight="1">
android:layout_width="@dimen/measurement_tool_button_width"
android:layout_marginEnd="@dimen/measurement_tool_button_margin" <net.osmand.plus.widgets.TextViewEx
android:layout_marginRight="@dimen/measurement_tool_button_margin" android:id="@+id/options_button"
layout="@layout/bottom_sheet_dialog_button" /> android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:paddingStart="@dimen/measurement_tool_text_button_padding_small"
android:paddingLeft="@dimen/measurement_tool_text_button_padding_small"
android:paddingEnd="@dimen/measurement_tool_text_button_padding_small"
android:paddingRight="@dimen/measurement_tool_text_button_padding_small"
android:text="@string/shared_string_options"
android:textColor="?attr/color_dialog_buttons"
osmand:typeface="@string/font_roboto_medium"/>
</FrameLayout>
<ImageButton
android:id="@+id/undo_point_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:padding="@dimen/measurement_tool_undo_redo_padding_small"
android:contentDescription="@string/shared_string_undo"
tools:src="@drawable/ic_action_undo_dark"/>
<ImageButton
android:id="@+id/redo_point_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/measurement_tool_button_padding"
android:layout_marginStart="@dimen/measurement_tool_button_padding"
android:background="?attr/selectableItemBackground"
android:padding="@dimen/measurement_tool_undo_redo_padding_small"
android:contentDescription="@string/shared_string_redo"
tools:src="@drawable/ic_action_redo_dark"/>
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<include
android:id="@+id/add_point_button"
layout="@layout/bottom_sheet_dialog_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:minWidth="@dimen/measurement_tool_button_width" />
</FrameLayout>
</LinearLayout>
<RelativeLayout
android:id="@+id/move_point_controls"
android:layout_width="match_parent"
android:layout_height="@dimen/measurement_tool_controls_height"
android:visibility="gone">
<include
android:id="@+id/apply_move_point_button"
layout="@layout/bottom_sheet_dialog_button"
android:layout_width="wrap_content"
android:layout_height="@dimen/measurement_tool_button_height"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/measurement_tool_button_margin"
android:layout_marginRight="@dimen/measurement_tool_button_margin"
android:minWidth="@dimen/measurement_tool_button_width" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/cancel_move_point_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_margin="@dimen/measurement_tool_button_margin"
android:background="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:padding="@dimen/measurement_tool_text_button_padding_small"
android:text="@string/shared_string_cancel"
android:textColor="?attr/color_dialog_buttons"
osmand:typeface="@string/font_roboto_medium"/>
</RelativeLayout>
<LinearLayout
android:id="@+id/add_point_before_after_controls"
android:layout_width="match_parent"
android:layout_height="@dimen/measurement_tool_controls_height"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/cancel_point_before_after_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_margin="@dimen/measurement_tool_button_margin"
android:background="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:padding="@dimen/measurement_tool_text_button_padding_small"
android:text="@string/shared_string_cancel"
android:textColor="?attr/color_dialog_buttons"
osmand:typeface="@string/font_roboto_medium"/>
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<include
android:id="@+id/apply_point_before_after_point_button"
android:layout_height="@dimen/measurement_tool_button_height"
android:layout_gravity="center_vertical"
android:layout_width="@dimen/measurement_tool_button_width"
android:layout_marginEnd="@dimen/measurement_tool_button_margin"
android:layout_marginRight="@dimen/measurement_tool_button_margin"
layout="@layout/bottom_sheet_dialog_button" />
<include
android:id="@+id/add_point_before_after_button"
android:layout_height="@dimen/measurement_tool_button_height"
android:layout_gravity="center_vertical"
android:layout_width="@dimen/measurement_tool_button_width"
android:layout_marginEnd="@dimen/measurement_tool_button_margin"
android:layout_marginRight="@dimen/measurement_tool_button_margin"
layout="@layout/bottom_sheet_dialog_button" />
</LinearLayout>
</LinearLayout> </LinearLayout>

View file

@ -4,6 +4,9 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/list_background_color"
android:clickable="true"
android:focusable="true"
android:orientation="vertical"> android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView

View file

@ -31,7 +31,7 @@
tools:text="Some title" /> tools:text="Some title" />
<net.osmand.plus.widgets.TextViewEx <net.osmand.plus.widgets.TextViewEx
android:id="@+id/description" android:id="@+id/title_description"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/title" android:layout_below="@+id/title"
@ -60,6 +60,54 @@
</RelativeLayout> </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 <LinearLayout
android:id="@+id/select_all_button" android:id="@+id/select_all_button"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -67,12 +115,12 @@
android:background="?attr/selectableItemBackground" android:background="?attr/selectableItemBackground"
android:gravity="center_vertical" android:gravity="center_vertical"
android:minHeight="@dimen/bottom_sheet_list_item_height" android:minHeight="@dimen/bottom_sheet_list_item_height"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding" android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding_small" android:paddingTop="@dimen/content_padding_small"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding" android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding_small" android:paddingBottom="@dimen/content_padding_small">
android:paddingStart="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding">
<net.osmand.plus.widgets.TextViewEx <net.osmand.plus.widgets.TextViewEx
android:id="@+id/check_box_title" android:id="@+id/check_box_title"

View file

@ -64,7 +64,6 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/content_padding_small" android:layout_marginTop="@dimen/content_padding_small"
android:layout_gravity="center_vertical"
android:paddingStart="@dimen/content_padding_small" android:paddingStart="@dimen/content_padding_small"
android:paddingLeft="@dimen/content_padding_small" android:paddingLeft="@dimen/content_padding_small"
android:paddingTop="@dimen/content_padding_small_half" android:paddingTop="@dimen/content_padding_small_half"

View file

@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" 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_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/bg_color" android:background="?attr/bg_color"
@ -13,78 +11,13 @@
android:layout_height="@dimen/list_content_padding" android:layout_height="@dimen/list_content_padding"
android:background="?attr/activity_background_color" /> android:background="?attr/activity_background_color" />
<include <include layout="@layout/divider" />
layout="@layout/divider" />
<FrameLayout <FrameLayout
android:id="@+id/subscriptions_list_container" android:id="@+id/subscriptions_list_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> 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 <LinearLayout
android:id="@+id/report_container" android:id="@+id/report_container"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -206,8 +139,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/activity_background_color"> android:background="?attr/activity_background_color">
<include <include layout="@layout/card_bottom_divider" />
layout="@layout/card_bottom_divider" />
</FrameLayout> </FrameLayout>

View file

@ -42,6 +42,7 @@
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<ScrollView <ScrollView
android:id="@+id/main_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@ -121,6 +122,13 @@
android:textColor="?android:textColorPrimary" android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size" /> 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 <include
android:id="@+id/btn_backup" android:id="@+id/btn_backup"
layout="@layout/bottom_sheet_dialog_button" layout="@layout/bottom_sheet_dialog_button"

View file

@ -32,7 +32,6 @@
android:id="@+id/troubleshooting_icon" android:id="@+id/troubleshooting_icon"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/map_widget_height" android:layout_marginEnd="@dimen/map_widget_height"
android:layout_marginRight="@dimen/map_widget_height" android:layout_marginRight="@dimen/map_widget_height"
android:paddingBottom="@dimen/dialog_content_bottom_margin" android:paddingBottom="@dimen/dialog_content_bottom_margin"

File diff suppressed because it is too large Load diff

View file

@ -3837,4 +3837,8 @@
<string name="track_has_no_altitude">Sporet indeholder ikke højdedata.</string> <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="track_has_no_speed">Sporet indeholder ikke hastighedsdata.</string>
<string name="select_another_colorization">Vælg en anden type farvelægning.</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> </resources>

View file

@ -3926,4 +3926,6 @@
<string name="poi_karate">Karate</string> <string name="poi_karate">Karate</string>
<string name="poi_office_diplomatic">Diplomatische Vertretung</string> <string name="poi_office_diplomatic">Diplomatische Vertretung</string>
<string name="poi_bay_filter">Art der Bucht</string> <string name="poi_bay_filter">Art der Bucht</string>
<string name="poi_plateau">Plateau</string>
<string name="poi_club_social">Freizeitclub</string>
</resources> </resources>

View file

@ -3856,7 +3856,7 @@
\nSie können sich mit der sicheren OAuth-Methode anmelden oder Ihren Benutzernamen und Ihr Passwort verwenden.</string> \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="use_login_password">Benutzername und Passwort verwenden</string>
<string name="login_account">Konto</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="markers_history">Historie der Marker</string>
<string name="send_files_to_openstreetmap">GPX-Datei an OpenStreetMap senden</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> <string name="enter_text_separated">Geben Sie durch Komma getrennte Tags ein.</string>

View file

@ -3926,4 +3926,6 @@
<string name="poi_hoops">Korboj</string> <string name="poi_hoops">Korboj</string>
<string name="poi_bay_filter">Tipo de golfo</string> <string name="poi_bay_filter">Tipo de golfo</string>
<string name="poi_office_diplomatic">Diplomatia oficejo</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> </resources>

View file

@ -3926,4 +3926,6 @@
<string name="poi_hoops">Aros</string> <string name="poi_hoops">Aros</string>
<string name="poi_office_diplomatic">Oficina diplomática</string> <string name="poi_office_diplomatic">Oficina diplomática</string>
<string name="poi_bay_filter">Tipo de bahía</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> </resources>

View file

@ -1460,4 +1460,5 @@
<string name="poi_shoes_women">بانوان</string> <string name="poi_shoes_women">بانوان</string>
<string name="poi_clothes_women">بانوان</string> <string name="poi_clothes_women">بانوان</string>
<string name="poi_clothes_workwear">لباس کار</string> <string name="poi_clothes_workwear">لباس کار</string>
<string name="poi_greenhouse_horticulture">باغداری گلخانه‌ای</string>
</resources> </resources>

View file

@ -3924,4 +3924,5 @@
<string name="poi_hoops">Kosárlabdapalánkok</string> <string name="poi_hoops">Kosárlabdapalánkok</string>
<string name="poi_office_diplomatic">Diplomáciai iroda</string> <string name="poi_office_diplomatic">Diplomáciai iroda</string>
<string name="poi_bay_filter">Öböl típusa</string> <string name="poi_bay_filter">Öböl típusa</string>
<string name="poi_plateau">Fennsík</string>
</resources> </resources>

View file

@ -3926,4 +3926,5 @@
<string name="poi_karate">Karate</string> <string name="poi_karate">Karate</string>
<string name="poi_office_diplomatic">Sendiskrifstofa</string> <string name="poi_office_diplomatic">Sendiskrifstofa</string>
<string name="poi_bay_filter">Gerð flóa</string> <string name="poi_bay_filter">Gerð flóa</string>
<string name="poi_plateau">Háslétta</string>
</resources> </resources>

View file

@ -1173,7 +1173,7 @@ POIの更新は利用できません</string>
<string name="save_as_favorites_points">お気に入りのグループとして保存</string> <string name="save_as_favorites_points">お気に入りのグループとして保存</string>
<string name="select_destination_and_intermediate_points">目的地の設定</string> <string name="select_destination_and_intermediate_points">目的地の設定</string>
<string name="layer_amenity_label">施設の名称</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="map_widget_plain_time">現在時刻</string>
<string name="shared_string_waypoint">経由地点</string> <string name="shared_string_waypoint">経由地点</string>
<string name="selected_gpx_info_show">" <string name="selected_gpx_info_show">"
@ -1446,7 +1446,7 @@ POIの更新は利用できません</string>
<string name="routing_settings_2">ナビゲーション設定</string> <string name="routing_settings_2">ナビゲーション設定</string>
<string name="general_settings_2">全般設定</string> <string name="general_settings_2">全般設定</string>
<string name="shared_string_ellipsis"></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_disable">無効化</string>
<string name="shared_string_selected">選択済み</string> <string name="shared_string_selected">選択済み</string>
<string name="shared_string_deselect">選択解除</string> <string name="shared_string_deselect">選択解除</string>
@ -2818,9 +2818,9 @@ POIの更新は利用できません</string>
<string name="osm_live_subscriptions">サブスクリプション</string> <string name="osm_live_subscriptions">サブスクリプション</string>
<string name="powered_by_osmand">By OsmAnd</string> <string name="powered_by_osmand">By OsmAnd</string>
<string name="osm_live_plan_pricing">プランと料金</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_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">%1$s / 月</string>
<string name="osm_live_payment_month_cost_descr_ex">%1$.2f %2$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_discount_descr">%1$s割引</string>
@ -3172,7 +3172,7 @@ POIの更新は利用できません</string>
<string name="app_mode_utv">横並び(サイドバイサイド)形式</string> <string name="app_mode_utv">横並び(サイドバイサイド)形式</string>
<string name="rendering_attr_piste_difficulty_aerialway_name">索道(リフトやロープウェイなど)</string> <string name="rendering_attr_piste_difficulty_aerialway_name">索道(リフトやロープウェイなど)</string>
<string name="rendering_attr_piste_difficulty_connection_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_string_osmand_usage">OsmAndの合計使用容量</string>
<string name="shared_sting_tiles">タイル</string> <string name="shared_sting_tiles">タイル</string>
<string name="shared_string_maps">マップ</string> <string name="shared_string_maps">マップ</string>
@ -3703,9 +3703,9 @@ POIの更新は利用できません</string>
\n \n
\n国の法律に基づいて、使用を望むかどうかを決定する必要があります。 \n国の法律に基づいて、使用を望むかどうかを決定する必要があります。
\n \n
\n%1$sを選択すると、スピードカメラに関するアラートと警告機能を使用できます。 \n%1$sを選択すると、スピードカメラに関するアラートと警告機能を使用できます。
\n \n
\n%2$sを選択すると、スピードカメラに関するすべてのデータ(警告、通知、POI)が、OsmAndの再インストールを行うまで削除されます。</string> \n%2$sを選択すると、スピードカメラに関するすべてのデータ(警告、通知、POI)が、OsmAndの再インストールを行うまで削除されます。</string>
<string name="keep_active">機能を維持</string> <string name="keep_active">機能を維持</string>
<string name="shared_string_uninstall">アンインストール</string> <string name="shared_string_uninstall">アンインストール</string>
<string name="speed_cameras_alert">一部の国では、スピードカメラの事前警告は法律で禁止されています。</string> <string name="speed_cameras_alert">一部の国では、スピードカメラの事前警告は法律で禁止されています。</string>
@ -4078,4 +4078,26 @@ POIの更新は利用できません</string>
<string name="app_mode_wheelchair_forward">基本前進のみの車椅子</string> <string name="app_mode_wheelchair_forward">基本前進のみの車椅子</string>
<string name="track_coloring_solid">通常色</string> <string name="track_coloring_solid">通常色</string>
<string name="in_case_of_reverse_direction">逆方向の場合</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> </resources>

View file

@ -1802,7 +1802,7 @@ failu(s)?
<string name="first_usage_item">Sākt lietot</string> <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="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="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">BUJ</string>
<string name="faq_item_description">Biežāk uzdotie jautājumi</string> <string name="faq_item_description">Biežāk uzdotie jautājumi</string>
<string name="map_viewing_item">Kartes skatīšana</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="shared_string_time">Laiks</string>
<string name="total_distance">Maršruta garums</string> <string name="total_distance">Maršruta garums</string>
<string name="routing_attr_height_obstacles_name">Lietot elevācijas datus</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="relief_smoothness_factor_descr">Ieteicamais reljefs: līdzens vai kalnains.</string>
<string name="shared_string_slope">Slīpums</string> <string name="shared_string_slope">Slīpums</string>
<string name="lang_ber">Berberu</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="show_map">Rādīt karti</string>
<string name="route_is_calculated">Maršruts aprēķināts</string> <string name="route_is_calculated">Maršruts aprēķināts</string>
<string name="round_trip">Turp un atpakaļ</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_error">Piezīmei nevarēja veikt izmaiņas</string>
<string name="osn_modify_dialog_title">Labot piezīmi</string> <string name="osn_modify_dialog_title">Labot piezīmi</string>
<string name="context_menu_item_modify_note">!abot OSM 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_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="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="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="my_location">Mana pozīcija</string>
<string name="shared_string_finish">Finišs</string> <string name="shared_string_finish">Finišs</string>
<string name="plan_route">Plānot maršrutu</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="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_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="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> </resources>

View file

@ -4056,13 +4056,13 @@
<string name="customize_route_line">Zmień trasę nawigacji</string> <string name="customize_route_line">Zmień trasę nawigacji</string>
<string name="shared_string_route_line">Trasa nawigacji</string> <string name="shared_string_route_line">Trasa nawigacji</string>
<string name="expired">Wygasł</string> <string name="expired">Wygasł</string>
<string name="release_4_0_beta">OsmAnd Live aktualizacje przeniesiono do \"Pobrane &gt; Aktualizacje\" <string name="release_4_0_beta">Aktualizacje OsmAnd Live przeniesiono do \"Pobrane &gt; Aktualizacje\"
\n \n
\n •Ślady mogą być pokolorowane względem wysokości, prędkości, wzniesień. \n •Ślady mogą być pokolorowane względem wysokości, prędkości, wzniesień.
\n \n
\n • Dodano opcję zmiany wyglądu trasy nawigacji \n • Dodano opcję zmiany wyglądu trasy nawigacji
\n \n
\n • zaktualizowano okno \"Nagrywanie Trasy\" \n • Zaktualizowano okno \"Nagrywanie Trasy\"
\n \n
\n</string> \n</string>
<string name="map_quick_action_pattern">%1$s → …</string> <string name="map_quick_action_pattern">%1$s → …</string>

View file

@ -3918,4 +3918,13 @@
<string name="poi_jiu_jitsu">Jiu-jitsu</string> <string name="poi_jiu_jitsu">Jiu-jitsu</string>
<string name="poi_karate">Karatê</string> <string name="poi_karate">Karatê</string>
<string name="poi_hoops">Aros</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> </resources>

View file

@ -3758,7 +3758,7 @@
<string name="shared_string_file_name">Nome do arquivo</string> <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="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="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_stop">Pausar gravação de viagem</string>
<string name="gpx_monitoring_start">Retomar a gravação da viagem</string> <string name="gpx_monitoring_start">Retomar a gravação da viagem</string>
<string name="system_default_theme">Padrão do sistema</string> <string name="system_default_theme">Padrão do sistema</string>
@ -4049,15 +4049,15 @@
<string name="shared_string_route_line">Linha de rota</string> <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="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="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 &gt; Atualizações\" <string name="release_4_0_beta">• As atualizações do OsmAnd Live foram movidas para \"Downloads &gt; Atualizações\"
\n \n
\n • As trilhas agora podem ser coloridas por altitude, velocidade ou inclinação. \n• As trilhas agora podem ser coloridas por altitude, velocidade ou inclinação.
\n \n
\n • Adicionada opção para alterar a aparência da linha da rota de navegação \n• Adicionada opção para alterar a aparência da linha da rota de navegação
\n \n
\n • Caixa de diálogo \"Gravação de viagem\" atualizada \n• Caixa de diálogo \"Gravação de viagem\" atualizada
\n \n
\n"</string> \n</string>
<string name="no_purchases">Você não tem nenhuma compra</string> <string name="no_purchases">Você não tem nenhuma compra</string>
<string name="new_device_account">Novo dispositivo / nova conta</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> <string name="contact_support_description">Se você tiver alguma dúvida, entre em contato conosco em %1$s.</string>

View file

@ -58,7 +58,7 @@
<string name="poi_greengrocer">Loja de frutas e verduras</string> <string name="poi_greengrocer">Loja de frutas e verduras</string>
<string name="poi_seafood">Peixaria</string> <string name="poi_seafood">Peixaria</string>
<string name="poi_confectionery">Confeitaria</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_supermarket">Supermercado</string>
<string name="poi_tea">Loja de chás</string> <string name="poi_tea">Loja de chás</string>
<string name="poi_pasta">Loja de massas</string> <string name="poi_pasta">Loja de massas</string>
@ -80,7 +80,7 @@
<string name="poi_carpet">Loja de tapetes</string> <string name="poi_carpet">Loja de tapetes</string>
<string name="poi_charity">Loja de caridade</string> <string name="poi_charity">Loja de caridade</string>
<string name="poi_chemist">Loja de produtos de higiene pessoal</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_clothes_children">Vestuário infantil</string>
<string name="poi_shoes">Sapataria</string> <string name="poi_shoes">Sapataria</string>
<string name="poi_candles">Loja de velas</string> <string name="poi_candles">Loja de velas</string>
@ -248,7 +248,7 @@
<string name="poi_shoes_type">Tipo</string> <string name="poi_shoes_type">Tipo</string>
<string name="poi_fire_hydrant_type">Tipo</string> <string name="poi_fire_hydrant_type">Tipo</string>
<string name="poi_fire_hydrant_position">Localização</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_payment_toll_type">Forma de pagamento</string>
<string name="poi_traffic_signals_sound">Som</string> <string name="poi_traffic_signals_sound">Som</string>
<string name="poi_highway_crossing_type">Tipo</string> <string name="poi_highway_crossing_type">Tipo</string>
@ -296,7 +296,7 @@
<string name="poi_fireplace">Lareira</string> <string name="poi_fireplace">Lareira</string>
<string name="poi_beach_surface_type">Superfície</string> <string name="poi_beach_surface_type">Superfície</string>
<string name="poi_nudism">Nudismo</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_massage_type">Tipo de massagem</string>
<string name="poi_tents">Tendas</string> <string name="poi_tents">Tendas</string>
<string name="poi_washing_machine">Máquina de lavar roupa</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_water_tower">Reservatório elevado</string>
<string name="poi_lock_gate">Comporta de eclusa</string> <string name="poi_lock_gate">Comporta de eclusa</string>
<string name="poi_waterway_turning_point">Ponto de viragem fluvial</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_dam">Barragem</string>
<string name="poi_watermill">Moinho de água</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_groyne">Espigão marítimo</string>
<string name="poi_power_substation">Subestação</string> <string name="poi_power_substation">Subestação</string>
<string name="poi_power_transformer">Transformador</string> <string name="poi_power_transformer">Transformador</string>
@ -565,18 +565,18 @@
<string name="poi_capital">Sim</string> <string name="poi_capital">Sim</string>
<string name="poi_town">Sede de concelho</string> <string name="poi_town">Sede de concelho</string>
<string name="poi_village">Sede de freguesia</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_isolated_dwelling">Moradia isolada</string>
<string name="poi_suburb">Subúrbio</string> <string name="poi_suburb">Subúrbio</string>
<string name="poi_quarter">Zona de cidade</string> <string name="poi_quarter">Zona de cidade</string>
<string name="poi_neighbourhood">Bairro</string> <string name="poi_neighbourhood">Bairro</string>
<string name="poi_locality">Localidade</string> <string name="poi_locality">Localidade</string>
<string name="poi_place_allotments">Horta comunitária</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_pharmacy">Farmácia</string>
<string name="poi_hospital">Hospital</string> <string name="poi_hospital">Hospital</string>
<string name="poi_doctors">Consultório médico</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_first_aid">Primeiros socorros</string>
<string name="poi_dentist">Dentista</string> <string name="poi_dentist">Dentista</string>
<string name="poi_nursing_home">Clínica geriátrica</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_boundary_stone">Marco de fronteira</string>
<string name="poi_historic_cannon">Canhão histórico</string> <string name="poi_historic_cannon">Canhão histórico</string>
<string name="poi_castle">Castelo</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_fort">Forte</string>
<string name="poi_fountain">Chafariz</string> <string name="poi_fountain">Chafariz</string>
<string name="poi_historic_ruins">Ruínas históricas</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_attraction_water_slide">Tobogã aquático</string>
<string name="poi_lodging">Alojamento</string> <string name="poi_lodging">Alojamento</string>
<string name="poi_hotel">Hotel</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_hostel">Hostel</string>
<string name="poi_motel">Hotel estrada</string> <string name="poi_motel">Hotel estrada</string>
<string name="poi_alpine_hut">Abrigo de montanha</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_lean_to">Galpão</string>
<string name="poi_hunting_lodge">Cabana de caça</string> <string name="poi_hunting_lodge">Cabana de caça</string>
<string name="poi_place_of_worship">Local de culto</string> <string name="poi_place_of_worship">Local de culto</string>
<string name="poi_religion_christian">Cristianismo</string> <string name="poi_religion_christian">Cristã</string>
<string name="poi_religion_jewish">Judaísmo</string> <string name="poi_religion_jewish">Judaica</string>
<string name="poi_religion_muslim">Islamismo</string> <string name="poi_religion_muslim">Islâmica</string>
<string name="poi_religion_sikh">Sikhismo</string> <string name="poi_religion_sikh">Siquista</string>
<string name="poi_religion_buddhist">Budismo</string> <string name="poi_religion_buddhist">Budista</string>
<string name="poi_religion_hindu">Hinduísmo</string> <string name="poi_religion_hindu">Hinduísta</string>
<string name="poi_religion_shinto">Xintoísmo</string> <string name="poi_religion_shinto">Xintoísma</string>
<string name="poi_religion_taoist">Taoísmo</string> <string name="poi_religion_taoist">Taoísma</string>
<string name="poi_religion_voodoo">Vodu</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_multifaith">Multirreligiosa</string>
<string name="poi_religion_jain">Jainismo</string> <string name="poi_religion_jain">Jainista</string>
<string name="poi_religion_spiritualist">Espiritualismo</string> <string name="poi_religion_spiritualist">Espiritualista</string>
<string name="poi_religion_bahai">Bahaísmo</string> <string name="poi_religion_bahai">Bahaísta</string>
<string name="poi_religion_scientologist">Cientologismo</string> <string name="poi_religion_scientologist">Cientologista</string>
<string name="poi_religion_pagan">Paganismo</string> <string name="poi_religion_pagan">Paganista</string>
<string name="poi_religion_tenrikyo">Tenrikyo</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_catholic">Católica</string>
<string name="poi_denomination_baptist">Batista</string> <string name="poi_denomination_baptist">Batista</string>
<string name="poi_denomination_roman_catholic">Católica romana</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_travel_agent">Agência de viagens</string>
<string name="poi_viewpoint">Miradouro</string> <string name="poi_viewpoint">Miradouro</string>
<string name="poi_camp_site">Local de acampamento</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_picnic_table">Mesa de piquenique</string>
<string name="poi_spring">Nascente</string> <string name="poi_spring">Nascente</string>
<string name="poi_hot_spring">Fonte termal</string> <string name="poi_hot_spring">Fonte termal</string>
@ -890,7 +890,7 @@
<string name="poi_theatre_genre_circus">Circo</string> <string name="poi_theatre_genre_circus">Circo</string>
<string name="poi_gallery">Galeria de arte</string> <string name="poi_gallery">Galeria de arte</string>
<string name="poi_dance_floor">Pista de dança</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_stripclub">Clube de striptease</string>
<string name="poi_ski_resort">Resort de esqui</string> <string name="poi_ski_resort">Resort de esqui</string>
<string name="poi_beach_resort">Resort de praia</string> <string name="poi_beach_resort">Resort de praia</string>
@ -912,9 +912,9 @@
<string name="poi_restaurant">Restaurante</string> <string name="poi_restaurant">Restaurante</string>
<string name="poi_fast_food">Comida rápida</string> <string name="poi_fast_food">Comida rápida</string>
<string name="poi_bar">Bar</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_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_barbecue">Churrasqueira</string>
<string name="poi_craft_agricultural_engines">Máquinas agrícolas</string> <string name="poi_craft_agricultural_engines">Máquinas agrícolas</string>
<string name="poi_craft_basket_maker">Cesteiro</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_car_pooling">Ponto de boleia solidária de carro</string>
<string name="poi_boat_sharing">Ponto de barcos partilhados</string> <string name="poi_boat_sharing">Ponto de barcos partilhados</string>
<string name="poi_dock">Doca</string> <string name="poi_dock">Doca</string>
<string name="poi_cutline">Linha de corte florestal;Atalhada;Linha corta-fogo</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</string> <string name="poi_toilets">Casa de banho;Banheiros;WC</string>
<string name="poi_shower">Chuveiros públicos</string> <string name="poi_shower">Chuveiros públicos</string>
<string name="poi_sauna">Sauna</string> <string name="poi_sauna">Sauna</string>
<string name="poi_brothel">Bordel</string> <string name="poi_brothel">Bordel</string>
@ -1002,9 +1002,9 @@
<string name="poi_ridge">Cumeeira</string> <string name="poi_ridge">Cumeeira</string>
<string name="poi_glacier">Glaciar</string> <string name="poi_glacier">Glaciar</string>
<string name="poi_sinkhole">Sumidouro</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_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_rapids">Rápidos</string>
<string name="poi_cape">Cabo</string> <string name="poi_cape">Cabo</string>
<string name="poi_beach">Praia</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_zh">Wiki em chinês</string>
<string name="poi_wiki_lang_af">Wiki em africâner</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_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_bn">Wiki em bengali</string>
<string name="poi_wiki_lang_bpy">Wiki em bishnupriya</string> <string name="poi_wiki_lang_bpy">Wiki em bishnupriya</string>
<string name="poi_wiki_lang_br">Wiki em bretão</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_fee_no">Não</string>
<string name="poi_drinking_water_yes">Sim</string> <string name="poi_drinking_water_yes">Sim</string>
<string name="poi_drinking_water_no">Não</string> <string name="poi_drinking_water_no">Não</string>
<string name="poi_supervised_yes">Vigiado</string> <string name="poi_supervised_yes">Vigiado: sim</string>
<string name="poi_supervised_no">Não vigiado</string> <string name="poi_supervised_no">Vigiado: não</string>
<string name="poi_seasonal_yes">Sim</string> <string name="poi_seasonal_yes">Sim</string>
<string name="poi_seasonal_no">Não</string> <string name="poi_seasonal_no">Não</string>
<string name="poi_seasonal_dry_season">Estação seca</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_mineral">Mineral</string>
<string name="poi_water_characteristic_mud">Lama</string> <string name="poi_water_characteristic_mud">Lama</string>
<string name="poi_water_characteristic_sulfuric">Sulfurosa</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_guidepost">Poste com direções</string>
<string name="poi_information_board">Painel</string> <string name="poi_information_board">Painel</string>
<string name="poi_information_map">Mapa</string> <string name="poi_information_map">Mapa</string>
@ -1433,7 +1433,7 @@
<string name="poi_horse_riding">Centro equestre</string> <string name="poi_horse_riding">Centro equestre</string>
<string name="poi_leisure_common">Área de lazer comum</string> <string name="poi_leisure_common">Área de lazer comum</string>
<string name="poi_garden">Jardim</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_grass">Relvado</string>
<string name="poi_grassland">Pradaria</string> <string name="poi_grassland">Pradaria</string>
<string name="poi_scrub">Matagal</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_payment_yandexmoney_no">Não aceita Yandex.Money</string>
<string name="poi_description_payment">Detalhes de pagamento</string> <string name="poi_description_payment">Detalhes de pagamento</string>
<string name="poi_events_venue">Salão de eventos</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_filter_yes">Pratos vegetarianos: sim</string>
<string name="poi_diet_vegetarian_few">Vegetariana (alguns)</string> <string name="poi_diet_vegetarian_few">Pratos vegetarianos: alguns</string>
<string name="poi_diet_vegetarian_only">Apenas vegetariana</string> <string name="poi_diet_vegetarian_only">Pratos vegetarianos: só vegetarianos</string>
<string name="poi_diet_vegetarian_yes">Vegetariana</string> <string name="poi_diet_vegetarian_yes">Pratos vegetarianos: sim</string>
<string name="poi_diet_vegetarian_no">Dieta vegetariana: não</string> <string name="poi_diet_vegetarian_no">Pratos vegetarianos: não</string>
<string name="poi_diet_vegan_filter_yes">Vegana</string> <string name="poi_diet_vegan_filter_yes">Pratos veganos: sim</string>
<string name="poi_diet_vegan_only">Apenas vegana</string> <string name="poi_diet_vegan_only">Pratos veganos: só veganos</string>
<string name="poi_diet_vegan_yes">Vegana</string> <string name="poi_diet_vegan_yes">Pratos veganos: sim</string>
<string name="poi_diet_vegan_no">Dieta vegana: não</string> <string name="poi_diet_vegan_no">Pratos veganos: não</string>
<string name="poi_diet_gluten_free_filter_yes">Livre de glúten</string> <string name="poi_diet_gluten_free_filter_yes">Pratos livres de glúten: sim</string>
<string name="poi_diet_gluten_free_only">Apenas livre de glúten</string> <string name="poi_diet_gluten_free_only">Pratos livres de glúten: unicamente</string>
<string name="poi_diet_gluten_free_yes">Livre de glúten</string> <string name="poi_diet_gluten_free_yes">Pratos livres de glúten: sim</string>
<string name="poi_diet_gluten_free_no">Dieta livre de glúten: não</string> <string name="poi_diet_gluten_free_no">Pratos livres de glúten: não</string>
<string name="poi_diet_kosher_filter_yes">Kosher (judaica)</string> <string name="poi_diet_kosher_filter_yes">Pratos kosher (judaica): sim</string>
<string name="poi_diet_kosher_only">Apenas kosher</string> <string name="poi_diet_kosher_only">Pratos kosher (judaica): unicamente</string>
<string name="poi_diet_kosher_yes">Kosher</string> <string name="poi_diet_kosher_yes">Pratos kosher (judaica): sim</string>
<string name="poi_diet_kosher_no">Dieta kosher: não</string> <string name="poi_diet_kosher_no">Pratos kosher (judaica): não</string>
<string name="poi_diet_halal_filter_yes">Halal (árabe)</string> <string name="poi_diet_halal_filter_yes">Pratos halal (árabe): sim</string>
<string name="poi_diet_halal_only">Apenas halal</string> <string name="poi_diet_halal_only">Pratos halal (árabe): apenas</string>
<string name="poi_diet_halal_yes">Halal</string> <string name="poi_diet_halal_yes">Pratos halal (árabe): sim</string>
<string name="poi_diet_halal_no">Dieta halal: não</string> <string name="poi_diet_halal_no">Pratos halal (árabe): não</string>
<string name="poi_diet_lactose_free_filter_yes">Livre de lactose</string> <string name="poi_diet_lactose_free_filter_yes">Pratos sem lactose: sim</string>
<string name="poi_diet_lactose_free_only">Apenas livre de lactose</string> <string name="poi_diet_lactose_free_only">Pratos sem lactose: unicamente</string>
<string name="poi_diet_lactose_free_yes">Livre de lactose</string> <string name="poi_diet_lactose_free_yes">Pratos sem lactose: sim</string>
<string name="poi_diet_lactose_free_no">Dieta livre de lactose: não</string> <string name="poi_diet_lactose_free_no">Pratos sem lactose: não</string>
<string name="poi_diet_pescetarian_yes">Piscitariana (peixes e vegetais)</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_yes">Sim</string>
<string name="poi_drive_in_no">Serviço a conduzir: não</string> <string name="poi_drive_in_no">Serviço a conduzir: não</string>
<string name="poi_drive_through_yes">Sim</string> <string name="poi_drive_through_yes">Sim</string>
@ -1771,7 +1771,7 @@
<string name="poi_vending_toys">Brinquedos</string> <string name="poi_vending_toys">Brinquedos</string>
<string name="poi_vending_ice_cream">Gelados</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_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_war">Memorial de guerra</string>
<string name="poi_memorial_plaque">Placa comemorativa</string> <string name="poi_memorial_plaque">Placa comemorativa</string>
<string name="poi_memorial_statue">Estátua</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_even">Condição dos degraus: regular</string>
<string name="poi_step_condition_uneven">Condição dos degraus: irregular</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_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">Desfibrilhador</string>
<string name="poi_defibrillator_yes">Desfibrilhador: sim</string> <string name="poi_defibrillator_yes">Desfibrilhador: sim</string>
<string name="poi_tomb_war_grave">Tipo: túmulo de guerra</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_sconce">Tipo de fortificação: arandela</string>
<string name="poi_fortification_type_ring_ditch">Tipo de fortificação: vala circular</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_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_railway_station">Estação ferroviária histórica</string>
<string name="poi_historic_threshing_floor">Eira 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_gallows">Forca histórica</string>
<string name="poi_historic_railway">Ferrovia 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_artist_name">Artista</string>
<string name="poi_sculptor">Escultor</string> <string name="poi_sculptor">Escultor</string>
<string name="poi_building_type_church">Tipo de edifício: igreja</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_behavior_yes">Comportamental</string>
<string name="poi_health_specialty_palliative_medicine_yes">Medicina paliativa</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_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_fitness">Exercício físico</string>
<string name="poi_billiards">Bilhar</string> <string name="poi_billiards">Bilhar</string>
<string name="poi_microwave_oven_yes">Forno microondas: sim</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_nutrition_supplements">Suplementos alimentares</string>
<string name="poi_photo_studio">Estúdio de fotografia</string> <string name="poi_photo_studio">Estúdio de fotografia</string>
<string name="poi_cliff">Penhasco</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_horse">Cativeiro de animais: cavalos</string>
<string name="poi_animal_keeping_sheep">Cativeiro de animais: ovelhas</string> <string name="poi_animal_keeping_sheep">Cativeiro de animais: ovelhas</string>
<string name="poi_animal_keeping_type_paddock">Tipo: cercado</string> <string name="poi_animal_keeping_type_paddock">Tipo: cercado</string>
@ -3118,7 +3118,7 @@
<string name="poi_stands">Estandes</string> <string name="poi_stands">Estandes</string>
<string name="poi_motorcycle_sales_yes">Vendas</string> <string name="poi_motorcycle_sales_yes">Vendas</string>
<string name="poi_motorcycle_sales_no">Vendas: não</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_sales_used">Vendas: usados</string>
<string name="poi_motorcycle_rental_yes">Aluguer</string> <string name="poi_motorcycle_rental_yes">Aluguer</string>
<string name="poi_motorcycle_rental_no">Aluguer: não</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_transportation">Instituição governamental de transportes</string>
<string name="poi_government_legislative">Instituição legislativa governamental</string> <string name="poi_government_legislative">Instituição legislativa governamental</string>
<string name="poi_vhf">Canal VHF</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_couloir">Ravina</string>
<string name="poi_mountain_area">Área montanhosa</string> <string name="poi_mountain_area">Área montanhosa</string>
<string name="poi_surface_clay">Argila</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_yes">Mesa muda-fraldas: sim</string>
<string name="poi_changing_table_no">Mesa muda-fraldas: não</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_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_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_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> <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_traffic_signals_vibration">Vibração</string>
<string name="poi_city_block">Quarteirão</string> <string name="poi_city_block">Quarteirão</string>
<string name="poi_borough">Município</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_traffic_signals_arrow_no">Seta: não</string>
<string name="poi_elevator">Elevador</string> <string name="poi_elevator">Elevador</string>
<string name="poi_departures_board_timetable">Horário</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_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_closed">Estado da pista: fechada</string>
<string name="poi_piste_status_open">Estado da pista: aberta</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_no">Supervisionado: não</string>
<string name="poi_patrolled_yes">Vigiado: sim</string> <string name="poi_patrolled_yes">Supervisionado: sim</string>
<string name="poi_piste_name">Nome da pista</string> <string name="poi_piste_name">Nome da pista</string>
<string name="poi_piste_ski_jump">Salto com esqui</string> <string name="poi_piste_ski_jump">Salto com esqui</string>
<string name="poi_wildlife_crossing">Passagem de vida selvagem</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_water_source_well">Poço</string>
<string name="poi_office_diplomatic">Gabinete diplomático</string> <string name="poi_office_diplomatic">Gabinete diplomático</string>
<string name="poi_bay_filter">Tipo de baía</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> </resources>

View file

@ -37,7 +37,7 @@
<string name="poi_filter_food_shop">Supermercado</string> <string name="poi_filter_food_shop">Supermercado</string>
<string name="poi_filter_for_tourists">Para turistas</string> <string name="poi_filter_for_tourists">Para turistas</string>
<string name="poi_filter_fuel">Combustível</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="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_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> <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> \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="unzipping_file">A descomprimir o ficheiro…</string>
<string name="route_tr">Vire à direita e continue em</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_tslr">Vire ligeiramente à direita e continue em</string>
<string name="route_tl">Vire à esquerda 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_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="route_head">Comece em</string>
<string name="first_time_continue">Continuar</string> <string name="first_time_continue">Continuar</string>
<string name="first_time_download">Descarregar regiões</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="search_nothing_found">Não foi encontrado nada</string>
<string name="searching">A pesquisar…</string> <string name="searching">A pesquisar…</string>
<string name="searching_address">A pesquisar o endereço …</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="hint_search_online">Pesquisa online: número da casa, rua, cidade</string>
<string name="search_offline_address">Pesquisa offline</string> <string name="search_offline_address">Pesquisa offline</string>
<string name="search_online_address">Pesquisa online</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">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="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="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="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> <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_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_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_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_comment_default">Alterar POI</string>
<string name="poi_dialog_other_tags_message">Todas as outras etiquetas são preservadas</string> <string name="poi_dialog_other_tags_message">Todas as outras etiquetas são preservadas</string>
<string name="default_buttons_commit">Enviar</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="modify_transparency">Definir a transparência (0 - transparente, 255 - opaco)</string>
<string name="confirm_interrupt_download">Cancelar o descarregamento\?</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="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="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_plugin_is_not_installed">Ative a extensão de \'Mapas online\' para selecionar diferentes origens de mapas</string>
<string name="map_online_data">Mapas on-line e mosaicos</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="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="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="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 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="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 \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 \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_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_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> <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="left">para a esquerda</string>
<string name="front_left">para a frente à esquerda</string> <string name="front_left">para a frente à esquerda</string>
<string name="oclock">horas</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="accuracy">Precisão</string>
<string name="altitude">Altitude</string> <string name="altitude">Altitude</string>
<string name="no_info">Sem informação</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_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">POIs / notas guardados no dispositivo</string>
<string name="local_openstreetmap_settings_descr">Mostrar e gerir POIs/notas do OSM guardados localmente.</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_descr">Especifique o intervalo de rastreamento online.</string>
<string name="live_monitoring_interval">Intervalo de rastreamento on-line</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_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="live_monitoring_url">Endereço web de rastreamento online</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="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="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_message">Pode descarregar ou atualizar %1$s mapas.</string>
<string name="free_version_title">Versão gratuita</string> <string name="free_version_title">Versão gratuita</string>
@ -562,7 +562,7 @@
<string name="shared_string_undefined">Sem definir</string> <string name="shared_string_undefined">Sem definir</string>
<string name="search_position_map_view">Centro do mapa atual</string> <string name="search_position_map_view">Centro do mapa atual</string>
<string name="select_search_position">Origem:</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="route_successfully_saved_at">Rota guardada como \'%1$s\'.</string>
<string name="filename_input">Nome do ficheiro:</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> <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="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_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="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 \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="specified_dir_doesnt_exist">Não foi possível encontrar a pasta especificada.</string>
<string name="application_dir">Local de armazenamento</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> <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). <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> \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="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="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="starting_point_too_far">Ponto de partida demasiado distante da estrada mais próxima.</string>
<string name="shared_location">Local partilhado</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="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_cameras">Radares de velocidade</string>
<string name="show_traffic_warnings">Informações de circulação</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_top_text">Nome da rua</string>
<string name="map_widget_config">Configuração do ecrã</string> <string name="map_widget_config">Configuração do ecrã</string>
<string name="map_widget_back_to_loc">Onde estou</string> <string name="map_widget_back_to_loc">Onde estou</string>
@ -763,10 +763,10 @@
\na execução em segundo plano</string> \na execução em segundo plano</string>
<string name="show_warnings_title">Mostrar alertas…</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="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="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_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="filterpoi_activity">Criar filtro de POI</string>
<string name="select_navigation_mode">Meio de transporte:</string> <string name="select_navigation_mode">Meio de transporte:</string>
<string name="day_night_info_description">Nascer do sol: %1$s <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="map_widget_renderer">Estilo de renderização</string>
<string name="layer_map_appearance">Configurar ecrã</string> <string name="layer_map_appearance">Configurar ecrã</string>
<string name="show_lanes">Mostrar faixas de rodagem</string> <string name="show_lanes">Mostrar faixas de rodagem</string>
<string name="avoid_unpaved">Sem estradas não pavimentadas</string> <string name="avoid_unpaved">Evitar estradas não pavimentadas</string>
<string name="avoid_ferries">Sem balsas/ferries</string> <string name="avoid_ferries">Evitar balsas/ferries</string>
<string name="avoid_in_routing_title">Evitar…</string> <string name="avoid_in_routing_title">Evitar…</string>
<string name="map_widget_fluorescent">Rotas fluorescentes</string> <string name="map_widget_fluorescent">Rotas fluorescentes</string>
<string name="map_widget_show_ruler">Régua</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_description">Selecione um esquema de cores de estrada:</string>
<string name="rendering_attr_roadColors_name">Esquema de cores</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="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="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="gps_not_available">Ative o GPS nas configurações</string>
<string name="map_widget_monitoring_services">Serviços de registo</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="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="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_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_descr">Ação predefinida do widget:</string>
<string name="av_widget_action">Ação widget padrão</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> <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="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_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="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="dropbox_plugin_name">Extensão Dropbox</string>
<string name="intermediate_points_change_order">Alterar ordem</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> <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_def_action_choose">A pedido\?</string>
<string name="av_video_format_descr">Formato de saída de vídeo:</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_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="av_use_external_camera">Usar aplicação da câmara</string>
<string name="recording_playing">A reproduzir o áudio da gravação. <string name="recording_playing">A reproduzir o áudio da gravação.
\n%1$s</string> \n%1$s</string>
@ -901,7 +901,7 @@
<string name="shared_string_control_stop">Parar</string> <string name="shared_string_control_stop">Parar</string>
<string name="shared_string_control_start">Iniciar</string> <string name="shared_string_control_start">Iniciar</string>
<string name="map_widget_av_notes">Notas de áudio/vídeo</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="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="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> <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="audionotes_plugin_name">Notas de áudio/vídeo</string>
<string name="index_srtm_parts">Partes</string> <string name="index_srtm_parts">Partes</string>
<string name="index_srtm_ele">Curvas de nível</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="recording_photo_description">Fotografia %1$s de %2$s</string>
<string name="av_def_action_picture">Tirar uma foto</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. <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 \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> \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="srtm_plugin_name">Curvas de nível</string>
<string name="download_select_map_types">Outros mapas</string> <string name="download_select_map_types">Outros mapas</string>
<string name="download_srtm_maps">Curvas de nível</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="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="recording_context_menu_show">Ver</string>
<string name="item_unchecked">desmarcado</string> <string name="item_unchecked">desmarcado</string>
@ -948,7 +948,7 @@
<string name="files_limit">%1$d ficheiros restantes</string> <string name="files_limit">%1$d ficheiros restantes</string>
<string name="available_downloads_left">Faltam %1$d ficheiros para descarregar</string> <string name="available_downloads_left">Faltam %1$d ficheiros para descarregar</string>
<string name="install_paid">Versão completa</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="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_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> <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_auto">Focagem automática</string>
<string name="av_camera_focus_hiperfocal">Foco hiperfocal</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_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_macro">Focagem macro (close-up)</string>
<string name="av_camera_focus_continuous">A câmara tenta focar continuadamente</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> <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="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="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="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="amenity_type_seamark">Marca marítima</string>
<string name="app_modes_choose_descr">Escolha os perfis a mostrar.</string> <string name="app_modes_choose_descr">Escolha os perfis a mostrar.</string>
<string name="app_modes_choose">Perfis da aplicação</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_en">Inglês</string>
<string name="lang_af">Africâner</string> <string name="lang_af">Africâner</string>
<string name="lang_hy">Arménio</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="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="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> <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="route_info">Informações da rota</string>
<string name="routing_attr_prefer_motorway_name">Preferir autoestradas</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_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_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_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_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_avoid_motorway_description">Evita autoestradas</string>
<string name="routing_attr_weight_name">Peso máximo</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> <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_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_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="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="app_mode_truck">Camião</string>
<string name="lang_eu">Basco</string> <string name="lang_eu">Basco</string>
<string name="lang_be">Bielorrusso</string> <string name="lang_be">Bielorrusso</string>
@ -1323,7 +1323,7 @@
<string name="storage_directory">Armazenamento do mapa</string> <string name="storage_directory">Armazenamento do mapa</string>
<string name="shared_string_copy">Copiar</string> <string name="shared_string_copy">Copiar</string>
<string name="filter_poi_hint">Filtrar por nome</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="shared_string_is_open">Aberto agora</string>
<string name="rendering_attr_OSMMapperAssistant_name">Assistente de mapeador OSM</string> <string name="rendering_attr_OSMMapperAssistant_name">Assistente de mapeador OSM</string>
<string name="agps_info">Informação A-GPS</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_attr_streetLighting_name">Iluminação pública</string>
<string name="rendering_value__name">Predefinido</string> <string name="rendering_value__name">Predefinido</string>
<string name="rendering_value_highContrastRoads_name">Estradas em alto contraste</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="welcome_header">Bem-vindo(a)</string>
<string name="current_route">Rota atual</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> <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_currently_recording_track">A gravar o trajeto</string>
<string name="shared_string_audio">Áudio</string> <string name="shared_string_audio">Áudio</string>
<string name="shared_string_video">Vídeo</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="route_points">Pontos de rota</string>
<string name="track_segments">Segmentos do trajeto</string> <string name="track_segments">Segmentos do trajeto</string>
<string name="track_points">Pontos do trajeto</string> <string name="track_points">Pontos do trajeto</string>
@ -1410,13 +1410,13 @@
<string name="share_note">Partilhar nota</string> <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="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="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="roads_only">Apenas estradas</string>
<string name="rendering_attr_pisteRoutes_name">Pistas de esqui</string> <string name="rendering_attr_pisteRoutes_name">Pistas de esqui</string>
<string name="free">%1$s livre</string> <string name="free">%1$s livre</string>
<string name="device_memory">Memória do dispositivo</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="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 off-line 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="edit_group">Editar grupo</string>
<string name="parking_place">Lugar de estacionamento</string> <string name="parking_place">Lugar de estacionamento</string>
<string name="version_settings">Compilações</string> <string name="version_settings">Compilações</string>
@ -1426,7 +1426,7 @@
<string name="wake_on_voice">Ligar o ecrã</string> <string name="wake_on_voice">Ligar o ecrã</string>
<string name="configure_map">Configurar mapa</string> <string name="configure_map">Configurar mapa</string>
<string name="shared_string_waypoints">Pontos de rota</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_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_showAccess_name">Mostrar restrições de acesso e portagens</string>
<string name="rendering_attr_showSurfaceGrade_name">Mostrar qualidade da via</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_coloredBuildings_name">Colorir edifícios por tipo</string>
<string name="rendering_attr_alpineHiking_name">Escala de montanhismo (SAC)</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_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_hideBuildings_name">Edifícios</string>
<string name="rendering_attr_trolleybusRoutes_name">Rotas de troleicarros</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> <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_description">\'Desligado\' abre o mapa diretamente.</string>
<string name="show_on_start">Mostrar no arranque</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="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="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="impassable_road_desc">Escolha as estradas que quer evitar durante a navegação.</string>
<string name="shared_string_sound">Som</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="share_osm_edits_subject">Edições OSM partilhadas via OsmAnd</string>
<string name="read_more">Ler mais</string> <string name="read_more">Ler mais</string>
<string name="whats_new">Novidades</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="shared_string_upload">Enviar</string>
<string name="osm_edit_created_poi">POI OSM adicionado</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> <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_descr">Ficheiro GPX com localizações.</string>
<string name="av_locations">Localizações</string> <string name="av_locations">Localizações</string>
<string name="plugin_settings">Extensõ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="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="traffic_warning_hazard">Perigo</string>
<string name="rendering_value_boldOutline_name">Contorno em negrito</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_value_defaultTranslucentCyan_name">Padrão (ciano translúcido)</string>
<string name="rendering_attr_currentTrackColor_name">Cor GPX</string> <string name="rendering_attr_currentTrackColor_name">Cor GPX</string>
<string name="rendering_attr_currentTrackColor_description">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_name">Espessura dos trilhos GPX</string>
<string name="rendering_attr_currentTrackWidth_description">Espessura 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_red_name">Vermelho</string>
<string name="rendering_value_translucent_red_name">Vermelho translúcido</string> <string name="rendering_value_translucent_red_name">Vermelho translúcido</string>
<string name="rendering_value_translucent_orange_name">Laranja 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="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="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="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="shared_string_wikipedia">Wikipédia</string>
<string name="local_indexes_cat_wiki">Wikipédia</string> <string name="local_indexes_cat_wiki">Wikipédia</string>
<string name="shared_string_show_details">Mostrar detalhes</string> <string name="shared_string_show_details">Mostrar detalhes</string>
@ -1659,7 +1659,7 @@
<string name="map_mode">Modo do mapa</string> <string name="map_mode">Modo do mapa</string>
<string name="rendering_value_thin_name">Fino</string> <string name="rendering_value_thin_name">Fino</string>
<string name="rendering_value_medium_name">Médio</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="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_up">Mover ↑</string>
<string name="shared_string_move_down">Mover ↓</string> <string name="shared_string_move_down">Mover ↓</string>
@ -1754,7 +1754,7 @@
<string name="map_markers">Marcadores</string> <string name="map_markers">Marcadores</string>
<string name="map_marker">Marcador de mapa</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="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="show_polygons">Mostrar polígonos</string>
<string name="find_parking">Encontrar estacionamento</string> <string name="find_parking">Encontrar estacionamento</string>
<string name="shared_string_status">Situação</string> <string name="shared_string_status">Situação</string>
@ -1768,7 +1768,7 @@
<string name="road_blocked">Estrada bloqueada</string> <string name="road_blocked">Estrada bloqueada</string>
<string name="shared_string_select">Selecionar</string> <string name="shared_string_select">Selecionar</string>
<string name="switch_start_finish">Inverter ponto de partida e destino</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="item_removed">Item removido</string>
<string name="n_items_removed">Itens removidos</string> <string name="n_items_removed">Itens removidos</string>
<string name="shared_string_undo_all">Desfazer tudo</string> <string name="shared_string_undo_all">Desfazer tudo</string>
@ -1776,7 +1776,7 @@
<string name="starting_point">Ponto de partida</string> <string name="starting_point">Ponto de partida</string>
<string name="rec_split">Divisão das gravações</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_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="rec_split_clip_length_desc">Limite de tempo máximo para clipes gravados.</string>
<string name="lang_mk">Macedónio</string> <string name="lang_mk">Macedónio</string>
<string name="lang_sh">Servo-Croata</string> <string name="lang_sh">Servo-Croata</string>
@ -1807,14 +1807,14 @@
<string name="search_another_country">Selecionar outra região</string> <string name="search_another_country">Selecionar outra região</string>
<string name="shared_string_change">Alterar</string> <string name="shared_string_change">Alterar</string>
<string name="storage_directory_card">Cartão de memória</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="shared_string_markers">Marcadores</string>
<string name="coordinates_format">Formato de coordenadas</string> <string name="coordinates_format">Formato de coordenadas</string>
<string name="use_system_keyboard">Usar teclado do sistema</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_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="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_name">Evitar 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_description">Evitar estradas de gelo e vaus (passagens em riachos baixos).</string>
<string name="use_location">Usar posição</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="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> <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="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="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="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_guide_line">Mostrar linhas para marcadores</string>
<string name="show_arrows_on_the_map">Mostrar setas no mapa</string> <string name="show_arrows_on_the_map">Mostrar setas para marcadores</string>
<string name="show_passed">Mostrar passado</string> <string name="show_passed">Mostrar passado</string>
<string name="hide_passed">Esconder o passado</string> <string name="hide_passed">Esconder o passado</string>
<string name="remove_from_map_markers">Remover dos \'Marcadores do mapa\'</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="shared_string_install">Instalar</string>
<string name="improve_coverage_mapillary">Melhorar cobertura fotográfica com Mapillary</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="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="online_photos">Fotografias na Internet</string>
<string name="shared_string_add_photos">Adicionar fotos</string> <string name="shared_string_add_photos">Adicionar fotografias</string>
<string name="no_photos_descr">Não há fotos aqui.</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_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">Widget Mapillary</string>
<string name="mapillary_widget_descr">Permite contribuir rapidamente para o 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="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="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="restart_search">Reiniciar pesquisa</string>
<string name="increase_search_radius">Aumentar raio de 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_high_name">Alto</string>
<string name="rendering_value_medium_w_name">Médio</string> <string name="rendering_value_medium_w_name">Médio</string>
<string name="rendering_value_low_name">Baixo</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_description">Espessura das curvas de nível</string>
<string name="rendering_attr_contourWidth_name">Largura 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_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_name">Utilizar autoestradas</string>
<string name="routing_attr_allow_motorway_description">Permitir autoestradas.</string> <string name="routing_attr_allow_motorway_description">Permitir autoestradas.</string>
<string name="wiki_around">Artigos da Wikipédia próximos</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_paused">Em pausa</string>
<string name="shared_string_trip">Viagem</string> <string name="shared_string_trip">Viagem</string>
<string name="shared_string_recorded">Gravado</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="gpx_logging_no_data">Sem dados</string>
<string name="rendering_attr_contourColorScheme_description">Esquema de cores das curvas de nível</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> <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="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="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="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="show_full_description">Mostrar a descrição completa</string>
<string name="thank_you_for_feedback">Obrigado pelos seus comentários</string> <string name="thank_you_for_feedback">Obrigado pelos seus comentários</string>
<string name="search_street">Procurar rua</string> <string name="search_street">Procurar rua</string>
<string name="shared_string_restore">Restaurar</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_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 passados no 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="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="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> <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="shared_string_wifi_only">Apenas em Wi-Fi</string>
<string name="select_travel_book">Selecione um livro de viagem</string> <string name="select_travel_book">Selecione um livro de viagem</string>
<string name="shared_string_travel_book">Livro de viagens</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="images_cache">Cache de imagens</string>
<string name="delete_search_history">Eliminar histórico de pesquisa</string> <string name="delete_search_history">Eliminar histórico de pesquisa</string>
<string name="download_images">Descarregar imagens</string> <string name="download_images">Descarregar imagens</string>
@ -2240,11 +2240,11 @@
<string name="enter_lon">Digite a longitude</string> <string name="enter_lon">Digite a longitude</string>
<string name="enter_lat">Digite a latitude</string> <string name="enter_lat">Digite a latitude</string>
<string name="enter_lat_and_lon">Digite a latitude e a longitude</string> <string name="enter_lat_and_lon">Digite a latitude e a longitude</string>
<string name="dd_mm_ss_format">DD°MMSS″</string> <string name="dd_mm_ss_format">GG°MMSS″</string>
<string name="dd_dddddd_format">DD.DDDDDD°</string> <string name="dd_dddddd_format">GG.GGGGGG°</string>
<string name="dd_ddddd_format">DD.DDDDD°</string> <string name="dd_ddddd_format">GG.GGGGG°</string>
<string name="dd_mm_mmmm_format">DD°MM.MMMM</string> <string name="dd_mm_mmmm_format">GG°MM.MMMM</string>
<string name="dd_mm_mmm_format">DD°MM.MMM</string> <string name="dd_mm_mmm_format">GG°MM.MMM</string>
<string name="east_abbreviation">E</string> <string name="east_abbreviation">E</string>
<string name="west_abbreviation">O</string> <string name="west_abbreviation">O</string>
<string name="south_abbreviation">S</string> <string name="south_abbreviation">S</string>
@ -2261,7 +2261,7 @@
<string name="first_intermediate_dest_description">Adicionar paragem inicial</string> <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="subsequent_dest_description">Mover destino para cima e criar destino</string>
<string name="show_closed_notes">Mostrar notas fechadas</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="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="osc_file_desc">OSC - adequado para exportar para o OSM.</string>
<string name="shared_string_gpx_file">Ficheiro GPX</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_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="one_tap_active">\'Um toque\' ativo</string>
<string name="empty_state_av_notes">Faça notas!</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="notes_by_date">Notas de áudio/vídeo por data</string>
<string name="by_date">Por data</string> <string name="by_date">Por data</string>
<string name="by_type">Por tipo</string> <string name="by_type">Por tipo</string>
@ -2321,7 +2321,7 @@
<string name="shared_string_two">Dois</string> <string name="shared_string_two">Dois</string>
<string name="shared_string_one">Um</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_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="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="active_markers_descr">Especifique a quantidade de indicadores de orientação.</string>
<string name="digits_quantity">Número de casas decimais</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="show_number_pad">Mostrar teclado numérico</string>
<string name="shared_string_paste">Colar</string> <string name="shared_string_paste">Colar</string>
<string name="go_to_next_field">Próximo campo</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_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="tap_on_map_to_hide_interface">Modo ecrã cheio</string>
<string name="mark_passed">Marcador visitado</string> <string name="mark_passed">Marcador visitado</string>
@ -2459,9 +2459,9 @@
<string name="forward">Avançar</string> <string name="forward">Avançar</string>
<string name="home">Painel de controlo</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_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_m">Rastreamento online (requer GPX)</string>
<string name="live_monitoring_start">Iniciar rastreamento on-line</string> <string name="live_monitoring_start">Iniciar rastreamento online</string>
<string name="live_monitoring_stop">Parar rastreamento on-line</string> <string name="live_monitoring_stop">Parar rastreamento online</string>
<string name="gpx_start_new_segment">Iniciar novo segmento</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_hideNonVehicleHighways_name">Estradas não transitáveis</string>
<string name="rendering_attr_hideText_name">Texto</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_cn">Chinês (simplificado)</string>
<string name="lang_zh_hk">Chinês (Hong Kong)</string> <string name="lang_zh_hk">Chinês (Hong Kong)</string>
<string name="lang_zh_tw">Chinês (tradicional)</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_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_avoid_borders_description">Evita cruzar fronteiras nacionais</string>
<string name="routing_attr_height_name">Altura máxima</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> <string name="routing_attr_height_description">Especifique a altura permitida do veículo nas rotas.</string>
@ -2504,7 +2504,7 @@
\n \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> \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 <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• 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• 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 \n• Orientação de pista, nomes de ruas e tempo estimado de chegada ajudará ao longo do caminho
@ -2515,14 +2515,14 @@
\n• Suporta pontos intermédios no seu itinerário \n• Suporta pontos intermédios no seu itinerário
\n• Grave ou envie um trilho GPX e siga-a \n• Grave ou envie um trilho GPX e siga-a
\n</string> \n</string>
<string name="osmand_extended_description_part3">Mapa <string name="osmand_extended_description_part3">Mapa
\n• Mostra POIs (ponto de interesse) perto de si \n• Mostra POIs (ponto de interesse) perto de si
\n• Ajusta o mapa na sua direção de movimento (ou bússola) \n• Ajusta o mapa na sua direção de movimento (ou bússola)
\n• Mostra a sua posição e direção para onde está olhando \n• Mostra a sua posição e direção para onde está olhando
\n• Partilhe sua posição para que seus amigos possam encontrá-lo \n• Partilhe sua posição para que seus amigos possam encontrá-lo
\n• Mantém seus lugares mais importantes em \'Favoritos\' \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• 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> \n</string>
<string name="osmand_extended_description_part4">Esqui <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> \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 \n
\nAlgumas das características principais:</string> \nAlgumas das características principais:</string>
<string name="osmand_plus_extended_description_part2">Navegação <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 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• 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 \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 • Dados do OpenStreetMap disponíveis por país ou região
\n • POIs da Wikipédia, ótimo para passeios turísticos \n • POIs da Wikipédia, ótimo para passeios turísticos
\n • Descarregamentos grátis ilimitados, diretamente da aplicação \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
\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> \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 <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• 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• 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• 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 opcional de velocidade e altitudes
\n• Visualização de curvas de nível e sombreamento de relevo (com uma extensão adicional)</string> \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 <string name="osmand_plus_extended_description_part7">Contribua diretamente para o OpenStreetMap
\n • Envie relatórios de erros. \n• Envie relatórios de erros.
\n • Envie trilhos GPX para o OpenStreetMap diretamente da aplicação. \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• 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• 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 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> \n</string>
<string name="osmand_plus_extended_description_part8">Cobertura de mapa e qualidade aproximada: <string name="osmand_plus_extended_description_part8">Cobertura de mapa e qualidade aproximada:
\n• Europa Ocidental: **** \n• Europa Ocidental: ****
@ -2627,7 +2627,7 @@
<string name="arrival_distance_factor_normally">Normal</string> <string name="arrival_distance_factor_normally">Normal</string>
<string name="arrival_distance_factor_late">Atrasado</string> <string name="arrival_distance_factor_late">Atrasado</string>
<string name="arrival_distance_factor_at_last">Nos últimos metros</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="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="index_name_netherlands">Europa - Países Baixos</string>
<string name="shared_string_others">Outros</string> <string name="shared_string_others">Outros</string>
@ -2636,7 +2636,7 @@
<string name="favourites_context_menu_add">Adicionar favorito</string> <string name="favourites_context_menu_add">Adicionar favorito</string>
<string name="poi_action_delete">eliminar</string> <string name="poi_action_delete">eliminar</string>
<string name="poi_dialog_reopen">Reabrir</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="av_camera_pic_size_descr">Definir o tamanho da imagem</string>
<string name="get_plugin">Obter</string> <string name="get_plugin">Obter</string>
<string name="use_fast_recalculation">Recálculo de rota inteligente</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="shared_string_undo">Desfazer</string>
<string name="app_name_osmand">OsmAnd</string> <string name="app_name_osmand">OsmAnd</string>
<string name="offline_maps_and_navigation">Mapas e navegação <string name="offline_maps_and_navigation">Mapas e navegação
\noff-line</string> \noffline</string>
<string name="commit_poi">Enviar POI</string> <string name="commit_poi">Enviar POI</string>
<string name="tab_title_basic">Básico</string> <string name="tab_title_basic">Básico</string>
<string name="tab_title_advanced">Avançado</string> <string name="tab_title_advanced">Avançado</string>
@ -2685,7 +2685,7 @@
<string name="file_size_in_mb">%.1f MB</string> <string name="file_size_in_mb">%.1f MB</string>
<string name="update_all">Atualizar tudo (%1$s 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="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_action">Ação %d</string>
<string name="quick_action_item_screen">Ecrã %d</string> <string name="quick_action_item_screen">Ecrã %d</string>
<string name="quick_action_add_marker">Adicionar marcador de mapa</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_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_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_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_add_osm_bug">Adicionar nota OSM</string>
<string name="quick_action_navigation_voice">Ligar/desligar voz</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_off">Ativar voz</string>
<string name="quick_action_navigation_voice_on">Desativar 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_add_parking">Adicionar local de estacionamento</string>
<string name="quick_action_new_action">Adicionar ação</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="quick_action_add_favorite">Adicionar favorito</string>
<string name="dialog_add_action_title">Adicionar ação</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">Eliminar botão de ação rápida</string>
<string name="quick_actions_delete_text">Tem a certeza de que quer eliminar a ação \"%s\"\?</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_show_favorites_dialog">Mostrar lista dos favoritos</string>
<string name="quick_favorites_name_preset">Nome do modelo</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_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_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_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_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_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_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> <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="quick_action_interim_dialog">Mostrar uma janela temporal</string>
<string name="favorite_autofill_toast_text">" guardado em "</string> <string name="favorite_autofill_toast_text">" guardado em "</string>
<string name="favorite_empty_place_name">Local</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_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 de ação rápida duplicado</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_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_showhide_poi_descr">Uma alternância para mostrar ou ocultar POIs no mapa.</string>
<string name="quick_action_poi_show">Mostrar %1$s</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_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_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_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="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="retry">Repetir</string>
<string name="add_route_points">Adicionar pontos de rota</string> <string name="add_route_points">Adicionar pontos de rota</string>
<string name="add_waypoint">Adicionar ponto de passagem</string> <string name="add_waypoint">Adicionar ponto de passagem</string>
@ -2782,7 +2782,7 @@
<string name="show_tunnels">Túneis</string> <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_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="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="open_in_browser_wiki_description">Ver artigo no navegador web.</string>
<string name="download_wiki_region_placeholder">esta região</string> <string name="download_wiki_region_placeholder">esta região</string>
<string name="wiki_article_search_text">A procurar o artigo wiki correspondente</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="show_more">Mostrar mais</string>
<string name="tracks_on_map">Trilhos mostrados</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="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_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_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_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_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_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="routing_attr_avoid_ferry_description">Evita balsas/ferries</string>
<string name="shared_string_milliradians">Milirradianos</string> <string name="shared_string_milliradians">Milirradianos</string>
<string name="rendering_attr_surface_sett_name">Paralelos</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="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_descr">Escolha os perfis mostrados na aplicação.</string>
<string name="application_profiles">Perfis da 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_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_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> <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="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="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="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_current_profile">Aplicar só a \"%1$s\"</string>
<string name="apply_to_all_profiles">Aplicar a todos os perfis</string> <string name="apply_to_all_profiles">Aplicar a todos os perfis</string>
<string name="start_up_message_pref">Mensagem de inicialização</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="empty_filename">O nome do ficheiro está vazio</string>
<string name="shared_string_revert">Reverter</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="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="clear_confirmation_msg">Limpar %1$s\?</string>
<string name="download_map_dialog">Diálogo de descarregar mapas</string> <string name="download_map_dialog">Diálogo de descarregar mapas</string>
<string name="dialogs_and_notifications_title">Diálogos e notificações</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="osm_authorization_success">Autorização bem sucedida</string>
<string name="multimedia_photo_play_sound">Som do obturador da câmara</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_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="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_distance">Deslocamento mínimo</string>
<string name="monitoring_min_accuracy">Precisão mínima</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="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_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_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_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_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> <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="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\". <string name="ui_customization_description">Personalize a quantidade de itens em \"Gaveta\", \"Configurar Mapa\" e \"Menu de Contexto\".
\n \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_short_descr">Itens da gaveta, menu de contexto</string>
<string name="ui_customization">Personalização da interface</string> <string name="ui_customization">Personalização da interface</string>
<string name="shared_string_drawer">Gaveta</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="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="mapillary_item">OsmAnd + Mapillary</string>
<string name="tracker_item">OsmAnd Tracker</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="radius_ruler_item">Régua radial</string>
<string name="measure_distance_item">Medir distância</string> <string name="measure_distance_item">Medir distância</string>
<string name="travel_item">Viagem (Wikivoyage e Wikipédia)</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="pseudo_mercator_projection">Projeção pseudo-Mercator</string>
<string name="one_image_per_tile">Um ficheiro de imagem por mosaico</string> <string name="one_image_per_tile">Um ficheiro de imagem por mosaico</string>
<string name="sqlite_db_file">Ficheiro SQLiteDB</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_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 on-line.</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 on-line</string> <string name="edit_online_source">Editar origem online</string>
<string name="expire_time">Tempo de validade</string> <string name="expire_time">Tempo de validade</string>
<string name="mercator_projection">Projeção de Mercator</string> <string name="mercator_projection">Projeção de Mercator</string>
<string name="storage_format">Formato de armazenamento</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. \nSelecione %1$s e receberá alertas e avisos sobre radares de velocidade.
\n \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> \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="app_mode_motor_scooter">Scooter</string>
<string name="quick_action_remove_next_destination">Eliminar o ponto de destino mais próximo</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> <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_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="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="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_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="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> <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_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_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="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="overwrite_track">Substituir trilho</string>
<string name="save_as_new_track">Guardar como novo trilho</string> <string name="save_as_new_track">Guardar como novo trilho</string>
<string name="reverse_route">Rota inversa</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="save_track_to_gpx_globally">Registar o trilho num ficheiro GPX</string>
<string name="layer_gpx_layer">Trilhos</string> <string name="layer_gpx_layer">Trilhos</string>
<string name="context_menu_item_add_waypoint">Adicionar ponto de passagem de trilho</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="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_stop">Pausar a gravação da viagem</string>
<string name="gpx_monitoring_start">Retomar 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> <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_close_note">Fechar nota do OSM</string>
<string name="osm_edit_comment_note">Comentário de 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="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 <string name="register_on_openplacereviews">Crie uma conta em
\nOpenPlaceReviews.org</string> \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_create_new_account">Criar uma conta</string>
<string name="register_opr_have_account">Já tenho 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> <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="analyze_by_intervals">Analisar por intervalos</string>
<string name="upload_to_openstreetmap">Enviar para OpenStreetMap</string> <string name="upload_to_openstreetmap">Enviar para OpenStreetMap</string>
<string name="edit_track">Editar trilho</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="change_folder">Mudar pasta</string>
<string name="hillshade_slope_contour_lines">Sombras de relevo / declives / curvas de nível</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 \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 \n
\nPode ler mais em: http://openplacereviews.org</string> \nPode ler mais em: http://openplacereviews.org</string>
<string name="open_place_reviews">OpenPlaceReviews</string> <string name="open_place_reviews">OpenPlaceReviews</string>
@ -3962,11 +3962,11 @@
<string name="live_update_delete_updates_msg">Tem a certeza que quer eliminar todas as %s atualizações OsmAnd Live\?</string> <string name="live_update_delete_updates_msg">Tem a certeza que quer eliminar todas as %s atualizações OsmAnd Live\?</string>
<string name="release_4_0_beta">• Atualizações OsmAnd Live movidas para \"Descarregamentos &gt; Atualizações\" <string name="release_4_0_beta">• Atualizações OsmAnd Live movidas para \"Descarregamentos &gt; Atualizações\"
\n \n
\n • Os trilhos podem ser agora coloridos conforme a altitude, velocidade e declive. \n• Os trilhos podem ser agora coloridos conforme a altitude, velocidade e declive.
\n \n
\n • Adicionada opção para alterar a aparência da linha de rota de navegação \n• Adicionada opção para alterar a aparência da linha de rota de navegação
\n \n
\n • Janela de diálogo \"Gravação do trilho\" atualizada \n• Janela de diálogo \"Gravação do trilho\" atualizada
\n \n
\n</string> \n</string>
<string name="routing_attr_height_obstacles_description">O roteamento pode evitar subidas íngremes.</string> <string name="routing_attr_height_obstacles_description">O roteamento pode evitar subidas íngremes.</string>
@ -4025,7 +4025,7 @@
<string name="no_purchases">Não tem compras</string> <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="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="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="contact_support">Contacte o suporte</string>
<string name="troubleshooting_description">Por favor siga este link se tiver algum problema com assinaturas.</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> <string name="update_all_maps_added">Atualizar todos os mapas para %1$s\?</string>

View file

@ -141,8 +141,8 @@
<string name="routing_attr_height_obstacles_name">Использовать данные о высотах</string> <string name="routing_attr_height_obstacles_name">Использовать данные о высотах</string>
<string name="quick_action_duplicates">Действие переименовано в %1$s, чтобы избежать дублирования.</string> <string name="quick_action_duplicates">Действие переименовано в %1$s, чтобы избежать дублирования.</string>
<string name="quick_action_duplicate">Обнаружен дубликат имени</string> <string name="quick_action_duplicate">Обнаружен дубликат имени</string>
<string name="quick_action_showhide_favorites_descr">Переключатель, чтобы показать или скрыть избранные точки на карте.</string> <string name="quick_action_showhide_favorites_descr">Переключатель для отображения или скрытия избранных точек на карте.</string>
<string name="quick_action_showhide_poi_descr">Переключатель, чтобы показать или скрыть POI на карте.</string> <string name="quick_action_showhide_poi_descr">Переключатель для отображения или скрытия POI на карте.</string>
<string name="quick_action_add_category">Категория</string> <string name="quick_action_add_category">Категория</string>
<string name="quick_action_add_create_items">Действия</string> <string name="quick_action_add_create_items">Действия</string>
<string name="quick_action_fav_name_descr">Если оставить это поле пустым, то оно будет автоматически заполнено адресом или названием места.</string> <string name="quick_action_fav_name_descr">Если оставить это поле пустым, то оно будет автоматически заполнено адресом или названием места.</string>
@ -3660,7 +3660,7 @@
<string name="vessel_height_warning">Вы можете указать высоту судна, чтобы избегать низких мостов. Имейте в виду, что если мост раздвижной, будет использована его высота в открытом состоянии.</string> <string name="vessel_height_warning">Вы можете указать высоту судна, чтобы избегать низких мостов. Имейте в виду, что если мост раздвижной, будет использована его высота в открытом состоянии.</string>
<string name="vessel_height_limit_description">Укажите высоту судна, чтобы избежать низких мостов. Имейте в виду, что если мост раздвижной, будет использована его высота в открытом состоянии.</string> <string name="vessel_height_limit_description">Укажите высоту судна, чтобы избежать низких мостов. Имейте в виду, что если мост раздвижной, будет использована его высота в открытом состоянии.</string>
<string name="vessel_width_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="shared_string_legal">Законодательство</string>
<string name="speed_cameras_legal_descr">В некоторых странах и регионах использование предупреждений о камерах контроля скорости запрещено законом. <string name="speed_cameras_legal_descr">В некоторых странах и регионах использование предупреждений о камерах контроля скорости запрещено законом.
\n \n

View file

@ -3926,4 +3926,6 @@
<string name="poi_hoops">Canisteddos</string> <string name="poi_hoops">Canisteddos</string>
<string name="poi_camp_pitch">Pratzola de acampamentu</string> <string name="poi_camp_pitch">Pratzola de acampamentu</string>
<string name="poi_bay_filter">Casta de baia</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> </resources>

View file

@ -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="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="map_orientation_threshold_descr">Neotáčať mapu, ak je rýchlosť nižšia ako hranica</string>
<string name="restart">Reštartovať</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="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_stop_without_saving">Zastaviť bez uloženia</string>
<string name="track_recording_save_and_stop">Uložiť a zastaviť záznam</string> <string name="track_recording_save_and_stop">Uložiť a zastaviť záznam</string>

View file

@ -3867,4 +3867,45 @@
<string name="poi_water_source_river">Река</string> <string name="poi_water_source_river">Река</string>
<string name="poi_vaccination_covid19">Цепљење: Ковид 19</string> <string name="poi_vaccination_covid19">Цепљење: Ковид 19</string>
<string name="poi_health_specialty_vaccination_yes">Цепљење</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> </resources>

View file

@ -662,7 +662,7 @@
<string name="share_osm_edits_subject">ОСМ измене дељене преко OsmAnd-а</string> <string name="share_osm_edits_subject">ОСМ измене дељене преко OsmAnd-а</string>
<string name="osm_edit_created_poi">OSM тачка од интереса је направљена</string> <string name="osm_edit_created_poi">OSM тачка од интереса је направљена</string>
<string name="nm">nmi</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_mile">min/m</string>
<string name="min_km">min/km</string> <string name="min_km">min/km</string>
<string name="m_s">m/s</string> <string name="m_s">m/s</string>
@ -922,7 +922,7 @@
<string name="rendering_attr_roadColors_name">Образац боја путева</string> <string name="rendering_attr_roadColors_name">Образац боја путева</string>
<string name="enable_plugin_monitoring_services">Омогућите додатак за „снимање путовања“ ради коришћења услуга бележења (GPX бележење, праћење положаја на мрежи)</string> <string name="enable_plugin_monitoring_services">Омогућите додатак за „снимање путовања“ ради коришћења услуга бележења (GPX бележење, праћење положаја на мрежи)</string>
<string name="non_optimal_route_calculation">Рачунај могућу приближну путању за велике раздаљине</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="map_widget_monitoring_services">Услуге бележења путање</string>
<string name="no_route">Нема пута</string> <string name="no_route">Нема пута</string>
<string name="arrived_at_intermediate_point">Стигли сте на пролазно одредиште</string> <string name="arrived_at_intermediate_point">Стигли сте на пролазно одредиште</string>
@ -1005,7 +1005,7 @@
<string name="new_filter_desc">Молимо, унесите име новог филтера који ће бити придодат језичку „Категорије“.</string> <string name="new_filter_desc">Молимо, унесите име новог филтера који ће бити придодат језичку „Категорије“.</string>
<string name="osm_live_payment_desc">Чланарина се наплаћује по одабраном периоду. Можете је отказати на Гугл плеју кад год пожелите.</string> <string name="osm_live_payment_desc">Чланарина се наплаћује по одабраном периоду. Можете је отказати на Гугл плеју кад год пожелите.</string>
<string name="donation_to_osm">Прилог ОСМ заједници</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="osm_live_subscription_desc">Чланарина омогућава часовне, дневне и седмичне надоградње, и неограничена преузимања свих карата.</string>
<string name="get_it">Добавите је</string> <string name="get_it">Добавите је</string>
<string name="get_for">Добавите за %1$s</string> <string name="get_for">Добавите за %1$s</string>
@ -1062,9 +1062,9 @@
<string name="access_direction_audio_feedback_descr">Указуј на правац циљне тачке звуком.</string> <string name="access_direction_audio_feedback_descr">Указуј на правац циљне тачке звуком.</string>
<string name="access_direction_haptic_feedback">Упутства трешењем</string> <string name="access_direction_haptic_feedback">Упутства трешењем</string>
<string name="access_direction_haptic_feedback_descr">Указуј на правац циљне тачке трешњом.</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="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="access_category_choice">Изаберите категорију</string>
<string name="storage_directory_readonly_desc">Пребачено на интерну меморију пошто је означено складиште за податке заштићено од писања. Изаберите фасциклу за складиште у коју може да се пише.</string> <string name="storage_directory_readonly_desc">Пребачено на интерну меморију пошто је означено складиште за податке заштићено од писања. Изаберите фасциклу за складиште у коју може да се пише.</string>
<string name="save_track_interval_descr">Наведите интервал логовања снимања путање приликом навођења</string> <string name="save_track_interval_descr">Наведите интервал логовања снимања путање приликом навођења</string>
@ -1221,7 +1221,7 @@
<string name="rendering_attr_horseRoutes_name">Коњске стазе</string> <string name="rendering_attr_horseRoutes_name">Коњске стазе</string>
<string name="share_geo">положај:</string> <string name="share_geo">положај:</string>
<string name="lang_br">Бретонски</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="hillshade_purchase_header">Инсталирајте додатак \"Изохипсе\" да прикажете нагиб вертикалних области.</string>
<string name="shared_string_plugin">Додатак</string> <string name="shared_string_plugin">Додатак</string>
<string name="display_zoom_level">Приказ нивоа увеличања: %1$s</string> <string name="display_zoom_level">Приказ нивоа увеличања: %1$s</string>
@ -1234,11 +1234,11 @@
<string name="shared_string_add_photos">Додај слике</string> <string name="shared_string_add_photos">Додај слике</string>
<string name="no_photos_descr">Нема слика овде.</string> <string name="no_photos_descr">Нема слика овде.</string>
<string name="mapillary_action_descr">Поделите Ваш поглед са улице преко Мапилара.</string> <string name="mapillary_action_descr">Поделите Ваш поглед са улице преко Мапилара.</string>
<string name="mapillary_widget">Справица Мапилара</string> <string name="mapillary_widget">Mapillary справица</string>
<string name="mapillary_widget_descr">Омогућава брзи допринос Мапилару.</string> <string name="mapillary_widget_descr">Омогућава брзи допринос Mapillary-ју.</string>
<string name="open_mapillary">Отвори Мапилар</string> <string name="open_mapillary">Отвори Mapillary</string>
<string name="mapillary_descr">Мрежне слике улица за све. Откријте места, сарађујте, освојите свет.</string> <string name="mapillary_descr">Мрежне слике улица за све. Откријте места, сарађујте, освојите свет.</string>
<string name="mapillary">Мапилари</string> <string name="mapillary">Mapillary</string>
<string name="plugin_mapillary_descr">Мрежне слике улица за све. Откријте места, сарађујте, освојите свет.</string> <string name="plugin_mapillary_descr">Мрежне слике улица за све. Откријте места, сарађујте, освојите свет.</string>
<string name="private_access_routing_req">Ваше одредиште се налази на приватном поседу. Дозволити коришћење приватних путева на овом путовању\?</string> <string name="private_access_routing_req">Ваше одредиште се налази на приватном поседу. Дозволити коришћење приватних путева на овом путовању\?</string>
<string name="restart_search">Препокрени претрагу</string> <string name="restart_search">Препокрени претрагу</string>
@ -1512,8 +1512,8 @@
<string name="import_gpx_failed_descr">Не могу да увезем фајл. Проверите да ли OsmAnd има дозволе за читање фајла.</string> <string name="import_gpx_failed_descr">Не могу да увезем фајл. Проверите да ли OsmAnd има дозволе за читање фајла.</string>
<string name="distance_moving">Растојање је исправљено</string> <string name="distance_moving">Растојање је исправљено</string>
<string name="mapillary_image">Слика са Мапилара</string> <string name="mapillary_image">Слика са Мапилара</string>
<string name="improve_coverage_mapillary">Побољшајте покривеност слика користећи Мапилар</string> <string name="improve_coverage_mapillary">Побољшајте покривеност слика користећи Mapillary</string>
<string name="improve_coverage_install_mapillary_desc">Инсталирајте програм Мапилар (Mapillary) да додате слике на ову локацију на карти.</string> <string name="improve_coverage_install_mapillary_desc">Инсталирајте програм Mapillary да додате слике на ову локацију на карти.</string>
<string name="subscribe_email_desc">Претплатите се на нашу дописну листу за попуст и добијте још 3 преузимања карти!</string> <string name="subscribe_email_desc">Претплатите се на нашу дописну листу за попуст и добијте још 3 преузимања карти!</string>
<string name="depth_contour_descr">Изобате мора (изохипсе дубине) и карте поморских ознака.</string> <string name="depth_contour_descr">Изобате мора (изохипсе дубине) и карте поморских ознака.</string>
<string name="sea_depth_thanks">Хвала Вам на куповини „Поморских изобата“</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_title">Помери дугме</string>
<string name="quick_action_btn_tutorial_descr">Дуго држање и превлачење дугмета га помера по екрану.</string> <string name="quick_action_btn_tutorial_descr">Дуго држање и превлачење дугмета га помера по екрану.</string>
<string name="shared_string_action_name">Име радње</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="retry">Покушај поново</string>
<string name="empty_state_favourites">Додај омиљене</string> <string name="empty_state_favourites">Додај омиљене</string>
<string name="empty_state_favourites_desc">Увезите Омиљене тачке или их додајте означавајући их као ознаке на карти.</string> <string name="empty_state_favourites_desc">Увезите Омиљене тачке или их додајте означавајући их као ознаке на карти.</string>
@ -2134,7 +2134,7 @@
<string name="plugin_install_needs_network">Морате имати интернет да бисте инсталирали овај додатак.</string> <string name="plugin_install_needs_network">Морате имати интернет да бисте инсталирали овај додатак.</string>
<string name="get_plugin">Преузми</string> <string name="get_plugin">Преузми</string>
<string name="use_fast_recalculation">Пмаетно прерачунавање пута</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="do_you_like_osmand">Да ли Вам се OsmAnd свиђа?</string>
<string name="we_really_care_about_your_opinion">Важно нам је да чујемо Ваше мишљење.</string> <string name="we_really_care_about_your_opinion">Важно нам је да чујемо Ваше мишљење.</string>
<string name="rate_this_app">Оцените ову апликацију</string> <string name="rate_this_app">Оцените ову апликацију</string>
@ -2543,7 +2543,7 @@
<string name="update_poi_error_local">Не могу да ажурирам локални списак тачака од интереса.</string> <string name="update_poi_error_local">Не могу да ажурирам локални списак тачака од интереса.</string>
<string name="quick_action_add_gpx_descr">Дугме за додавање GPX пролазне тачке на средину екрана.</string> <string name="quick_action_add_gpx_descr">Дугме за додавање GPX пролазне тачке на средину екрана.</string>
<string name="show_images">Прикажи слике</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="purchase_cancelled_dialog_descr">Обновите чланарину да наставите да користите све ове функционалности:</string>
<string name="gpxup_identifiable">Може да се користи за идентификацију</string> <string name="gpxup_identifiable">Може да се користи за идентификацију</string>
<string name="gpxup_trackable">Може да се користи за праћење</string> <string name="gpxup_trackable">Може да се користи за праћење</string>
@ -2581,7 +2581,7 @@
<string name="default_render_descr">Стил опште намене. Густи градови су приказани јасно. Приказује изохипсе, путање, квалитет подлоге, забране приступа, блокаде путева, исцртавање путева по SAC алпској скали, објекти за спортове на брзацима.</string> <string name="default_render_descr">Стил опште намене. Густи градови су приказани јасно. Приказује изохипсе, путање, квалитет подлоге, забране приступа, блокаде путева, исцртавање путева по SAC алпској скали, објекти за спортове на брзацима.</string>
<string name="open_wikipedia_link_online">Отвори Википедија везу са интернетом</string> <string name="open_wikipedia_link_online">Отвори Википедија везу са интернетом</string>
<string name="open_wikipedia_link_online_description">Веза ће бити отворена у веб читачу.</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="how_to_open_link">Како да отворим везу?</string>
<string name="read_wikipedia_offline">Читај Википедију ван мреже</string> <string name="read_wikipedia_offline">Читај Википедију ван мреже</string>
<string name="download_all">Преузми све</string> <string name="download_all">Преузми све</string>
@ -2703,7 +2703,7 @@
\n - Окретањем мапе према компасу или правцу кретања \n - Окретањем мапе према компасу или правцу кретања
\n - Навођењем у праву траку, приказ ограничења брзине, снимљени и синтетизовани гласови за навођење \n - Навођењем у праву траку, приказ ограничења брзине, снимљени и синтетизовани гласови за навођење
\n</string> \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">Карта <string name="osmand_extended_description_part3">Карта
\n • Приказ тачака од интереса око Вас \n • Приказ тачака од интереса око Вас
\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">%1$s / месечно</string>
<string name="osm_live_payment_month_cost_descr_ex">%1$.2f %2$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_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_monthly">Месечно обнављање</string>
<string name="osm_live_payment_renews_quarterly">Квартално обнављање</string> <string name="osm_live_payment_renews_quarterly">Квартално обнављање</string>
<string name="osm_live_payment_renews_annually">Годишње обнављање</string> <string name="osm_live_payment_renews_annually">Годишње обнављање</string>
<string name="default_price_currency_format">%1$.2f %2$s</string> <string name="default_price_currency_format">%1$.2f %2$s</string>
<string name="osm_live_payment_header">Период плаћања:</string> <string name="osm_live_payment_header">Период плаћања:</string>
<string name="osm_live_payment_contribute_descr">Донације помажу финансирање OSM картографа.</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="mapillary_menu_title_pano">Прикажи само слике од 360°</string>
<string name="shared_string_launch">Покрени</string> <string name="shared_string_launch">Покрени</string>
<string name="lang_gn_py">Гварани</string> <string name="lang_gn_py">Гварани</string>
@ -2894,8 +2894,8 @@
<string name="tracks_on_map">Приказане путање</string> <string name="tracks_on_map">Приказане путање</string>
<string name="sit_on_the_stop">Укрцавање на стајању</string> <string name="sit_on_the_stop">Укрцавање на стајању</string>
<string name="quick_action_show_hide_gpx_tracks_descr">Дугме које приказује или сакрива одабране путање са карте.</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_description">Омогући јавни превоз на OsmAnd уживо изменама.</string>
<string name="use_osm_live_public_transport">OsmAnd Live јавни превоз</string> <string name="use_osm_live_public_transport">OsmAnd уживо јавни превоз</string>
<string name="rendering_attr_surface_sett_name">Калдрма</string> <string name="rendering_attr_surface_sett_name">Калдрма</string>
<string name="rendering_attr_surface_paving_stones_name">Поплочано камење</string> <string name="rendering_attr_surface_paving_stones_name">Поплочано камење</string>
<string name="rendering_attr_highway_class_motorway_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_part">%1$s првих %2$s</string>
<string name="get_discount_first_few_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="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="price_and_discount">%1$s • Уштеди %2$s</string>
<string name="configure_profile_info">Поставке за профил:</string> <string name="configure_profile_info">Поставке за профил:</string>
<string name="utm_format_descr">OsmAnd користи UTM Standard format који је сличан, али није истоветан као UTM NATO format.</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="login_and_pass">Корисничко име и лозинка</string>
<string name="plugin_global_prefs_info">Ова подешавања додатака су глобална и примењују се на све профиле</string> <string name="plugin_global_prefs_info">Ова подешавања додатака су глобална и примењују се на све профиле</string>
<string name="osm_editing">OSM уређивање</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="app_mode_osm">OSM</string>
<string name="select_nav_icon_descr">Иконица која се приказује за време навођења или померања.</string> <string name="select_nav_icon_descr">Иконица која се приказује за време навођења или померања.</string>
<string name="select_map_icon_descr">Иконица која се приказује у мировању.</string> <string name="select_map_icon_descr">Иконица која се приказује у мировању.</string>
@ -3484,7 +3484,7 @@
<string name="measure_distance_item">Измери удаљеност</string> <string name="measure_distance_item">Измери удаљеност</string>
<string name="travel_item">Путовање (Wikivoyage и Википедија)</string> <string name="travel_item">Путовање (Wikivoyage и Википедија)</string>
<string name="favorites_item">Омиљени</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="osmand_purchases_item">OsmAnd куповине</string>
<string name="legend_item_description">Упутство за легенду карте.</string> <string name="legend_item_description">Упутство за легенду карте.</string>
<string name="navigation_profiles_item">Профили навођења</string> <string name="navigation_profiles_item">Профили навођења</string>
@ -3650,9 +3650,9 @@
<string name="context_menu_actions">Акције Контекст менија</string> <string name="context_menu_actions">Акције Контекст менија</string>
<string name="osm_live_payment_subscription_management">Наплатом ће бити оптерећен ваш Гугл Плеј налог при потврди куповине. <string name="osm_live_payment_subscription_management">Наплатом ће бити оптерећен ваш Гугл Плеј налог при потврди куповине.
\n \n
\n Претплата се аутоматски обнавља уколико није отказана пре датума обнове. Ваш налог биће задужен периодом обнове (месец / три месеца / годину дана) само на дан обнове. \nЧланарина се аутоматски обнавља уколико није отказана пре датума обнове. Ваш налог биће задужен периодом обнове (месец / три месеца / годину дана) само на дан обнове.
\n \n
\n Претплатама можете управљати и отказати их тако што ћете отићи на ваша Гугл Плеј подешавања.</string> \nЧланаринама можете управљати и отказати их тако што ћете отићи на ваша Гугл Плеј подешавања.</string>
<string name="release_3_7">• Нове офлајн мапе нагиба <string name="release_3_7">• Нове офлајн мапе нагиба
\n \n
\n • Пуно прилагођавање Фаворита и ГПКС тачака прилагођавање боја, икона, облика \n • Пуно прилагођавање Фаворита и ГПКС тачака прилагођавање боја, икона, облика
@ -3683,9 +3683,9 @@
<string name="lenght_limit_description">Унесите дужину возила, нека ограничења пута могу бити примењена за дужа возила.</string> <string name="lenght_limit_description">Унесите дужину возила, нека ограничења пута могу бити примењена за дужа возила.</string>
<string name="quick_action_remove_next_destination">Обриши најближу одредишну тачку</string> <string name="quick_action_remove_next_destination">Обриши најближу одредишну тачку</string>
<string name="please_provide_point_name_error">Молимо одредите име тачке</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="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_enduro_motorcycle">Ендуро скутер</string>
<string name="app_mode_motor_scooter">Скутер</string> <string name="app_mode_motor_scooter">Скутер</string>
<string name="app_mode_wheelchair">Инвалидска колица</string> <string name="app_mode_wheelchair">Инвалидска колица</string>
@ -3723,7 +3723,7 @@
<string name="navigation_profile">Навигацијски профил</string> <string name="navigation_profile">Навигацијски профил</string>
<string name="route_between_points_add_track_desc">Изаберите датотеку записа којој ће се додати нови сегмент.</string> <string name="route_between_points_add_track_desc">Изаберите датотеку записа којој ће се додати нови сегмент.</string>
<string name="street_level_imagery">Слике на нивоу улице</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="in_case_of_reverse_direction">У случају обрнутог правца</string>
<string name="shared_string_save_as_gpx">Сачувај као нову датотеку стазе</string> <string name="shared_string_save_as_gpx">Сачувај као нову датотеку стазе</string>
<string name="add_segment_to_the_track">Додај у датотеку стазе</string> <string name="add_segment_to_the_track">Додај у датотеку стазе</string>
@ -3761,9 +3761,9 @@
<string name="gpx_monitoring_stop">Паузирај снимање пута</string> <string name="gpx_monitoring_stop">Паузирај снимање пута</string>
<string name="one_point_error">Додајте бар две тачке.</string> <string name="one_point_error">Додајте бар две тачке.</string>
<string name="osm_edit_logout_success">Одјављен</string> <string name="osm_edit_logout_success">Одјављен</string>
<string name="gpx_upload_private_visibility_descr">„Приватно“ значи да се траг не појављује ни на једној јавној листи, али су тачке праћења у њему у нехронолошком редоследу доступне путем јавног ГПС АПИ-ја без временских ознака.</string> <string name="gpx_upload_private_visibility_descr">„Приватно“ значи да се траг не појављује ни на једној јавној листи, али су тачке праћења у њему у нехронолошком редоследу доступне путем јавног GPS API-ја без временских ознака.</string>
<string name="gpx_upload_identifiable_visibility_descr">„Могуће је идентификовати“ значи да ће се траг јавно приказати у вашим ГПС траговима и у јавним списковима ГПС трагова, тј. други корисници ће моћи да преузму необрађени траг и повежу га са вашим корисничким именом. Јавни подаци о временским тачкама трага из ГПС АПИ-ја који се сервирају путем АПИ-ја за тачке праћења имаће референцу на вашу оригиналну страницу праћења.</string> <string name="gpx_upload_identifiable_visibility_descr">„Могуће је идентификовати“ значи да ће се траг јавно приказати у Вашим GPS траговима и у јавним списковима GPS трагова, тј. други корисници ће моћи да преузму необрађени траг и повежу га са Вашим корисничким именом. Јавни подаци о временским тачкама трага из GPS API-ја који се сервирају путем API-ја за тачке праћења имаће референцу на вашу оригиналну страницу праћења.</string>
<string name="gpx_upload_trackable_visibility_descr">„Следљиво“ значи да се траг не приказује нигде на јавним листама, али обрађене тачке праћења са временским ознакама у њима (које не могу бити директно повезане са вама) иду кроз преузимања са јавног ГПС АПИ-ја.</string> <string name="gpx_upload_trackable_visibility_descr">„Следљиво“ значи да се траг не приказује нигде на јавним листама, али обрађене тачке праћења са временским ознакама у њима (које не могу бити директно повезане са вама) иду кроз преузимања са јавног GPS API-ја.</string>
<string name="osm_edit_close_note">Затвори ОСМ белешку</string> <string name="osm_edit_close_note">Затвори ОСМ белешку</string>
<string name="osm_edit_comment_note">Коментар ОСМ напомене</string> <string name="osm_edit_comment_note">Коментар ОСМ напомене</string>
<string name="osm_login_descr">Можете се пријавити користећи безбедан ОАут метод или користити своје корисничко име и лозинку.</string> <string name="osm_login_descr">Можете се пријавити користећи безбедан ОАут метод или користити своје корисничко име и лозинку.</string>
@ -3776,12 +3776,12 @@
<string name="shared_string_search_history">Претрага</string> <string name="shared_string_search_history">Претрага</string>
<string name="app_mode_kayak">Кајак</string> <string name="app_mode_kayak">Кајак</string>
<string name="app_mode_motorboat">Моторни чамац</string> <string name="app_mode_motorboat">Моторни чамац</string>
<string name="add_to_mapillary">Додај у Мапилари</string> <string name="add_to_mapillary">Додај у Mapillary</string>
<string name="add_to_opr">Додај у ОпенПлејсРевјуз</string> <string name="add_to_opr">Додај у OpenPlaceReviews</string>
<string name="add_photos_descr">ОсмАнд приказује фотографије из неколико извора: <string name="add_photos_descr">OsmAnd приказује фотографије из неколико извора:
\nОпенПлејсРевјуз - ПОИ фотографије; \nOpenPlaceReviews - фотографије тачака од интереса;
\nМапилари - слике на нивоу улице; \nMapillary - слике на нивоу улице;
\nВеб / Викимедиа - ПОИ фотографије наведене у подацима ОпенСтритМап.</string> \nВеб / Викимедија - фотографије тачака од интереса наведене у OpenStreetMap подацима.</string>
<string name="shared_string_resources">Ресурси</string> <string name="shared_string_resources">Ресурси</string>
<string name="approximate_file_size">Приближна величина датотеке</string> <string name="approximate_file_size">Приближна величина датотеке</string>
<string name="select_data_to_export">Изаберите податке за извоз у датотеку.</string> <string name="select_data_to_export">Изаберите податке за извоз у датотеку.</string>
@ -3795,7 +3795,7 @@
<string name="mgrs_format_descr">ОсмАнд користи МГРС, који је сличан УТМ НАТО формату.</string> <string name="mgrs_format_descr">ОсмАнд користи МГРС, који је сличан УТМ НАТО формату.</string>
<string name="simplified_track">Поједностављена стаза</string> <string name="simplified_track">Поједностављена стаза</string>
<string name="simplified_track_description">Само линија руте ће бити сачувана, а путне тачке ће бити избрисане.</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="save_global_track_interval_descr">Наведите интервал евидентирања за опште снимање стаза (укључено помоћу виџета „Снимање путовања“ на мапи).</string>
<string name="gpx_monitoring_start">Наставите снимање путовања</string> <string name="gpx_monitoring_start">Наставите снимање путовања</string>
<string name="system_default_theme">Системско подразумевана</string> <string name="system_default_theme">Системско подразумевана</string>
@ -3827,17 +3827,17 @@
<string name="sort_name_descending">Име: З - А</string> <string name="sort_name_descending">Име: З - А</string>
<string name="sort_name_ascending">Име: А - З</string> <string name="sort_name_ascending">Име: А - З</string>
<string name="contour_lines_thanks">Хвала вам што сте купили „Контурне линије“</string> <string name="contour_lines_thanks">Хвала вам што сте купили „Контурне линије“</string>
<string name="osm_live_payment_desc_hw">Претплата се наплаћује по изабраном периоду. Откажите га у АппГалери у било ком тренутку.</string> <string name="osm_live_payment_desc_hw">Чланарина се наплаћује по изабраном периоду. Откажите је у AppGallery у било ком тренутку.</string>
<string name="osm_live_payment_subscription_management_hw">Уплата ће бити наплаћена са вашег рачуна АппГалери при потврди куповине. <string name="osm_live_payment_subscription_management_hw">Уплата ће бити наплаћена са вашег рачуна AppGallery при потврди куповине.
\n \n
\nПретплата се аутоматски обнавља уколико није отказана пре датума обнове. Ваш рачун ће бити задужен за период обнове (месец / три месеца / година) само на датум обнове. \nЧланарина се аутоматски обнавља уколико није отказана пре датума обнове. Ваш рачун ће бити задужен за период обнове (месец / три месеца / година) само на датум обнове.
\n \n
\nПретплатама можете управљати и отказати их тако што ћете отићи у подешавања апликације АппГалери.</string> \nЧланаринама можете управљати и отказати их тако што ћете отићи у подешавања апликације AppGallery.</string>
<string name="routing_attr_avoid_footways_description">Избегавајте пешачке стазе</string> <string name="routing_attr_avoid_footways_description">Избегавајте пешачке стазе</string>
<string name="routing_attr_avoid_footways_name">Избегавајте пешачке стазе</string> <string name="routing_attr_avoid_footways_name">Избегавајте пешачке стазе</string>
<string name="development">Развој</string> <string name="development">Развој</string>
<string name="use_live_public_transport">ОсмАнд лајв подаци</string> <string name="use_live_public_transport">OsmAnd уживо подаци</string>
<string name="use_live_routing">ОсмАнд лајв подаци</string> <string name="use_live_routing">OsmAnd уживо подаци</string>
<string name="complex_routing_descr">Двофазно усмеравање за аутомобилску навигацију.</string> <string name="complex_routing_descr">Двофазно усмеравање за аутомобилску навигацију.</string>
<string name="use_native_pt">Развој матичног јавног превоза</string> <string name="use_native_pt">Развој матичног јавног превоза</string>
<string name="use_native_pt_desc">Пребаците се на Јава (безбедан) прорачун рутирања јавног превоза</string> <string name="use_native_pt_desc">Пребаците се на Јава (безбедан) прорачун рутирања јавног превоза</string>
@ -3847,9 +3847,9 @@
<string name="file_already_imported">Датотека је већ увезена у ОсмАнд</string> <string name="file_already_imported">Датотека је већ увезена у ОсмАнд</string>
<string name="use_two_phase_routing">Користите двофазни алгоритам усмеравања А*</string> <string name="use_two_phase_routing">Користите двофазни алгоритам усмеравања А*</string>
<string name="shared_string_graph">Графикон</string> <string name="shared_string_graph">Графикон</string>
<string name="message_need_calculate_route_before_show_graph">%1$s подаци доступни само на путевима, морате израчунати руту користећи „Рута између тачака“ да бисте је добили.</string> <string name="message_need_calculate_route_before_show_graph">%1$s подаци доступни само на путевима, израчунајте руту користећи „Рута између тачака“ да бисте видели графике.</string>
<string name="message_graph_will_be_available_after_recalculation">Сачекајте поновно израчунавање руте. <string name="message_graph_will_be_available_after_recalculation">Молимо сачекајте.
\nГрафикон ће бити доступан након поновног израчунавања.</string> \nГрафикон ће бити доступан након поновног израчунавања путање.</string>
<string name="shared_string_local_maps">Локалне мапе</string> <string name="shared_string_local_maps">Локалне мапе</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string> <string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="app_mode_gap">Размак</string> <string name="app_mode_gap">Размак</string>
@ -3871,15 +3871,15 @@
<string name="use_login_password">Користите корисничко име и лозинку</string> <string name="use_login_password">Користите корисничко име и лозинку</string>
<string name="login_account">Налог</string> <string name="login_account">Налог</string>
<string name="user_login">Пријавите се</string> <string name="user_login">Пријавите се</string>
<string name="manage_subscription">Управљајте претплатом</string> <string name="manage_subscription">Управљајте чланарином</string>
<string name="subscription_payment_issue_title">Постоји проблем са вашом претплатом. Кликните на дугме да бисте отворили подешавања претплате за Гугле Плеј и да бисте поправили начин плаћања.</string> <string name="subscription_payment_issue_title">Постоји проблем са Вашом чланарином. Кликните на дугме да бисте отворили подешавања претплате за Гугле Плеј и да бисте поправили начин плаћања.</string>
<string name="subscription_expired_title">Претплата на ОсмАнд лајв је истекла</string> <string name="subscription_expired_title">Чланарина за OsmAnd уживо је истекла</string>
<string name="subscription_paused_title">Претплата на ОсмАнд лајв је паузирана</string> <string name="subscription_paused_title">Чланарина на OsmAnd уживо је паузирана</string>
<string name="subscription_on_hold_title">Претплата на ОсмАнд лајв је на чекању</string> <string name="subscription_on_hold_title">Чланарина на OsmAnd уживо је на чекању</string>
<string name="markers_history">Историја маркера</string> <string name="markers_history">Историја маркера</string>
<string name="send_files_to_openstreetmap">Пошаљите ГПКС датотеку на ОпенСтритМап</string> <string name="send_files_to_openstreetmap">Пошаљите ГПКС датотеку на ОпенСтритМап</string>
<string name="enter_text_separated">Унесите ознаке одвојене зарезом.</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="cannot_upload_image">Није могуће отпремити слику, покушајте поново касније</string>
<string name="select_picture">Изаберите слику</string> <string name="select_picture">Изаберите слику</string>
<string name="select_groups_for_import">Изаберите групе које ће бити увезене.</string> <string name="select_groups_for_import">Изаберите групе које ће бити увезене.</string>
@ -3895,11 +3895,11 @@
<string name="plan_route_add_new_segment">Додајте нови сегмент</string> <string name="plan_route_add_new_segment">Додајте нови сегмент</string>
<string name="release_3_9">• Додата је опција за извоз и увоз свих података, укључујући подешавања, ресурсе, моја места <string name="release_3_9">• Додата је опција за извоз и увоз свих података, укључујући подешавања, ресурсе, моја места
\n \n
\n • Планирање руте: графикони за сегменте са рутом, додата је могућност креирања и уређивања вишеструких сегмената стаза \n • Планирање руте: графикони за сегменте са рутом, и додата је могућност креирања и уређивања вишеструких сегмената стаза
\n \n
\n • Додан је метод аутентификације ОАут за ОпенСтритМап, побољшан кориснички интерфејс ОСМ дијалога \n • Додан је метод аутентификације ОАут за ОпенСтритМап, побољшан кориснички интерфејс ОСМ дијалога
\n \n
\n • Прилагођене боје за омиљене и путне тачаке стаза \n • Подршка за прилагођене боје за омиљене и пролазне тачке путања
\n \n
\n</string> \n</string>
<string name="activity_type_water_name">Вода</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_electric">Екетрични бициклизам</string>
<string name="routing_engine_vehicle_type_cycling_mountain">Планински бициклизам</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_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_hgv">Теретни камион</string>
<string name="routing_engine_vehicle_type_small_truck">Камионет</string> <string name="routing_engine_vehicle_type_small_truck">Камионет</string>
<string name="routing_engine_vehicle_type_truck">Камион</string> <string name="routing_engine_vehicle_type_truck">Камион</string>
@ -3988,4 +3988,98 @@
<string name="rename_track">Преименуј путању</string> <string name="rename_track">Преименуј путању</string>
<string name="trip_recording_save_and_continue">Сачувај и настави</string> <string name="trip_recording_save_and_continue">Сачувај и настави</string>
<string name="lost_data_warning">Сви несачувани подаци ће бити изгубљени.</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 уживо су премештена у „Преузимања &gt; Ажурирања”
\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> </resources>

View file

@ -3926,4 +3926,6 @@
<string name="poi_hoops">Ringar</string> <string name="poi_hoops">Ringar</string>
<string name="poi_office_diplomatic">Diplomatiskt kontor</string> <string name="poi_office_diplomatic">Diplomatiskt kontor</string>
<string name="poi_bay_filter">Typ av vik</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> </resources>

View file

@ -470,7 +470,7 @@
<string name="indexing_map">Indexerar kartan …</string> <string name="indexing_map">Indexerar kartan …</string>
<string name="indexing_poi">Indexerar Intressepunkter …</string> <string name="indexing_poi">Indexerar Intressepunkter …</string>
<string name="indexing_transport">Indexerar transport …</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">km</string>
<string name="km_h">km/h</string> <string name="km_h">km/h</string>
<string name="m">m</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="favourites_remove_dialog_success">Favoritpunkten {0} togs bort utan problem.</string>
<string name="osb_comment_dialog_message">Meddelande</string> <string name="osb_comment_dialog_message">Meddelande</string>
<string name="osb_comment_dialog_author">Författarnamn</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="osb_comment_dialog_error">Det gick inte att lägga till kommentar.</string>
<string name="poi_edit_title">Redigera POI</string> <string name="poi_edit_title">Redigera POI</string>
<string name="poi_create_title">Skapa 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="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_distancemeasurement">Avståndsmätning</string>
<string name="map_widget_audionotes">Ljudanteckningar</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="audionotes_plugin_name">Ljud-/Videoanteckningar</string>
<string name="index_srtm_parts">delar</string> <string name="index_srtm_parts">delar</string>
<string name="index_srtm_ele">Höjdkurvor</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="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_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="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="anonymous_user">Anonym användare</string>
<string name="logged_as">Inloggad som %1$s</string> <string name="logged_as">Inloggad som %1$s</string>
<string name="configure_map">Konfigurera kartan</string> <string name="configure_map">Konfigurera kartan</string>
@ -1357,11 +1360,11 @@
<string name="notes">Anteckningar</string> <string name="notes">Anteckningar</string>
<string name="online_map">Online-karta</string> <string name="online_map">Online-karta</string>
<string name="share_note">Dela anteckning</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 \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 \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. <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 \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> \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">Mer…</string>
<string name="shared_string_more_actions">Fler åtgärder</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_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_refresh">Uppdatera</string>
<string name="shared_string_download">Hämta</string> <string name="shared_string_download">Hämta</string>
<string name="shared_string_downloading">Laddar ner…</string> <string name="shared_string_downloading">Laddar ner…</string>
<string name="shared_string_download_successful">Hämtningen lyckades</string> <string name="shared_string_download_successful">Nedladdat</string>
<string name="shared_string_unexpected_error">Ett oväntat fel uppstod</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_action_template">Åtgärd {0}</string>
<string name="shared_string_close">Stäng</string> <string name="shared_string_close">Stäng</string>
<string name="shared_string_exit">Utgå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_map">Karta</string>
<string name="shared_string_favorite">Favorit</string> <string name="shared_string_favorite">Favorit</string>
<string name="shared_string_favorites">Favoriter</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_location">Min position</string>
<string name="shared_string_my_places">Mina platser</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_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_currently_recording_track">Spelar för tillfället in spår</string>
<string name="shared_string_audio">Ljud</string> <string name="shared_string_audio">Ljud</string>
@ -1459,21 +1462,21 @@
<string name="your_edits">Dina redigeringar</string> <string name="your_edits">Dina redigeringar</string>
<string name="osmand_parking_overdue">över tiden</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_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="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="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">Vill du tömma historiken?</string> <string name="confirmation_to_clear_history">Rensa historik\?</string>
<string name="current_route">Aktuell rutt</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="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="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="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_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_text">OsmAnd erbjuder global frånkopplad kartsurfning och frånkopplad navigering.</string>
<string name="welcome_header">Välkommen</string> <string name="welcome_header">Välkommen</string>
<string name="agps_info">A-GPS-info</string> <string name="agps_info">A-GPS-info</string>
<string name="shared_string_message">Meddelande</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_do_not_use">Använd inte</string>
<string name="shared_string_address">Adress</string> <string name="shared_string_address">Adress</string>
<string name="shared_string_show_description">Visa beskrivning.</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="index_name_netherlands">Europa - Nederländerna</string>
<string name="rendering_value_highContrastRoads_name">Högkontrastvägar</string> <string name="rendering_value_highContrastRoads_name">Högkontrastvägar</string>
<string name="rendering_value__name">Standard</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="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_external">Extern lagring</string>
<string name="storage_directory_multiuser">Lagring för flera användare</string> <string name="storage_directory_multiuser">Lagring för flera användare</string>
<string name="storage_directory_internal_app">Internt appminne</string> <string name="storage_directory_internal_app">Internt appminne</string>
@ -1512,16 +1515,16 @@
<string name="shared_string_wikipedia">Wikipedia</string> <string name="shared_string_wikipedia">Wikipedia</string>
<string name="local_indexes_cat_wiki">Wikipedia</string> <string name="local_indexes_cat_wiki">Wikipedia</string>
<string name="shared_string_show_details">Visa detaljer</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="download_wikipedia_maps">Wikipedia</string>
<string name="shared_string_import2osmand">Importera till OsmAnd</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="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="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_vo">Volapük</string>
<string name="lang_th">Thai</string> <string name="lang_th">Thai</string>
<string name="lang_te">Telugu</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_new">Newar/Nepal Bhasa</string>
<string name="lang_ms">Malajiska</string> <string name="lang_ms">Malajiska</string>
<string name="lang_ht">Haitiska</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_translucent_blue_name">Genomskinlig blå</string>
<string name="rendering_value_purple_name">Purpur</string> <string name="rendering_value_purple_name">Purpur</string>
<string name="rendering_value_translucent_purple_name">Genomskinlig 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_attr_currentTrackColor_name">GPX-färg</string>
<string name="rendering_value_yellow_name">Gul</string> <string name="rendering_value_yellow_name">Gul</string>
<string name="rendering_value_default13_name">Standard (13)</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_undo">ÅNGRA</string>
<string name="shared_string_skip">Hoppa över</string> <string name="shared_string_skip">Hoppa över</string>
<string name="app_name_osmand">OsmAnd</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_name">Inget 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_description">Undviker att använda pendeltåg</string>
<string name="plugin_settings">Insticksprogram</string> <string name="plugin_settings">Insticksprogram</string>
<string name="traffic_warning_hazard">Varning</string> <string name="traffic_warning_hazard">Varning</string>
<string name="tab_title_basic">Grundläggande</string> <string name="tab_title_basic">Grundläggande</string>
@ -1600,7 +1603,7 @@
<string name="opening_at">Öppnar</string> <string name="opening_at">Öppnar</string>
<string name="closing_at">Stänger</string> <string name="closing_at">Stänger</string>
<string name="av_locations">Platser</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="poi_dialog_poi_type">Typ av POI</string>
<string name="add_opening_hours">Lägg till öppettider</string> <string name="add_opening_hours">Lägg till öppettider</string>
<string name="contact_info">Kontaktinformation</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_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="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="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="roads">Vägar</string>
<string name="favourites_context_menu_add">Lägg till favorit</string> <string name="favourites_context_menu_add">Lägg till favorit</string>
<string name="default_speed_system_descr">Ange enhet för hastighet.</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="si_nm_h">Sjömil per timme (knop)</string>
<string name="shared_string_trip_recording">Inspelning av resa</string> <string name="shared_string_trip_recording">Inspelning av resa</string>
<string name="shared_string_navigation">Navigering</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_add_new">Lägg till ny</string>
<string name="favorite_category_select">Välj kategori</string> <string name="favorite_category_select">Välj kategori</string>
<string name="count_of_lines">Antal rader</string> <string name="count_of_lines">Antal rader</string>
@ -1653,7 +1656,7 @@
<string name="activate_srtm_plugin">Aktivera modulen SRTM</string> <string name="activate_srtm_plugin">Aktivera modulen SRTM</string>
<string name="later">Senare</string> <string name="later">Senare</string>
<string name="get_full_version">Fullversionen</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_name">Kategorinamn</string>
<string name="favorite_category_add_new_title">Lägg till en ny kategori</string> <string name="favorite_category_add_new_title">Lägg till en ny kategori</string>
<string name="file_size_in_mb">%.1f MB</string> <string name="file_size_in_mb">%.1f MB</string>
@ -1668,9 +1671,9 @@
<string name="share_menu_location">Dela platsen</string> <string name="share_menu_location">Dela platsen</string>
<string name="shared_string_send">Sänd</string> <string name="shared_string_send">Sänd</string>
<string name="hillshade_layer_disabled">Skuggad relief-lager inaktiverat</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">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="go_to_map">Visa kartan</string>
<string name="shared_string_qr_code">QR-kod</string> <string name="shared_string_qr_code">QR-kod</string>
<string name="enter_country_name">Ange land</string> <string name="enter_country_name">Ange land</string>
@ -1693,7 +1696,7 @@
<string name="versions_item">Versioner</string> <string name="versions_item">Versioner</string>
<string name="contact_us">Kontakta oss</string> <string name="contact_us">Kontakta oss</string>
<string name="osm_edit_created_poi">Skapat en OSM POI</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="shared_string_upload">Skicka</string>
<string name="map_legend">Teckenförklaring</string> <string name="map_legend">Teckenförklaring</string>
<string name="shared_string_update">Uppdatering</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_comment_dialog_title">Lägg till kommentar</string>
<string name="osn_reopen_dialog_title">Öppna anteckning igen</string> <string name="osn_reopen_dialog_title">Öppna anteckning igen</string>
<string name="osn_close_dialog_title">Stäng anteckning</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_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="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_delete_waypoint">Ta bort GPX-waypoint?</string>
<string name="context_menu_item_edit_waypoint">Redigera 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="route_duration">Tid:</string>
<string name="missing_write_external_storage_permission">Appen har inte tillåtelse att använda SD-kortet</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_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_camera_permission">Ge kameraåtkomst.</string>
<string name="no_microphone_permission">Appen har inte tillräckliga behörigheter för att komma åt mikrofonen.</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">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="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> <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="starting_point">Startpunkt</string>
<string name="item_removed">Post borttagen</string> <string name="item_removed">Post borttagen</string>
<string name="n_items_removed">poster raderade</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="rendering_attr_hideIcons_name">POI-ikoner</string>
<string name="switch_start_finish">Skifta startpunkt och destination</string> <string name="switch_start_finish">Skifta startpunkt och destination</string>
<string name="number_of_contributors">Antal bidragsgivare</string> <string name="number_of_contributors">Antal bidragsgivare</string>
@ -1798,10 +1801,10 @@
<string name="reports_for">Rapport för</string> <string name="reports_for">Rapport för</string>
<string name="shared_string_select">Välj</string> <string name="shared_string_select">Välj</string>
<string name="shared_string_remove">Ta bort</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="add_time_span">Lägg till tidsspann</string>
<string name="road_blocked">Blockerad väg</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="rendering_attr_hideUnderground_name">Underjordiska objekt</string>
<string name="shared_string_read_more">Läs mer</string> <string name="shared_string_read_more">Läs mer</string>
<string name="rec_split_storage_size">Lagringsutrymme</string> <string name="rec_split_storage_size">Lagringsutrymme</string>
@ -1810,18 +1813,18 @@
<string name="shared_string_save_changes">Spara ändringar</string> <string name="shared_string_save_changes">Spara ändringar</string>
<string name="find_parking">Hitta en parkeringsplats</string> <string name="find_parking">Hitta en parkeringsplats</string>
<string name="show_polygons">Visa polygoner</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="select_map_markers">Välj kartmarkörer</string>
<string name="shared_string_reverse_order">Omvänd ordning</string> <string name="shared_string_reverse_order">Omvänd ordning</string>
<string name="show_map_markers_description">Aktivera kartmarkörerna.</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_active_markers_q">Ta bort alla aktiva markörer\?</string>
<string name="clear_markers_history_q">Vill du radera kartmarkörshistoriken?</string> <string name="clear_markers_history_q">Radera kartmarkörshistoriken\?</string>
<string name="active_markers">Aktiva markörer</string> <string name="active_markers">Aktiva markörer</string>
<string name="map_markers">Kartmarkörer</string> <string name="map_markers">Kartmarkörer</string>
<string name="map_marker">Kartmarkör</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="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_1st">Första kartmarkör</string>
<string name="map_marker_2nd">Andra kartmarkör</string> <string name="map_marker_2nd">Andra kartmarkör</string>
<string name="shared_string_toolbar">Verktygsfält</string> <string name="shared_string_toolbar">Verktygsfält</string>
@ -1839,34 +1842,34 @@
<string name="donations">Donationer</string> <string name="donations">Donationer</string>
<string name="number_of_recipients">Antal mottagare</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_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_subscription">OsmAnd Live-prenumeration</string>
<string name="osm_live_subscribe_btn">Prenumerera</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_email_desc">Behövs för att uppdatera dig om dina bidrag.</string>
<string name="osm_live_user_public_name">Publikt namn</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_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_month_cost_desc">Månadsbetalning</string>
<string name="osm_live_active">Aktiv</string> <string name="osm_live_active">Aktiv</string>
<string name="osm_live_not_active">Inaktiv</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_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! <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> \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_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_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="show_transparency_seekbar">Visa transparent sökfält</string>
<string name="recalculate_route">Beräkna om rutten</string> <string name="recalculate_route">Beräkna om rutten</string>
<string name="shared_string_topbar">Toppfält</string> <string name="shared_string_topbar">Toppfält</string>
<string name="storage_directory_shared">Delat minne</string> <string name="storage_directory_shared">Delat minne</string>
<string name="avoid_road">Undvik väg</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="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 upp</string> <string name="shared_string_move_up">Flytta </string>
<string name="shared_string_move_down">Flytta ned</string> <string name="shared_string_move_down">Flytta </string>
<string name="finish_navigation">Avsluta navigeringen</string> <string name="finish_navigation">Avsluta navigeringen</string>
<string name="full_report">Fullständig rapport</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_map_markers_found">Lägg till kartmarkörer via kartan</string>
<string name="no_waypoints_found">Hittar inga waypoints</string> <string name="no_waypoints_found">Hittar inga waypoints</string>
<string name="map_widget_bearing">Relativ bäring</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_medium_name">Mellan</string>
<string name="rendering_value_bold_name">Tjock</string> <string name="rendering_value_bold_name">Tjock</string>
<string name="report">Rapporter</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_support_region">Stödregion</string>
<string name="osm_live_header">Denna prenumeration aktiverar uppdateringar varje timme av kartor runt omkring i världen. <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. \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> \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="map_widget_magnetic_bearing">Magnetisk bäring</string>
<string name="rec_split_clip_length">Klipplängd</string> <string name="rec_split_clip_length">Klipplängd</string>
<string name="file_name_containes_illegal_char">Filnamnet innehåller ogiltiga tecken</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="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="search_location">Söker efter plats…</string>
<string name="storage_free_space">Oanvänt utrymme</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="give_permission">Bevilja tillstånd</string>
<string name="allow_access_location">Tillåt platsåtkomst</string> <string name="allow_access_location">Tillåt platsåtkomst</string>
<string name="update_all_maps_now">Uppdatera alla kartor nu\?</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="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="clear_tile_data">Rensa alla rutor</string>
<string name="search_hint">Ange stad, adress och POI-namn</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_it">Skaffa det</string>
<string name="get_for">Skaffa för %1$s</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> <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">Minsta loggningsprecision</string>
<string name="save_track_precision_descr">Filter: Ingen loggning om inte denna noggrannhet uppnås.</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_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_light_brown_name">Ljusbrun</string>
<string name="rendering_value_dark_brown_name">Mörkbrun</string> <string name="rendering_value_dark_brown_name">Mörkbrun</string>
<string name="rendering_attr_contourColorScheme_name">Färgschema för konturer</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_recorded">Inspelat</string>
<string name="shared_string_record">Spela in</string> <string name="shared_string_record">Spela in</string>
<string name="gpx_logging_no_data">Inga data</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="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">Tillåt motorvägar</string> <string name="routing_attr_allow_motorway_name">Använd motorvägar</string>
<string name="routing_attr_allow_motorway_description">Tillåt 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="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="route_roundabout_short">Tag den %1$d avfarten och kör</string>
<string name="upload_poi">Ladda upp POI</string> <string name="upload_poi">Ladda upp POI</string>
<string name="route_calculation">Ruttberäkning</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">Du har inga spårfiler än</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_folder">Du kan också lägga till spårfiler i mappen</string>
<string name="gpx_add_track">Lägg till mer…</string> <string name="gpx_add_track">Lägg till mer…</string>
<string name="shared_string_appearance">Utseende</string> <string name="shared_string_appearance">Utseende</string>
<string name="trip_rec_notification_settings">Aktivera snabbstart av inspelning</string> <string name="trip_rec_notification_settings">Aktivera snabbinspelning</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="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_contourWidth_name">Bredd på konturlinjen</string>
<string name="rendering_attr_hideWaterPolygons_description">Vatten</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="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-användare som skickar in ändringar till OpenStreetMap. Kostnaden för abonnemanget förblir densamma.</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_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_value_low_name">Låg</string>
<string name="rendering_attr_contourWidth_description">Bredd på konturlinjen</string> <string name="rendering_attr_contourWidth_description">Bredd på konturlinjen</string>
<string name="rendering_value_high_name">Hög</string> <string name="rendering_value_high_name">Hög</string>
@ -2069,7 +2072,7 @@
\n</string> \n</string>
<string name="navigate_point_olc_info_short">Kort OLC <string name="navigate_point_olc_info_short">Kort OLC
\nVänligen tillhandahåll fullständig kod</string> \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_move">Flytta</string>
<string name="shared_string_gpx_tracks">Spår</string> <string name="shared_string_gpx_tracks">Spår</string>
<string name="routing_attr_driving_style_name">Körstil</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="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="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_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="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="track_points_category_name">Vägpunkter, sevärdheter, namngivna funktioner</string>
<string name="shared_string_gpx_track">Spår</string> <string name="shared_string_gpx_track">Spår</string>
@ -2135,11 +2138,11 @@
<string name="select_street">Välj gator</string> <string name="select_street">Välj gator</string>
<string name="shared_string_in_name">i %1$s</string> <string name="shared_string_in_name">i %1$s</string>
<string name="type_address">Ange adress</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="type_postcode">Ange postnummer</string>
<string name="nearest_cities">Närmaste städer</string> <string name="nearest_cities">Närmaste städer</string>
<string name="select_city">Välj stad</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_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="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> <string name="restart_search">Starta om sökningen</string>
@ -2153,7 +2156,7 @@
<string name="favorite_group_name">Gruppnamn</string> <string name="favorite_group_name">Gruppnamn</string>
<string name="change_color">Ändra färg</string> <string name="change_color">Ändra färg</string>
<string name="edit_name">Redigera namn</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="quick_action_replace_destination">Ersätt destination</string>
<string name="no_overlay">Inget överlägg</string> <string name="no_overlay">Inget överlägg</string>
<string name="no_underlay">Inget underlä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_title_dates">Datum</string>
<string name="mapillary_menu_edit_text_hint">Ange användarnamn</string> <string name="mapillary_menu_edit_text_hint">Ange användarnamn</string>
<string name="mapillary_menu_title_username">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="analyze_on_map">Analysera på kartan</string>
<string name="restore_purchases">Återställ köp</string> <string name="restore_purchases">Återställ köp</string>
<string name="shared_string_paused">Pausad</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_name">Tillåt privat åtkomst</string>
<string name="routing_attr_allow_private_description">Tillåta åtkomst till privata områden.</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="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="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_desc">Knapp för att slå på eller av hastighetsstyrd automatisk zoom.</string>
<string name="quick_action_auto_zoom_on">Aktivera autozoom karta</string> <string name="quick_action_auto_zoom_on">Aktivera autozoom</string>
<string name="quick_action_auto_zoom_off">Inaktivera autozoom karta</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_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_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">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_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">Genom att trycka på denna åtgärdsknapp kommer skärmens mittpunkt att bli den första mellanliggande destinationen.</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="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="depth_contour_descr">Havsdjupskonturer och sjömärken.</string>
<string name="sea_depth_thanks">Tack för att du köpt \"Nautiska djupkonturer\"</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="renew_subscription">Förnya prenumerationen</string>
<string name="in_grace_period">I nådeperioden</string> <string name="in_grace_period">I nådeperioden</string>
<string name="on_hold">Pausad</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&gt; 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> </resources>

View file

@ -3926,4 +3926,6 @@
<string name="poi_karate">Карате</string> <string name="poi_karate">Карате</string>
<string name="poi_office_diplomatic">Дипломатичне відомство</string> <string name="poi_office_diplomatic">Дипломатичне відомство</string>
<string name="poi_bay_filter">Тип затоки</string> <string name="poi_bay_filter">Тип затоки</string>
<string name="poi_plateau">Плато</string>
<string name="poi_club_social">Суспільний клуб</string>
</resources> </resources>

View file

@ -3926,4 +3926,6 @@
<string name="poi_hoops">籃圈</string> <string name="poi_hoops">籃圈</string>
<string name="poi_office_diplomatic">外交部</string> <string name="poi_office_diplomatic">外交部</string>
<string name="poi_bay_filter">海灣類型</string> <string name="poi_bay_filter">海灣類型</string>
<string name="poi_plateau">高原</string>
<string name="poi_club_social">社交俱樂部</string>
</resources> </resources>

View file

@ -16,8 +16,14 @@
<string name="user_points">User points</string> <string name="user_points">User points</string>
<string name="announce_when_exceeded">Announce when exceeded</string> <string name="announce_when_exceeded">Announce when exceeded</string>
<string name="exit_number">Exit number</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="update_all_maps_added">Update all maps added to %1$s?</string>
<string name="release_4_0_beta"> <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 • OsmAnd Live updates moved to \"Downloads > Updates\"\n\n
• Tracks now could be colorizing by altitude, speed, or slope.\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 • Added option to change the appearance of the navigation route line\n\n

View file

@ -3,10 +3,10 @@ package net.osmand;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.util.Pair;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import net.osmand.osm.io.NetworkUtils; import net.osmand.osm.io.NetworkUtils;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
@ -38,6 +38,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
public class AndroidNetworkUtils { public class AndroidNetworkUtils {
@ -56,6 +57,15 @@ public class AndroidNetworkUtils {
void onFilesUploadDone(@NonNull Map<File, String> errors); 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 { public static class RequestResponse {
private Request request; private Request request;
private String response; private String response;
@ -74,35 +84,46 @@ public class AndroidNetworkUtils {
} }
} }
public interface OnRequestsResultListener { public interface OnSendRequestsListener {
void onResult(@NonNull List<RequestResponse> results); void onRequestSent(@NonNull RequestResponse response);
void onRequestsSent(@NonNull List<RequestResponse> results);
} }
public static void sendRequestsAsync(final OsmandApplication ctx, public static void sendRequestsAsync(@Nullable final OsmandApplication ctx,
final List<Request> requests, @NonNull final List<Request> requests,
final OnRequestsResultListener listener) { @Nullable final OnSendRequestsListener listener) {
new AsyncTask<Void, Void, List<RequestResponse>>() { new AsyncTask<Void, RequestResponse, List<RequestResponse>>() {
@Override @Override
protected List<RequestResponse> doInBackground(Void... params) { protected List<RequestResponse> doInBackground(Void... params) {
List<RequestResponse> responses = new ArrayList<>(); List<RequestResponse> responses = new ArrayList<>();
for (Request request : requests) { for (Request request : requests) {
RequestResponse requestResponse;
try { try {
String response = sendRequest(ctx, request.getUrl(), request.getParameters(), String response = sendRequest(ctx, request.getUrl(), request.getParameters(),
request.getUserOperation(), request.isToastAllowed(), request.isPost()); request.getUserOperation(), request.isToastAllowed(), request.isPost());
responses.add(new RequestResponse(request, response)); requestResponse = new RequestResponse(request, response);
} catch (Exception e) { } catch (Exception e) {
responses.add(new RequestResponse(request, null)); requestResponse = new RequestResponse(request, null);
} }
responses.add(requestResponse);
publishProgress(requestResponse);
} }
return responses; return responses;
} }
@Override
protected void onProgressUpdate(RequestResponse... values) {
if (listener != null) {
listener.onRequestSent(values[0]);
}
}
@Override @Override
protected void onPostExecute(@NonNull List<RequestResponse> results) { protected void onPostExecute(@NonNull List<RequestResponse> results) {
if (listener != null) { if (listener != null) {
listener.onResult(results); listener.onRequestsSent(results);
} }
} }
@ -146,7 +167,7 @@ public class AndroidNetworkUtils {
@Override @Override
protected String doInBackground(Void... params) { protected String doInBackground(Void... params) {
return downloadFile(url, fileToSave); return downloadFile(url, fileToSave, false, null);
} }
@Override @Override
@ -158,8 +179,80 @@ public class AndroidNetworkUtils {
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
} }
public static String sendRequest(OsmandApplication ctx, String url, Map<String, String> parameters, public static void downloadFilesAsync(final @NonNull String url,
String userOperation, boolean toastAllowed, boolean post) { 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; HttpURLConnection connection = null;
try { try {
@ -177,7 +270,7 @@ public class AndroidNetworkUtils {
String paramsSeparator = url.indexOf('?') == -1 ? "?" : "&"; String paramsSeparator = url.indexOf('?') == -1 ? "?" : "&";
connection = NetworkUtils.getHttpURLConnection(params == null || post ? url : url + paramsSeparator + params); connection = NetworkUtils.getHttpURLConnection(params == null || post ? url : url + paramsSeparator + params);
connection.setRequestProperty("Accept-Charset", "UTF-8"); 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); connection.setConnectTimeout(15000);
if (params != null && post) { if (params != null && post) {
connection.setDoInput(true); connection.setDoInput(true);
@ -200,9 +293,10 @@ public class AndroidNetworkUtils {
} }
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
if (toastAllowed) { if (toastAllowed && ctx != null) {
String msg = userOperation String msg = (!Algorithms.isEmpty(userOperation) ? userOperation + " " : "")
+ " " + ctx.getString(R.string.failed_op) + ": " + connection.getResponseMessage(); + ctx.getString(R.string.failed_op) + ": "
+ connection.getResponseMessage();
showToast(ctx, msg); showToast(ctx, msg);
} }
} else { } else {
@ -233,17 +327,17 @@ public class AndroidNetworkUtils {
} catch (NullPointerException e) { } catch (NullPointerException e) {
// that's tricky case why NPE is thrown to fix that problem httpClient could be used // 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); String msg = ctx.getString(R.string.auth_failed);
showToast(ctx, msg); showToast(ctx, msg);
} }
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
if (toastAllowed) { if (toastAllowed && ctx != null) {
showToast(ctx, MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template) showToast(ctx, MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template)
+ ": " + ctx.getResources().getString(R.string.shared_string_unexpected_error), userOperation)); + ": " + ctx.getResources().getString(R.string.shared_string_unexpected_error), userOperation));
} }
} catch (IOException e) { } catch (IOException e) {
if (toastAllowed) { if (toastAllowed && ctx != null) {
showToast(ctx, MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template) showToast(ctx, MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template)
+ ": " + ctx.getResources().getString(R.string.shared_string_io_error), userOperation)); + ": " + ctx.getResources().getString(R.string.shared_string_io_error), userOperation));
} }
@ -277,18 +371,23 @@ public class AndroidNetworkUtils {
return res; 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; String error = null;
try { try {
URLConnection connection = NetworkUtils.getHttpURLConnection(url); URLConnection connection = NetworkUtils.getHttpURLConnection(url);
connection.setConnectTimeout(CONNECTION_TIMEOUT); connection.setConnectTimeout(CONNECTION_TIMEOUT);
connection.setReadTimeout(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(); fileToSave.getParentFile().mkdirs();
OutputStream stream = null; OutputStream stream = null;
try { try {
stream = new FileOutputStream(fileToSave); stream = new FileOutputStream(fileToSave);
Algorithms.streamCopy(inputStream, stream); Algorithms.streamCopy(inputStream, stream, progress, 1024);
stream.flush(); stream.flush();
} finally { } finally {
Algorithms.closeStream(inputStream); Algorithms.closeStream(inputStream);
@ -307,12 +406,17 @@ public class AndroidNetworkUtils {
private static final String BOUNDARY = "CowMooCowMooCowCowCow"; private static final String BOUNDARY = "CowMooCowMooCowCowCow";
public static String uploadFile(@NonNull String urlText, @NonNull File file, boolean gzip, public static String uploadFile(@NonNull String urlText, @NonNull File file, boolean gzip,
@NonNull Map<String, String> additionalParams, @Nullable Map<String, String> headers) throws IOException { @NonNull Map<String, String> additionalParams,
return uploadFile(urlText, new FileInputStream(file), file.getName(), gzip, additionalParams, headers); @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, public static String uploadFile(@NonNull String urlText, @NonNull InputStream inputStream,
Map<String, String> additionalParams, @Nullable Map<String, String> headers) { @NonNull String fileName, boolean gzip,
@NonNull Map<String, String> additionalParams,
@Nullable Map<String, String> headers,
@Nullable IProgress progress) {
URL url; URL url;
try { try {
boolean firstPrm = !urlText.contains("?"); boolean firstPrm = !urlText.contains("?");
@ -350,11 +454,11 @@ public class AndroidNetworkUtils {
ous.flush(); ous.flush();
if (gzip) { if (gzip) {
GZIPOutputStream gous = new GZIPOutputStream(ous, 1024); GZIPOutputStream gous = new GZIPOutputStream(ous, 1024);
Algorithms.streamCopy(bis, gous); Algorithms.streamCopy(bis, gous, progress, 1024);
gous.flush(); gous.flush();
gous.finish(); gous.finish();
} else { } else {
Algorithms.streamCopy(bis, ous); Algorithms.streamCopy(bis, ous, progress, 1024);
} }
ous.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes()); ous.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes());
@ -406,8 +510,19 @@ public class AndroidNetworkUtils {
@NonNull @NonNull
protected Map<File, String> doInBackground(Void... v) { protected Map<File, String> doInBackground(Void... v) {
Map<File, String> errors = new HashMap<>(); Map<File, String> errors = new HashMap<>();
for (File file : files) { for (final File file : files) {
final int[] progressValue = {0};
publishProgress(file, 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 { try {
Map<String, String> params = new HashMap<>(parameters); Map<String, String> params = new HashMap<>(parameters);
if (callback != null) { if (callback != null) {
@ -416,14 +531,14 @@ public class AndroidNetworkUtils {
params.putAll(additionalParams); params.putAll(additionalParams);
} }
} }
String res = uploadFile(url, file, gzip, params, headers); String res = uploadFile(url, file, gzip, params, headers, progress);
if (res != null) { if (res != null) {
errors.put(file, res); errors.put(file, res);
} }
} catch (Exception e) { } catch (Exception e) {
errors.put(file, e.getMessage()); errors.put(file, e.getMessage());
} }
publishProgress(file, 100); publishProgress(file, Integer.MAX_VALUE);
} }
return errors; return errors;
} }
@ -484,4 +599,39 @@ public class AndroidNetworkUtils {
return post; 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) {
}
}
} }

View file

@ -22,6 +22,8 @@ import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.StateListDrawable; import android.graphics.drawable.StateListDrawable;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.IBinder; import android.os.IBinder;
import android.os.PowerManager; import android.os.PowerManager;
import android.os.StatFs; import android.os.StatFs;
@ -264,6 +266,11 @@ public class AndroidUtils {
return ""; 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) { public static View findParentViewById(View view, int id) {
ViewParent viewParent = view.getParent(); ViewParent viewParent = view.getParent();
@ -856,11 +863,39 @@ public class AndroidUtils {
return result; 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) { public static long getAvailableSpace(@Nullable File dir) {
if (dir != null && dir.canRead()) { if (dir != null && dir.canRead()) {
try { try {
StatFs fs = new StatFs(dir.getAbsolutePath()); 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) { } catch (IllegalArgumentException e) {
LOG.error(e); LOG.error(e);
} }
@ -887,13 +922,6 @@ public class AndroidUtils {
return -1; 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, public static CharSequence getStyledString(CharSequence baseString, CharSequence stringToInsertAndStyle,
CharacterStyle baseStyle, CharacterStyle replaceStyle) { CharacterStyle baseStyle, CharacterStyle replaceStyle) {
int indexOfPlaceholder = baseString.toString().indexOf(STRING_PLACEHOLDER); int indexOfPlaceholder = baseString.toString().indexOf(STRING_PLACEHOLDER);

View file

@ -184,7 +184,8 @@ public class AnalyticsHelper extends SQLiteOpenHelper {
String jsonStr = json.toString(); String jsonStr = json.toString();
InputStream inputStream = new ByteArrayInputStream(jsonStr.getBytes()); 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) { if (res != null) {
return; return;
} }

View file

@ -31,6 +31,7 @@ import net.osmand.osm.MapPoiTypes;
import net.osmand.plus.activities.LocalIndexHelper; import net.osmand.plus.activities.LocalIndexHelper;
import net.osmand.plus.activities.LocalIndexInfo; import net.osmand.plus.activities.LocalIndexInfo;
import net.osmand.plus.activities.SavingTrackHelper; import net.osmand.plus.activities.SavingTrackHelper;
import net.osmand.plus.backup.BackupHelper;
import net.osmand.plus.base.MapViewTrackingUtilities; import net.osmand.plus.base.MapViewTrackingUtilities;
import net.osmand.plus.download.DownloadActivity; import net.osmand.plus.download.DownloadActivity;
import net.osmand.plus.download.ui.AbstractLoadLocalIndexTask; 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.oprAuthHelper = startupInit(new OprAuthHelper(app), OprAuthHelper.class);
app.onlineRoutingHelper = startupInit(new OnlineRoutingHelper(app), OnlineRoutingHelper.class); app.onlineRoutingHelper = startupInit(new OnlineRoutingHelper(app), OnlineRoutingHelper.class);
app.itineraryHelper = startupInit(new ItineraryHelper(app), ItineraryHelper.class); app.itineraryHelper = startupInit(new ItineraryHelper(app), ItineraryHelper.class);
app.backupHelper = startupInit(new BackupHelper(app), BackupHelper.class);
initOpeningHoursParser(); initOpeningHoursParser();
} }

View file

@ -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 @Nullable
public Drawable getColoredIconForGroup(String groupName) { public Drawable getColoredIconForGroup(String groupName) {
String groupIdName = FavoriteGroup.convertDisplayNameToGroupIdName(context, groupName); String groupIdName = FavoriteGroup.convertDisplayNameToGroupIdName(context, groupName);

View file

@ -18,7 +18,7 @@ import androidx.annotation.Nullable;
public class GPXDatabase { 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 DB_NAME = "gpx_database";
private static final String GPX_TABLE_NAME = "gpxTable"; 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_COLOR = "color";
private static final String GPX_COL_FILE_LAST_MODIFIED_TIME = "fileLastModifiedTime"; 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_TYPE = "splitType";
private static final String GPX_COL_SPLIT_INTERVAL = "splitInterval"; private static final String GPX_COL_SPLIT_INTERVAL = "splitInterval";
@ -98,6 +99,7 @@ public class GPXDatabase {
GPX_COL_WPT_POINTS + " int, " + GPX_COL_WPT_POINTS + " int, " +
GPX_COL_COLOR + " TEXT, " + GPX_COL_COLOR + " TEXT, " +
GPX_COL_FILE_LAST_MODIFIED_TIME + " long, " + GPX_COL_FILE_LAST_MODIFIED_TIME + " long, " +
GPX_COL_FILE_LAST_UPLOADED_TIME + " long, " +
GPX_COL_SPLIT_TYPE + " int, " + GPX_COL_SPLIT_TYPE + " int, " +
GPX_COL_SPLIT_INTERVAL + " double, " + GPX_COL_SPLIT_INTERVAL + " double, " +
GPX_COL_API_IMPORTED + " int, " + // 1 = true, 0 = false GPX_COL_API_IMPORTED + " int, " + // 1 = true, 0 = false
@ -133,6 +135,7 @@ public class GPXDatabase {
GPX_COL_WPT_POINTS + ", " + GPX_COL_WPT_POINTS + ", " +
GPX_COL_COLOR + ", " + GPX_COL_COLOR + ", " +
GPX_COL_FILE_LAST_MODIFIED_TIME + ", " + GPX_COL_FILE_LAST_MODIFIED_TIME + ", " +
GPX_COL_FILE_LAST_UPLOADED_TIME + ", " +
GPX_COL_SPLIT_TYPE + ", " + GPX_COL_SPLIT_TYPE + ", " +
GPX_COL_SPLIT_INTERVAL + ", " + GPX_COL_SPLIT_INTERVAL + ", " +
GPX_COL_API_IMPORTED + ", " + GPX_COL_API_IMPORTED + ", " +
@ -184,6 +187,7 @@ public class GPXDatabase {
private int splitType; private int splitType;
private double splitInterval; private double splitInterval;
private long fileLastModifiedTime; private long fileLastModifiedTime;
private long fileLastUploadedTime;
private boolean apiImported; private boolean apiImported;
private boolean showAsMarkers; private boolean showAsMarkers;
private boolean joinSegments; private boolean joinSegments;
@ -200,6 +204,11 @@ public class GPXDatabase {
this.color = color; this.color = color;
} }
public GpxDataItem(File file, long fileLastUploadedTime) {
this.file = file;
this.fileLastUploadedTime = fileLastUploadedTime;
}
public GpxDataItem(File file, @NonNull GPXFile gpxFile) { public GpxDataItem(File file, @NonNull GPXFile gpxFile) {
this.file = file; this.file = file;
readGpxParams(gpxFile); readGpxParams(gpxFile);
@ -263,6 +272,10 @@ public class GPXDatabase {
return fileLastModifiedTime; return fileLastModifiedTime;
} }
public long getFileLastUploadedTime() {
return fileLastUploadedTime;
}
public int getSplitType() { public int getSplitType() {
return splitType; return splitType;
} }
@ -441,10 +454,13 @@ public class GPXDatabase {
db.execSQL("UPDATE " + GPX_TABLE_NAME + " SET " + GPX_COL_SHOW_START_FINISH + " = ? " + db.execSQL("UPDATE " + GPX_TABLE_NAME + " SET " + GPX_COL_SHOW_START_FINISH + " = ? " +
"WHERE " + GPX_COL_SHOW_START_FINISH + " IS NULL", new Object[]{1}); "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 + ");"); 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); SQLiteConnection db = openConnection(false);
if (db != null) { if (db != null) {
try { try {
@ -464,6 +480,25 @@ public class GPXDatabase {
return false; 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) { public boolean rename(@Nullable GpxDataItem item, File currentFile, File newFile) {
SQLiteConnection db = openConnection(false); SQLiteConnection db = openConnection(false);
if (db != null){ if (db != null){
@ -721,11 +756,11 @@ public class GPXDatabase {
String gradientScaleType = item.gradientScaleType != null ? item.gradientScaleType.getTypeName() : null; String gradientScaleType = item.gradientScaleType != null ? item.gradientScaleType.getTypeName() : null;
if (a != null) { if (a != null) {
db.execSQL( 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, new Object[] {fileName, fileDir, a.totalDistance, a.totalTracks, a.startTime, a.endTime,
a.timeSpan, a.timeMoving, a.totalDistanceMoving, a.diffElevationUp, a.diffElevationDown, a.timeSpan, a.timeMoving, a.totalDistanceMoving, a.diffElevationUp, a.diffElevationDown,
a.avgElevation, a.minElevation, a.maxElevation, a.maxSpeed, a.avgSpeed, a.points, a.wptPoints, 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, Algorithms.encodeStringSet(item.analysis.wptCategoryNames), item.showAsMarkers ? 1 : 0,
item.joinSegments ? 1 : 0, item.showArrows ? 1 : 0, item.showStartFinish ? 1 : 0, item.width, item.joinSegments ? 1 : 0, item.showArrows ? 1 : 0, item.showStartFinish ? 1 : 0, item.width,
item.gradientSpeedPalette, item.gradientAltitudePalette, item.gradientSlopePalette, gradientScaleType}); item.gradientSpeedPalette, item.gradientAltitudePalette, item.gradientSlopePalette, gradientScaleType});
@ -735,6 +770,7 @@ public class GPXDatabase {
GPX_COL_DIR + ", " + GPX_COL_DIR + ", " +
GPX_COL_COLOR + ", " + GPX_COL_COLOR + ", " +
GPX_COL_FILE_LAST_MODIFIED_TIME + ", " + GPX_COL_FILE_LAST_MODIFIED_TIME + ", " +
GPX_COL_FILE_LAST_UPLOADED_TIME + ", " +
GPX_COL_SPLIT_TYPE + ", " + GPX_COL_SPLIT_TYPE + ", " +
GPX_COL_SPLIT_INTERVAL + ", " + GPX_COL_SPLIT_INTERVAL + ", " +
GPX_COL_API_IMPORTED + ", " + GPX_COL_API_IMPORTED + ", " +
@ -747,8 +783,8 @@ public class GPXDatabase {
GPX_COL_GRADIENT_ALTITUDE_COLOR + ", " + GPX_COL_GRADIENT_ALTITUDE_COLOR + ", " +
GPX_COL_GRADIENT_SLOPE_COLOR + ", " + GPX_COL_GRADIENT_SLOPE_COLOR + ", " +
GPX_COL_GRADIENT_SCALE_TYPE + GPX_COL_GRADIENT_SCALE_TYPE +
") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
new Object[] {fileName, fileDir, color, 0, item.splitType, item.splitInterval, 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.apiImported ? 1 : 0, item.showAsMarkers ? 1 : 0, item.joinSegments ? 1 : 0,
item.showArrows ? 1 : 0, item.showStartFinish ? 1 : 0, item.width, item.showArrows ? 1 : 0, item.showStartFinish ? 1 : 0, item.width,
Algorithms.gradientPaletteToString(item.gradientSpeedPalette), Algorithms.gradientPaletteToString(item.gradientSpeedPalette),
@ -828,19 +864,20 @@ public class GPXDatabase {
int wptPoints = (int)query.getInt(17); int wptPoints = (int)query.getInt(17);
String color = query.getString(18); String color = query.getString(18);
long fileLastModifiedTime = query.getLong(19); long fileLastModifiedTime = query.getLong(19);
int splitType = (int)query.getInt(20); long fileLastUploadedTime = query.getLong(20);
double splitInterval = query.getDouble(21); int splitType = (int)query.getInt(21);
boolean apiImported = query.getInt(22) == 1; double splitInterval = query.getDouble(22);
String wptCategoryNames = query.getString(23); boolean apiImported = query.getInt(23) == 1;
boolean showAsMarkers = query.getInt(24) == 1; String wptCategoryNames = query.getString(24);
boolean joinSegments = query.getInt(25) == 1; boolean showAsMarkers = query.getInt(25) == 1;
boolean showArrows = query.getInt(26) == 1; boolean joinSegments = query.getInt(26) == 1;
boolean showStartFinish = query.getInt(27) == 1; boolean showArrows = query.getInt(27) == 1;
String width = query.getString(28); boolean showStartFinish = query.getInt(28) == 1;
String gradientSpeedPalette = query.getString(29); String width = query.getString(29);
String gradientAltitudePalette = query.getString(30); String gradientSpeedPalette = query.getString(30);
String gradientSlopePalette = query.getString(31); String gradientAltitudePalette = query.getString(31);
String gradientScaleType = query.getString(32); String gradientSlopePalette = query.getString(32);
String gradientScaleType = query.getString(33);
GPXTrackAnalysis a = new GPXTrackAnalysis(); GPXTrackAnalysis a = new GPXTrackAnalysis();
a.totalDistance = totalDistance; a.totalDistance = totalDistance;
@ -873,6 +910,7 @@ public class GPXDatabase {
GpxDataItem item = new GpxDataItem(new File(dir, fileName), a); GpxDataItem item = new GpxDataItem(new File(dir, fileName), a);
item.color = parseColor(color); item.color = parseColor(color);
item.fileLastModifiedTime = fileLastModifiedTime; item.fileLastModifiedTime = fileLastModifiedTime;
item.fileLastUploadedTime = fileLastUploadedTime;
item.splitType = splitType; item.splitType = splitType;
item.splitInterval = splitInterval; item.splitInterval = splitInterval;
item.apiImported = apiImported; item.apiImported = apiImported;

View file

@ -78,6 +78,12 @@ public class GpxDbHelper {
return res; 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) { public boolean updateGradientScalePalette(@NonNull GpxDataItem item, @NonNull GradientScaleType gradientScaleType, int[] palette) {
boolean res = db.updateGradientScaleColor(item, gradientScaleType, palette); boolean res = db.updateGradientScaleColor(item, gradientScaleType, palette);
putToCache(item); putToCache(item);

View file

@ -291,10 +291,12 @@ public class GpxSelectionHelper {
return group; return group;
} }
private String getGroupName(GPXFile g) { public String getGroupName(GPXFile g) {
String name = g.path; String name = g.path;
if (g.showCurrentTrack) { if (g.showCurrentTrack) {
name = getString(R.string.shared_string_currently_recording_track); name = getString(R.string.shared_string_currently_recording_track);
} else if (Algorithms.isEmpty(name)) {
name = getString(R.string.current_route);
} else { } else {
int i = name.lastIndexOf('/'); int i = name.lastIndexOf('/');
if (i >= 0) { if (i >= 0) {

View file

@ -52,6 +52,7 @@ import net.osmand.plus.activities.SavingTrackHelper;
import net.osmand.plus.activities.actions.OsmAndDialogs; import net.osmand.plus.activities.actions.OsmAndDialogs;
import net.osmand.plus.api.SQLiteAPI; import net.osmand.plus.api.SQLiteAPI;
import net.osmand.plus.api.SQLiteAPIImpl; import net.osmand.plus.api.SQLiteAPIImpl;
import net.osmand.plus.backup.BackupHelper;
import net.osmand.plus.base.MapViewTrackingUtilities; import net.osmand.plus.base.MapViewTrackingUtilities;
import net.osmand.plus.download.DownloadIndexesThread; import net.osmand.plus.download.DownloadIndexesThread;
import net.osmand.plus.download.DownloadService; import net.osmand.plus.download.DownloadService;
@ -169,6 +170,7 @@ public class OsmandApplication extends MultiDexApplication {
MeasurementEditingContext measurementEditingContext; MeasurementEditingContext measurementEditingContext;
OnlineRoutingHelper onlineRoutingHelper; OnlineRoutingHelper onlineRoutingHelper;
ItineraryHelper itineraryHelper; ItineraryHelper itineraryHelper;
BackupHelper backupHelper;
private Map<String, Builder> customRoutingConfigs = new ConcurrentHashMap<>(); private Map<String, Builder> customRoutingConfigs = new ConcurrentHashMap<>();
private File externalStorageDirectory; private File externalStorageDirectory;
@ -474,6 +476,10 @@ public class OsmandApplication extends MultiDexApplication {
return itineraryHelper; return itineraryHelper;
} }
public BackupHelper getBackupHelper() {
return backupHelper;
}
public TransportRoutingHelper getTransportRoutingHelper() { public TransportRoutingHelper getTransportRoutingHelper() {
return transportRoutingHelper; return transportRoutingHelper;
} }

View file

@ -5,6 +5,7 @@ import android.app.ProgressDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener; import android.content.DialogInterface.OnCancelListener;
import android.content.res.Resources;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.widget.ProgressBar; import android.widget.ProgressBar;
@ -204,7 +205,8 @@ public class ProgressImplementation implements IProgress {
work = -1; work = -1;
progress = 0; progress = 0;
if (taskName != null) { 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); mViewUpdateHandler.sendEmptyMessage(HANDLER_START_TASK);
} }
} }

View file

@ -442,15 +442,14 @@ public class UiUtilities {
} catch (Throwable e) { } } catch (Throwable e) { }
} }
public static void rotateImageByLayoutDirection(ImageView image, int layoutDirection) { public static void rotateImageByLayoutDirection(ImageView image) {
if (image == null) { if (image == null) {
return; 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); image.setRotationY(rotation);
} }
public static void updateCustomRadioButtons(Context app, View buttonsView, boolean nightMode, public static void updateCustomRadioButtons(Context app, View buttonsView, boolean nightMode,
CustomRadioButtonType buttonType) { CustomRadioButtonType buttonType) {
int activeColor = ContextCompat.getColor(app, nightMode int activeColor = ContextCompat.getColor(app, nightMode

View file

@ -13,6 +13,7 @@ import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.SQLiteTileSource; import net.osmand.plus.SQLiteTileSource;
import net.osmand.plus.Version; import net.osmand.plus.Version;
import net.osmand.plus.download.SrtmDownloadItem;
import net.osmand.plus.download.ui.AbstractLoadLocalIndexTask; import net.osmand.plus.download.ui.AbstractLoadLocalIndexTask;
import net.osmand.plus.voice.JSMediaCommandPlayerImpl; import net.osmand.plus.voice.JSMediaCommandPlayerImpl;
import net.osmand.plus.voice.JSTTSCommandPlayerImpl; import net.osmand.plus.voice.JSTTSCommandPlayerImpl;
@ -143,8 +144,6 @@ public class LocalIndexHelper {
return null; return null;
} }
public List<LocalIndexInfo> getLocalIndexInfos(String downloadName) { public List<LocalIndexInfo> getLocalIndexInfos(String downloadName) {
List<LocalIndexInfo> list = new ArrayList<>(); List<LocalIndexInfo> list = new ArrayList<>();
LocalIndexInfo info = getLocalIndexInfo(LocalIndexType.MAP_DATA, downloadName, false, false); LocalIndexInfo info = getLocalIndexInfo(LocalIndexType.MAP_DATA, downloadName, false, false);
@ -313,7 +312,7 @@ public class LocalIndexHelper {
} }
} }
} }
private void loadTravelData(File mapPath, List<LocalIndexInfo> result, AbstractLoadLocalIndexTask loadTask) { private void loadTravelData(File mapPath, List<LocalIndexInfo> result, AbstractLoadLocalIndexTask loadTask) {
if (mapPath.canRead()) { if (mapPath.canRead()) {
for (File mapFile : listFilesSorted(mapPath)) { for (File mapFile : listFilesSorted(mapPath)) {
@ -333,14 +332,15 @@ public class LocalIndexHelper {
if (mapPath.canRead()) { if (mapPath.canRead()) {
for (File mapFile : listFilesSorted(mapPath)) { for (File mapFile : listFilesSorted(mapPath)) {
if (mapFile.isFile() && mapFile.getName().endsWith(IndexConstants.BINARY_MAP_INDEX_EXT)) { if (mapFile.isFile() && mapFile.getName().endsWith(IndexConstants.BINARY_MAP_INDEX_EXT)) {
String fileName = mapFile.getName();
LocalIndexType lt = LocalIndexType.MAP_DATA; LocalIndexType lt = LocalIndexType.MAP_DATA;
if (mapFile.getName().endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)) { if (SrtmDownloadItem.isSrtmFile(fileName)) {
lt = LocalIndexType.SRTM_DATA; 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; lt = LocalIndexType.WIKI_DATA;
} }
LocalIndexInfo info = new LocalIndexInfo(lt, mapFile, backup, app); LocalIndexInfo info = new LocalIndexInfo(lt, mapFile, backup, app);
if (loadedMaps.containsKey(mapFile.getName()) && !backup) { if (loadedMaps.containsKey(fileName) && !backup) {
info.setLoaded(true); info.setLoaded(true);
} }
updateDescription(info); updateDescription(info);
@ -403,7 +403,7 @@ public class LocalIndexHelper {
if (fileName.endsWith(IndexConstants.SQLITE_EXT)) { if (fileName.endsWith(IndexConstants.SQLITE_EXT)) {
return fileName.substring(0, fileName.length() - IndexConstants.SQLITE_EXT.length()); return fileName.substring(0, fileName.length() - IndexConstants.SQLITE_EXT.length());
} }
if (localIndexInfo.getType() == TRAVEL_DATA && if (localIndexInfo.getType() == TRAVEL_DATA &&
fileName.endsWith(IndexConstants.BINARY_WIKIVOYAGE_MAP_INDEX_EXT)) { fileName.endsWith(IndexConstants.BINARY_WIKIVOYAGE_MAP_INDEX_EXT)) {
return fileName.substring(0, fileName.length() - IndexConstants.BINARY_WIKIVOYAGE_MAP_INDEX_EXT.length()); return fileName.substring(0, fileName.length() - IndexConstants.BINARY_WIKIVOYAGE_MAP_INDEX_EXT.length());
} }
@ -430,5 +430,4 @@ public class LocalIndexHelper {
return fileName; return fileName;
} }
} }
} }

View file

@ -94,6 +94,12 @@ public class MapActivityKeyListener implements KeyEvent.Callback {
mapActivity.getMapViewTrackingUtilities().backToLocationImpl(); mapActivity.getMapViewTrackingUtilities().backToLocationImpl();
} else if (keyCode == KeyEvent.KEYCODE_D) { } else if (keyCode == KeyEvent.KEYCODE_D) {
mapActivity.getMapViewTrackingUtilities().switchRotateMapMode(); 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)) { } else if (mapScrollHelper.isAvailableKeyCode(keyCode)) {
return mapScrollHelper.onKeyUp(keyCode, event); return mapScrollHelper.onKeyUp(keyCode, event);
} else if (settings.EXTERNAL_INPUT_DEVICE.get() == PARROT_EXTERNAL_DEVICE) { } else if (settings.EXTERNAL_INPUT_DEVICE.get() == PARROT_EXTERNAL_DEVICE) {
@ -121,13 +127,7 @@ public class MapActivityKeyListener implements KeyEvent.Callback {
return true; return true;
} }
} else if (settings.EXTERNAL_INPUT_DEVICE.get() == GENERIC_EXTERNAL_DEVICE) { } else if (settings.EXTERNAL_INPUT_DEVICE.get() == GENERIC_EXTERNAL_DEVICE) {
if (keyCode == KeyEvent.KEYCODE_MINUS) { // currently doesn't process specific commands
mapActivity.changeZoom(-1);
return true;
} else if (keyCode == KeyEvent.KEYCODE_PLUS || keyCode == KeyEvent.KEYCODE_EQUALS) {
mapActivity.changeZoom(1);
return true;
}
} else if (OsmandPlugin.onMapActivityKeyUp(mapActivity, keyCode)) { } else if (OsmandPlugin.onMapActivityKeyUp(mapActivity, keyCode)) {
return true; return true;
} }

View file

@ -109,7 +109,7 @@ public class PluginInfoFragment extends BaseOsmAndFragment implements PluginStat
} }
} }
}); });
UiUtilities.rotateImageByLayoutDirection(closeButton, AndroidUtils.getLayoutDirection(app)); UiUtilities.rotateImageByLayoutDirection(closeButton);
Drawable pluginImage = plugin.getAssetResourceImage(); Drawable pluginImage = plugin.getAssetResourceImage();
if (pluginImage != null) { if (pluginImage != null) {

View file

@ -101,7 +101,7 @@ public class PluginsFragment extends BaseOsmAndFragment implements PluginStateLi
} }
} }
}); });
UiUtilities.rotateImageByLayoutDirection(closeButton, AndroidUtils.getLayoutDirection(app)); UiUtilities.rotateImageByLayoutDirection(closeButton);
adapter = new PluginsListAdapter(requireContext()); adapter = new PluginsListAdapter(requireContext());

View file

@ -22,7 +22,6 @@ import android.media.MediaRecorder;
import android.media.SoundPool; import android.media.SoundPool;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.StatFs;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.view.Display; import android.view.Display;
import android.view.KeyEvent; 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 bitrate = (((p.videoBitRate + p.audioBitRate) / 8f) * 60f) / (1 << 30); // gigabytes per minute
double clipSpace = bitrate * AV_RS_CLIP_LENGTH.get(); double clipSpace = bitrate * AV_RS_CLIP_LENGTH.get();
double storageSize = AV_RS_STORAGE_SIZE.get(); double storageSize = AV_RS_STORAGE_SIZE.get();
double availableSpace = (double) AndroidUtils.getAvailableSpace(app) / (1 << 30) - clipSpace;
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;
}
if (usedSpace + clipSpace > storageSize || clipSpace > availableSpace) { if (usedSpace + clipSpace > storageSize || clipSpace > availableSpace) {
Arrays.sort(files, new Comparator<File>() { Arrays.sort(files, new Comparator<File>() {

View file

@ -11,7 +11,6 @@ import android.media.CamcorderProfile;
import android.media.MediaRecorder; import android.media.MediaRecorder;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.StatFs;
import android.text.SpannableString; import android.text.SpannableString;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -42,7 +41,6 @@ import net.osmand.plus.widgets.style.CustomTypefaceSpan;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -381,16 +379,7 @@ public class MultimediaNotesFragment extends BaseSettingsFragment implements Cop
private void setupStorageSizePref(AudioVideoNotesPlugin plugin) { private void setupStorageSizePref(AudioVideoNotesPlugin plugin) {
ListPreferenceEx storageSize = (ListPreferenceEx) findPreference(plugin.AV_RS_STORAGE_SIZE.getId()); ListPreferenceEx storageSize = (ListPreferenceEx) findPreference(plugin.AV_RS_STORAGE_SIZE.getId());
File dir = app.getAppPath("").getParentFile(); long size = AndroidUtils.getTotalSpace(app) / (1 << 30);
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);
}
}
if (size > 0) { if (size > 0) {
int value = 1; int value = 1;
ArrayList<Integer> gbList = new ArrayList<>(); ArrayList<Integer> gbList = new ArrayList<>();

View 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);
}
}

View 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);
}
}
}

View 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;
}
}

View 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);
}
}
}

View 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;
}
}

View file

@ -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");
}
}

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}
}

View 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;
}
}
}

View file

@ -32,6 +32,10 @@ public class BaseBottomSheetItem {
return tag; return tag;
} }
public void setTag(Object tag) {
this.tag = tag;
}
public BaseBottomSheetItem(View view, public BaseBottomSheetItem(View view,
@LayoutRes int layoutId, @LayoutRes int layoutId,
Object tag, Object tag,

View file

@ -11,7 +11,6 @@ import android.content.DialogInterface;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.StatFs;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
@ -34,10 +33,10 @@ import net.osmand.FileUtils;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
import net.osmand.ValueHolder; import net.osmand.ValueHolder;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.ProgressImplementation; import net.osmand.plus.ProgressImplementation;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.download.DownloadActivity; import net.osmand.plus.download.DownloadActivity;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -93,18 +92,6 @@ public class DashChooseAppDirFragment {
selectePathTemp = null; 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() { public void updateView() {
if (type == OsmandSettings.EXTERNAL_STORAGE_TYPE_INTERNAL_FILE) { if (type == OsmandSettings.EXTERNAL_STORAGE_TYPE_INTERNAL_FILE) {
locationPath.setText(R.string.storage_directory_internal_app); locationPath.setText(R.string.storage_directory_internal_app);
@ -117,7 +104,7 @@ public class DashChooseAppDirFragment {
} else if (type == OsmandSettings.EXTERNAL_STORAGE_TYPE_SPECIFIED) { } else if (type == OsmandSettings.EXTERNAL_STORAGE_TYPE_SPECIFIED) {
locationPath.setText(R.string.storage_directory_manual); 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; boolean copyFiles = !currentAppFile.getAbsolutePath().equals(selectedFile.getAbsolutePath()) && !mapsCopied;
warningReadonly.setVisibility(copyFiles ? View.VISIBLE : View.GONE); warningReadonly.setVisibility(copyFiles ? View.VISIBLE : View.GONE);
if (copyFiles) { if (copyFiles) {

View file

@ -1,12 +1,9 @@
package net.osmand.plus.development; package net.osmand.plus.development;
import android.app.Activity; import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils; import android.util.Pair;
import android.util.Patterns;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.View; import android.view.View;
import android.widget.EditText; import android.widget.EditText;
@ -17,56 +14,58 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar; 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.AndroidUtils;
import net.osmand.IndexConstants;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.ProgressImplementation;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.UiUtilities; import net.osmand.plus.UiUtilities;
import net.osmand.plus.UiUtilities.DialogButtonType; import net.osmand.plus.UiUtilities.DialogButtonType;
import net.osmand.plus.activities.OsmandActionBarActivity; 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.settings.backend.OsmandSettings;
import net.osmand.plus.widgets.OsmandTextFieldBoxes;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File; import java.io.File;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.text.DateFormat;
import java.util.HashMap; import java.util.Date;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
public class TestBackupActivity extends OsmandActionBarActivity { public class TestBackupActivity extends OsmandActionBarActivity {
// TODO pass actual sub order id! private static final DateFormat DF = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
private static final String TEST_ORDER_ID = "";
private OsmandApplication app; private OsmandApplication app;
private OsmandSettings settings; private OsmandSettings settings;
private BackupHelper backupHelper;
private ProgressBar progressBar; private ProgressBar progressBar;
private View buttonRegister; private View buttonRegister;
private View buttonVerify; private View buttonVerify;
private View buttonRefresh;
private View buttonBackup; private View buttonBackup;
private View buttonRestore; private View buttonRestore;
private EditText emailEditText; private EditText emailEditText;
private OsmandTextFieldBoxes tokenEdit;
private EditText tokenEditText; private EditText tokenEditText;
private TextView infoView; private TextView infoView;
public interface OnResultListener { private BackupInfo backupInfo;
void onResult(boolean success, @Nullable String result);
}
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
app = getMyApplication(); app = getMyApplication();
settings = app.getSettings(); settings = app.getSettings();
backupHelper = app.getBackupHelper();
final WeakReference<TestBackupActivity> activityRef = new WeakReference<>(this); final WeakReference<TestBackupActivity> activityRef = new WeakReference<>(this);
boolean nightMode = !app.getSettings().isLightContent(); 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); buttonRegister = findViewById(R.id.btn_register);
UiUtilities.setupDialogButton(nightMode, buttonRegister, DialogButtonType.PRIMARY, "Register"); UiUtilities.setupDialogButton(nightMode, buttonRegister, DialogButtonType.PRIMARY, "Register");
buttonVerify = findViewById(R.id.btn_verify); buttonVerify = findViewById(R.id.btn_verify);
UiUtilities.setupDialogButton(nightMode, buttonVerify, DialogButtonType.PRIMARY, "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); buttonBackup = findViewById(R.id.btn_backup);
UiUtilities.setupDialogButton(nightMode, buttonBackup, DialogButtonType.PRIMARY, "Backup"); UiUtilities.setupDialogButton(nightMode, buttonBackup, DialogButtonType.PRIMARY, "Backup");
buttonRestore = findViewById(R.id.btn_restore); buttonRestore = findViewById(R.id.btn_restore);
UiUtilities.setupDialogButton(nightMode, buttonRestore, DialogButtonType.PRIMARY, "Restore"); UiUtilities.setupDialogButton(nightMode, buttonRestore, DialogButtonType.PRIMARY, "Restore");
tokenEdit = findViewById(R.id.edit_token_label);
tokenEditText = findViewById(R.id.edit_token); tokenEditText = findViewById(R.id.edit_token);
infoView = findViewById(R.id.text_info); infoView = findViewById(R.id.text_info);
progressBar = findViewById(R.id.progress_bar); progressBar = findViewById(R.id.progress_bar);
@ -109,22 +116,31 @@ public class TestBackupActivity extends OsmandActionBarActivity {
if (!Algorithms.isEmpty(email)) { if (!Algorithms.isEmpty(email)) {
emailEditText.setText(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() { buttonRegister.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
String email = emailEditText.getText().toString(); String email = emailEditText.getText().toString();
if (isEmailValid(email)) { if (AndroidUtils.isValidEmail(email)) {
buttonRegister.setEnabled(false); buttonRegister.setEnabled(false);
settings.BACKUP_USER_EMAIL.set(email); settings.BACKUP_USER_EMAIL.set(email);
progressBar.setVisibility(View.VISIBLE); progressBar.setVisibility(View.VISIBLE);
registerUser(email, new OnResultListener() { backupHelper.registerUser(email, new OnRegisterUserListener() {
@Override @Override
public void onResult(boolean success, @Nullable String result) { public void onRegisterUser(int status, @Nullable String message) {
TestBackupActivity a = activityRef.get(); TestBackupActivity a = activityRef.get();
if (AndroidUtils.isActivityNotDestroyed(a)) { if (AndroidUtils.isActivityNotDestroyed(a)) {
a.progressBar.setVisibility(View.GONE); a.progressBar.setVisibility(View.GONE);
a.buttonRegister.setEnabled(!success); a.buttonRegister.setEnabled(status != BackupHelper.STATUS_SUCCESS);
a.buttonVerify.setEnabled(success); a.tokenEdit.setVisibility(View.VISIBLE);
a.buttonVerify.setVisibility(View.VISIBLE);
a.buttonVerify.setEnabled(status == BackupHelper.STATUS_SUCCESS);
a.tokenEditText.requestFocus(); a.tokenEditText.requestFocus();
} }
} }
@ -139,17 +155,22 @@ public class TestBackupActivity extends OsmandActionBarActivity {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
String token = tokenEditText.getText().toString(); String token = tokenEditText.getText().toString();
if (isTokenValid(token)) { if (BackupHelper.isTokenValid(token)) {
buttonVerify.setEnabled(false); buttonVerify.setEnabled(false);
progressBar.setVisibility(View.VISIBLE); progressBar.setVisibility(View.VISIBLE);
registerDevice(token, new OnResultListener() { backupHelper.registerDevice(token, new BackupHelper.OnRegisterDeviceListener() {
@Override @Override
public void onResult(boolean success, @Nullable String result) { public void onRegisterDevice(int status, @Nullable String message) {
TestBackupActivity a = activityRef.get(); TestBackupActivity a = activityRef.get();
if (AndroidUtils.isActivityNotDestroyed(a)) { if (AndroidUtils.isActivityNotDestroyed(a)) {
a.progressBar.setVisibility(View.GONE); a.progressBar.setVisibility(View.GONE);
a.buttonVerify.setEnabled(!success); a.buttonVerify.setEnabled(status != BackupHelper.STATUS_SUCCESS);
a.loadBackupInfo(); 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() { buttonBackup.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { 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() { buttonRestore.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
} if (backupInfo != null) {
}); BackupTask task = new BackupTask(backupInfo, TestBackupActivity.this, new OnBackupListener() {
loadBackupInfo();
}
private void loadBackupInfo() {
if (!Algorithms.isEmpty(getDeviceId()) && !Algorithms.isEmpty(getAccessToken())) {
final WeakReference<TestBackupActivity> activityRef = new WeakReference<>(this);
progressBar.setVisibility(View.VISIBLE);
loadBackupInfo(new OnResultListener() {
@Override
public void onResult(boolean success, @Nullable String result) {
TestBackupActivity a = activityRef.get();
if (AndroidUtils.isActivityNotDestroyed(a)) {
a.progressBar.setVisibility(View.GONE);
a.infoView.setText(result);
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 @Override
public void run() { public void onBackupDone(@Nullable Map<File, String> uploadErrors, @Nullable Map<File, String> downloadErrors,
try { @Nullable Map<UserFile, String> deleteErrors, @Nullable String error) {
if (progress.getDialog().isShowing()) { TestBackupActivity a = activityRef.get();
progress.getDialog().dismiss(); 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);
} }
} catch (Exception e) { a.infoView.setText(description);
//ignored a.infoView.requestFocus();
a.prepareBackup();
} }
} }
}, 300); });
app.showToastMessage("Uploaded " + (files.size() - errors.size() + " files" + task.runRestore();
(errors.size() > 0 ? ". Errors: " + errors.size() : "")));
loadBackupInfo();
} }
} }
}); });
prepareBackup();
} }
private void loadBackupInfo(@Nullable final OnResultListener listener) { private String getBackupErrorsDescription(@Nullable Map<File, String> uploadErrors, @Nullable Map<File, String> downloadErrors, @Nullable Map<UserFile, String> deleteErrors, @Nullable String error) {
Map<String, String> params = new HashMap<>(); StringBuilder sb = new StringBuilder();
params.put("deviceid", getDeviceId()); if (!Algorithms.isEmpty(uploadErrors)) {
params.put("accessToken", getAccessToken()); sb.append("--- Upload errors ---").append("\n");
AndroidNetworkUtils.sendRequestAsync(app, "https://osmand.net/userdata/list-files", params, "Get backup info", true, false, new OnRequestResultListener() { 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);
PrepareBackupTask prepareBackupTask = new PrepareBackupTask(this, new OnPrepareBackupListener() {
@Override @Override
public void onResult(String resultJson) { public void onBackupPrepared(@Nullable BackupInfo backupInfo, @Nullable String error) {
boolean success = false; TestBackupActivity.this.backupInfo = backupInfo;
StringBuilder resultString = new StringBuilder(); TestBackupActivity a = activityRef.get();
if (!Algorithms.isEmpty(resultJson)) { if (AndroidUtils.isActivityNotDestroyed(a)) {
try { String description = "Last uploaded: " + DF.format(new Date(settings.BACKUP_LAST_UPLOADED_TIME.get())) + "\n\n";
/* if (error != null) {
{ description += error;
"totalZipSize": 21792, } else if (backupInfo == null) {
"totalFileSize": 185920, description += "No data";
"totalFiles": 1, } else {
"totalFileVersions": 2, description += "Files to upload: " + backupInfo.filesToUpload.size()
"uniqueFiles": [ + "\nFiles to download: " + backupInfo.filesToDownload.size()
{ + "\nFiles to delete: " + backupInfo.filesToDelete.size()
"userid": 1033, + "\nConflicts: " + backupInfo.filesToMerge.size()
"id": 7, + "\n" + getBackupDescription(backupInfo);
"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) {
} }
} a.infoView.setText(description);
if (listener != null) { a.infoView.requestFocus();
listener.onResult(success, resultString.toString());
} }
} }
}); });
} prepareBackupTask.prepare();
private boolean isTokenValid(String token) {
return token.matches("[0-9]+");
} }
private int resolveResourceId(final Activity activity, final int attr) { private int resolveResourceId(final Activity activity, final int attr) {
@ -423,173 +345,4 @@ public class TestBackupActivity extends OsmandActionBarActivity {
activity.getTheme().resolveAttribute(attr, typedvalueattr, true); activity.getTheme().resolveAttribute(attr, typedvalueattr, true);
return typedvalueattr.resourceId; 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;
}
}
} }

View file

@ -530,7 +530,7 @@ public class ConfigureMapMenu {
TextView switchText = (TextView) v.findViewById(R.id.switchText); TextView switchText = (TextView) v.findViewById(R.id.switchText);
switchText.setText(activity.getString(R.string.translit_name_if_miss, txtValues[position])); switchText.setText(activity.getString(R.string.translit_name_if_miss, txtValues[position]));
SwitchCompat check = (SwitchCompat) v.findViewById(R.id.check); 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); check.setOnCheckedChangeListener(translitChangdListener);
UiUtilities.setupCompoundButton(nightMode, selectedProfileColor, check); UiUtilities.setupCompoundButton(nightMode, selectedProfileColor, check);
} else { } else {
@ -548,6 +548,7 @@ public class ConfigureMapMenu {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
selectedLanguageIndex = which; selectedLanguageIndex = which;
transliterateNames = settings.MAP_TRANSLITERATE_NAMES.isSet() ? transliterateNames : txtIds[which].equals("en");
((AlertDialog) dialog).getListView().setSelection(which); ((AlertDialog) dialog).getListView().setSelection(which);
singleChoiceAdapter.notifyDataSetChanged(); singleChoiceAdapter.notifyDataSetChanged();
} }

View file

@ -652,7 +652,7 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
TextView messageTextView = (TextView) view.findViewById(R.id.leftTextView); TextView messageTextView = (TextView) view.findViewById(R.id.leftTextView);
ProgressBar sizeProgress = (ProgressBar) view.findViewById(R.id.progressBar); ProgressBar sizeProgress = (ProgressBar) view.findViewById(R.id.progressBar);
File dir = activity.getMyApplication().getAppPath("").getParentFile(); File dir = activity.getMyApplication().getAppPath(null);
String size = ""; String size = "";
int percent = 0; int percent = 0;
if (dir.canRead()) { if (dir.canRead()) {

View file

@ -10,6 +10,7 @@ import net.osmand.map.OsmandRegions;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.Version; import net.osmand.plus.Version;
import net.osmand.plus.activities.LocalIndexInfo;
import net.osmand.plus.helpers.FileNameTranslationHelper; import net.osmand.plus.helpers.FileNameTranslationHelper;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
@ -27,11 +28,12 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import static net.osmand.IndexConstants.BINARY_MAP_INDEX_EXT; import static net.osmand.IndexConstants.BINARY_MAP_INDEX_EXT;
import static net.osmand.plus.activities.LocalIndexHelper.LocalIndexType.SRTM_DATA;
public class DownloadActivityType { public class DownloadActivityType {
private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.MM.yyyy", Locale.US); private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.MM.yyyy", Locale.US);
private static Map<String, DownloadActivityType> byTag = new HashMap<>(); private static Map<String, DownloadActivityType> byTag = new HashMap<>();
public static final DownloadActivityType NORMAL_FILE = public static final DownloadActivityType NORMAL_FILE =
new DownloadActivityType(R.string.download_regular_maps, "map", 10); new DownloadActivityType(R.string.download_regular_maps, "map", 10);
public static final DownloadActivityType VOICE_FILE = public static final DownloadActivityType VOICE_FILE =
@ -83,7 +85,7 @@ public class DownloadActivityType {
iconResource = R.drawable.ic_map; iconResource = R.drawable.ic_map;
} }
public int getStringResource(){ public int getStringResource() {
return stringResource; return stringResource;
} }
@ -101,7 +103,7 @@ public class DownloadActivityType {
public static boolean isCountedInDownloads(IndexItem es) { public static boolean isCountedInDownloads(IndexItem es) {
DownloadActivityType tp = es.getType(); DownloadActivityType tp = es.getType();
if(tp == NORMAL_FILE || tp == ROADS_FILE){ if (tp == NORMAL_FILE || tp == ROADS_FILE) {
if (!es.extra) { if (!es.extra) {
return true; return true;
} }
@ -120,17 +122,17 @@ public class DownloadActivityType {
public static Collection<DownloadActivityType> values() { public static Collection<DownloadActivityType> values() {
return byTag.values(); return byTag.values();
} }
protected static String addVersionToExt(String ext, int version) { protected static String addVersionToExt(String ext, int version) {
return "_" + version + ext; return "_" + version + ext;
} }
public boolean isAccepted(String fileName) { public boolean isAccepted(String fileName) {
if(NORMAL_FILE == this) { if (NORMAL_FILE == this) {
return fileName.endsWith(addVersionToExt(IndexConstants.BINARY_MAP_INDEX_EXT_ZIP, IndexConstants.BINARY_MAP_VERSION)) return fileName.endsWith(addVersionToExt(IndexConstants.BINARY_MAP_INDEX_EXT_ZIP, IndexConstants.BINARY_MAP_VERSION))
|| fileName.endsWith(IndexConstants.EXTRA_ZIP_EXT) || fileName.endsWith(IndexConstants.EXTRA_ZIP_EXT)
|| fileName.endsWith(IndexConstants.SQLITE_EXT); || fileName.endsWith(IndexConstants.SQLITE_EXT);
} else if(ROADS_FILE == this) { } else if (ROADS_FILE == this) {
return fileName.endsWith(addVersionToExt(IndexConstants.BINARY_ROAD_MAP_INDEX_EXT_ZIP, IndexConstants.BINARY_MAP_VERSION)); return fileName.endsWith(addVersionToExt(IndexConstants.BINARY_ROAD_MAP_INDEX_EXT_ZIP, IndexConstants.BINARY_MAP_VERSION));
} else if (VOICE_FILE == this) { } else if (VOICE_FILE == this) {
return fileName.endsWith(addVersionToExt(IndexConstants.VOICE_INDEX_EXT_ZIP, IndexConstants.VOICE_VERSION)); return fileName.endsWith(addVersionToExt(IndexConstants.VOICE_INDEX_EXT_ZIP, IndexConstants.VOICE_VERSION));
@ -145,8 +147,9 @@ public class DownloadActivityType {
return fileName.endsWith(addVersionToExt(IndexConstants.BINARY_TRAVEL_GUIDE_MAP_INDEX_EXT_ZIP, return fileName.endsWith(addVersionToExt(IndexConstants.BINARY_TRAVEL_GUIDE_MAP_INDEX_EXT_ZIP,
IndexConstants.BINARY_MAP_VERSION)); IndexConstants.BINARY_MAP_VERSION));
} else if (SRTM_COUNTRY_FILE == this) { } else if (SRTM_COUNTRY_FILE == this) {
return fileName.endsWith(addVersionToExt(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT_ZIP, boolean srtm = fileName.endsWith(addVersionToExt(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT_ZIP, IndexConstants.BINARY_MAP_VERSION));
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) { } else if (HILLSHADE_FILE == this) {
return fileName.endsWith(IndexConstants.SQLITE_EXT); return fileName.endsWith(IndexConstants.SQLITE_EXT);
} else if (SLOPE_FILE == this) { } else if (SLOPE_FILE == this) {
@ -160,7 +163,7 @@ public class DownloadActivityType {
} }
return false; return false;
} }
public File getDownloadFolder(OsmandApplication ctx, IndexItem indexItem) { public File getDownloadFolder(OsmandApplication ctx, IndexItem indexItem) {
if (NORMAL_FILE == this) { if (NORMAL_FILE == this) {
if (indexItem.fileName.endsWith(IndexConstants.SQLITE_EXT)) { if (indexItem.fileName.endsWith(IndexConstants.SQLITE_EXT)) {
@ -196,17 +199,17 @@ public class DownloadActivityType {
} }
public boolean isZipStream(OsmandApplication ctx, IndexItem indexItem) { public boolean isZipStream(OsmandApplication ctx, IndexItem indexItem) {
return HILLSHADE_FILE != this && SLOPE_FILE != this && SQLITE_FILE != this && WIKIVOYAGE_FILE != this && GPX_FILE != this; return HILLSHADE_FILE != this && SLOPE_FILE != this && SQLITE_FILE != this && WIKIVOYAGE_FILE != this && GPX_FILE != this;
} }
public boolean isZipFolder(OsmandApplication ctx, IndexItem indexItem) { public boolean isZipFolder(OsmandApplication ctx, IndexItem indexItem) {
return this == VOICE_FILE; return this == VOICE_FILE;
} }
public boolean preventMediaIndexing(OsmandApplication ctx, IndexItem indexItem) { public boolean preventMediaIndexing(OsmandApplication ctx, IndexItem indexItem) {
return this == VOICE_FILE && indexItem.fileName.endsWith(IndexConstants.VOICE_INDEX_EXT_ZIP); return this == VOICE_FILE && indexItem.fileName.endsWith(IndexConstants.VOICE_INDEX_EXT_ZIP);
} }
public String getUnzipExtension(OsmandApplication ctx, IndexItem indexItem) { public String getUnzipExtension(OsmandApplication ctx, IndexItem indexItem) {
if (NORMAL_FILE == this) { if (NORMAL_FILE == this) {
if (indexItem.fileName.endsWith(IndexConstants.BINARY_MAP_INDEX_EXT_ZIP)) { if (indexItem.fileName.endsWith(IndexConstants.BINARY_MAP_INDEX_EXT_ZIP)) {
@ -217,7 +220,7 @@ public class DownloadActivityType {
return IndexConstants.EXTRA_EXT; return IndexConstants.EXTRA_EXT;
} else if (indexItem.fileName.endsWith(IndexConstants.SQLITE_EXT)) { } else if (indexItem.fileName.endsWith(IndexConstants.SQLITE_EXT)) {
return IndexConstants.SQLITE_EXT; return IndexConstants.SQLITE_EXT;
} else if (indexItem.fileName.endsWith(IndexConstants.ANYVOICE_INDEX_EXT_ZIP)){ } else if (indexItem.fileName.endsWith(IndexConstants.ANYVOICE_INDEX_EXT_ZIP)) {
return ""; return "";
} }
} else if (ROADS_FILE == this) { } else if (ROADS_FILE == this) {
@ -227,7 +230,7 @@ public class DownloadActivityType {
} else if (FONT_FILE == this) { } else if (FONT_FILE == this) {
return IndexConstants.FONT_INDEX_EXT; return IndexConstants.FONT_INDEX_EXT;
} else if (SRTM_COUNTRY_FILE == this) { } else if (SRTM_COUNTRY_FILE == this) {
return IndexConstants.BINARY_SRTM_MAP_INDEX_EXT; return SrtmDownloadItem.getExtension(indexItem);
} else if (WIKIPEDIA_FILE == this) { } else if (WIKIPEDIA_FILE == this) {
return IndexConstants.BINARY_WIKI_MAP_INDEX_EXT; return IndexConstants.BINARY_WIKI_MAP_INDEX_EXT;
} else if (WIKIVOYAGE_FILE == this) { } else if (WIKIVOYAGE_FILE == this) {
@ -249,9 +252,9 @@ public class DownloadActivityType {
} }
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public String getUrlSuffix(OsmandApplication ctx) { public String getUrlSuffix(OsmandApplication ctx) {
if (this== ROADS_FILE) { if (this == ROADS_FILE) {
return "&road=yes"; return "&road=yes";
} else if (this == LIVE_UPDATES_FILE) { } else if (this == LIVE_UPDATES_FILE) {
return "&aosmc=yes"; return "&aosmc=yes";
@ -280,7 +283,7 @@ public class DownloadActivityType {
public String getBaseUrl(OsmandApplication ctx, String fileName) { public String getBaseUrl(OsmandApplication ctx, String fileName) {
String url = "https://" + IndexConstants.INDEX_DOWNLOAD_DOMAIN + "/download?event=2&" String url = "https://" + IndexConstants.INDEX_DOWNLOAD_DOMAIN + "/download?event=2&"
+ Version.getVersionAsURLParam(ctx) + "&file=" + encode(fileName); + Version.getVersionAsURLParam(ctx) + "&file=" + encode(fileName);
if(this == LIVE_UPDATES_FILE && fileName.length() > 16) { if (this == LIVE_UPDATES_FILE && fileName.length() > 16) {
// DATE_AND_EXT_STR_LEN = "_18_06_02.obf.gz".length() // DATE_AND_EXT_STR_LEN = "_18_06_02.obf.gz".length()
String region = fileName.substring(0, fileName.length() - 16).toLowerCase(); String region = fileName.substring(0, fileName.length() - 16).toLowerCase();
url += "&region=" + encode(region); url += "&region=" + encode(region);
@ -343,7 +346,7 @@ public class DownloadActivityType {
} }
return ""; return "";
} }
public String getVisibleName(DownloadItem downloadItem, Context ctx, OsmandRegions osmandRegions, boolean includingParent) { public String getVisibleName(DownloadItem downloadItem, Context ctx, OsmandRegions osmandRegions, boolean includingParent) {
if (this == VOICE_FILE) { if (this == VOICE_FILE) {
String fileName = downloadItem.getFileName(); String fileName = downloadItem.getFileName();
@ -361,6 +364,9 @@ public class DownloadActivityType {
if (basename.endsWith(FileNameTranslationHelper.WIKI_NAME)) { if (basename.endsWith(FileNameTranslationHelper.WIKI_NAME)) {
return FileNameTranslationHelper.getWikiName(ctx, basename); return FileNameTranslationHelper.getWikiName(ctx, basename);
} }
if (basename.endsWith(FileNameTranslationHelper.WIKIVOYAGE_NAME)) {
return FileNameTranslationHelper.getWikivoyageName(ctx, basename);
}
// if (this == HILLSHADE_FILE){ // if (this == HILLSHADE_FILE){
// return FileNameTranslationHelper.getHillShadeName(ctx, osmandRegions, bn); // return FileNameTranslationHelper.getHillShadeName(ctx, osmandRegions, bn);
// } // }
@ -383,7 +389,7 @@ public class DownloadActivityType {
return osmandRegions.getLocaleName(basename, includingParent); return osmandRegions.getLocaleName(basename, includingParent);
} }
public String getTargetFileName(IndexItem item) { public String getTargetFileName(IndexItem item) {
String fileName = item.fileName; String fileName = item.fileName;
// if(fileName.endsWith(IndexConstants.VOICE_INDEX_EXT_ZIP) || // if(fileName.endsWith(IndexConstants.VOICE_INDEX_EXT_ZIP) ||
@ -423,7 +429,7 @@ public class DownloadActivityType {
} }
String baseNameWithoutVersion = fileName.substring(0, l); String baseNameWithoutVersion = fileName.substring(0, l);
if (this == SRTM_COUNTRY_FILE) { if (this == SRTM_COUNTRY_FILE) {
return baseNameWithoutVersion + IndexConstants.BINARY_SRTM_MAP_INDEX_EXT; return baseNameWithoutVersion + SrtmDownloadItem.getExtension(item);
} }
if (this == WIKIPEDIA_FILE) { if (this == WIKIPEDIA_FILE) {
return baseNameWithoutVersion + IndexConstants.BINARY_WIKI_MAP_INDEX_EXT; return baseNameWithoutVersion + IndexConstants.BINARY_WIKI_MAP_INDEX_EXT;
@ -487,7 +493,7 @@ public class DownloadActivityType {
return fileName.substring(0, l); return fileName.substring(0, l);
} }
if (this == LIVE_UPDATES_FILE) { if (this == LIVE_UPDATES_FILE) {
if(fileName.indexOf('.') > 0){ if (fileName.indexOf('.') > 0) {
return fileName.substring(0, fileName.indexOf('.')); return fileName.substring(0, fileName.indexOf('.'));
} }
return fileName; return fileName;
@ -495,10 +501,10 @@ public class DownloadActivityType {
int ls = fileName.lastIndexOf('_'); int ls = fileName.lastIndexOf('_');
if (ls >= 0) { if (ls >= 0) {
return fileName.substring(0, ls); return fileName.substring(0, ls);
} else if(fileName.indexOf('.') > 0){ } else if (fileName.indexOf('.') > 0) {
return fileName.substring(0, fileName.indexOf('.')); return fileName.substring(0, fileName.indexOf('.'));
} }
return fileName; return fileName;
} }
} }

View file

@ -7,6 +7,7 @@ import net.osmand.osm.io.NetworkUtils;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.Version; import net.osmand.plus.Version;
import net.osmand.plus.download.IndexItem.DownloadEntry;
import net.osmand.plus.helpers.FileNameTranslationHelper; import net.osmand.plus.helpers.FileNameTranslationHelper;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
@ -199,33 +200,35 @@ public class DownloadFileHelper {
public boolean isWifiConnected(){ public boolean isWifiConnected(){
return ctx.getSettings().isWifiConnected(); return ctx.getSettings().isWifiConnected();
} }
public boolean downloadFile(IndexItem.DownloadEntry de, IProgress progress, public boolean downloadFile(IndexItem.DownloadEntry de, IProgress progress,
List<File> toReIndex, DownloadFileShowWarning showWarningCallback, boolean forceWifi) throws InterruptedException { List<File> toReIndex, DownloadFileShowWarning showWarningCallback, boolean forceWifi) throws InterruptedException {
try { try {
final List<InputStream> downloadInputStreams = new ArrayList<InputStream>(); final List<InputStream> downloadInputStreams = new ArrayList<InputStream>();
URL url = new URL(de.urlToDownload); //$NON-NLS-1$ URL url = new URL(de.urlToDownload); //$NON-NLS-1$
log.info("Url downloading " + de.urlToDownload); log.info("Url downloading " + de.urlToDownload);
downloadInputStreams.add(getInputStreamToDownload(url, forceWifi)); downloadInputStreams.add(getInputStreamToDownload(url, forceWifi));
de.fileToDownload = de.targetFile; de.fileToDownload = de.targetFile;
if(!de.unzipFolder) { if (!de.unzipFolder) {
de.fileToDownload = new File(de.targetFile.getParentFile(), de.targetFile.getName() +".download"); de.fileToDownload = new File(de.targetFile.getParentFile(), de.targetFile.getName() + ".download");
} }
unzipFile(de, progress, downloadInputStreams); unzipFile(de, progress, downloadInputStreams);
if(!de.targetFile.getAbsolutePath().equals(de.fileToDownload.getAbsolutePath())){ if (!de.targetFile.getAbsolutePath().equals(de.fileToDownload.getAbsolutePath())) {
boolean successfull = Algorithms.removeAllFiles(de.targetFile); boolean successful = Algorithms.removeAllFiles(de.targetFile);
if (successfull) { if (successful) {
ctx.getResourceManager().closeFile(de.targetFile.getName()); ctx.getResourceManager().closeFile(de.targetFile.getName());
} }
boolean renamed = de.fileToDownload.renameTo(de.targetFile); boolean renamed = de.fileToDownload.renameTo(de.targetFile);
if(!renamed) { if (!renamed) {
showWarningCallback.showWarning(ctx.getString(R.string.shared_string_io_error) + ": old file can't be deleted"); showWarningCallback.showWarning(ctx.getString(R.string.shared_string_io_error) + ": old file can't be deleted");
return false; return false;
} }
} }
if (de.type == DownloadActivityType.VOICE_FILE){ if (de.type == DownloadActivityType.VOICE_FILE) {
copyVoiceConfig(de); copyVoiceConfig(de);
} else if (de.type == DownloadActivityType.SRTM_COUNTRY_FILE) {
removePreviousSrtmFile(de);
} }
toReIndex.add(de.targetFile); toReIndex.add(de.targetFile);
return true; 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) { private void copyVoiceConfig(IndexItem.DownloadEntry de) {
File f = ctx.getAppPath("/voice/" + de.baseName + "/_config.p"); File f = ctx.getAppPath("/voice/" + de.baseName + "/_config.p");
if (f.exists()) try { if (f.exists()) try {
@ -386,23 +409,20 @@ public class DownloadFileHelper {
} }
return r; return r;
} }
@Override @Override
public int available() throws IOException { public int available() throws IOException {
int av = 0; int av = 0;
for(int i = currentRead; i < delegate.length; i++) { for (int i = currentRead; i < delegate.length; i++) {
av += delegate[i].available(); av += delegate[i].available();
} }
return av; return av;
} }
public int getAndClearReadCount() { public int getAndClearReadCount() {
int last = count; int last = count;
count = 0; count = 0;
return last; return last;
} }
} }
} }

View file

@ -9,7 +9,6 @@ import android.net.TrafficStats;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.AsyncTask.Status; import android.os.AsyncTask.Status;
import android.os.StatFs;
import android.view.View; import android.view.View;
import android.widget.Toast; import android.widget.Toast;
@ -17,13 +16,12 @@ import androidx.annotation.UiThread;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import net.osmand.AndroidNetworkUtils; import net.osmand.AndroidNetworkUtils;
import net.osmand.AndroidUtils;
import net.osmand.IndexConstants; import net.osmand.IndexConstants;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
import net.osmand.map.WorldRegion; import net.osmand.map.WorldRegion;
import net.osmand.map.WorldRegion.RegionParams; import net.osmand.map.WorldRegion.RegionParams;
import net.osmand.plus.OsmandApplication; 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.R;
import net.osmand.plus.Version; import net.osmand.plus.Version;
import net.osmand.plus.base.BasicProgressAsyncTask; 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.helpers.DatabaseHelper;
import net.osmand.plus.notifications.OsmandNotification; import net.osmand.plus.notifications.OsmandNotification;
import net.osmand.plus.resources.ResourceManager; 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 net.osmand.util.Algorithms;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -240,9 +240,12 @@ public class DownloadIndexesThread {
} }
public void cancelDownload(DownloadItem item) { public void cancelDownload(DownloadItem item) {
if (item instanceof MultipleIndexItem) { if (item instanceof MultipleDownloadItem) {
MultipleIndexItem multipleIndexItem = (MultipleIndexItem) item; MultipleDownloadItem multipleDownloadItem = (MultipleDownloadItem) item;
cancelDownload(multipleIndexItem.getAllIndexes()); cancelDownload(multipleDownloadItem.getAllIndexes());
} else if (item instanceof SrtmDownloadItem) {
IndexItem indexItem = ((SrtmDownloadItem) item).getIndexItem();
cancelDownload(indexItem);
} else if (item instanceof IndexItem) { } else if (item instanceof IndexItem) {
IndexItem indexItem = (IndexItem) item; IndexItem indexItem = (IndexItem) item;
cancelDownload(indexItem); cancelDownload(indexItem);
@ -299,19 +302,8 @@ public class DownloadIndexesThread {
return null; return null;
} }
@SuppressWarnings("deprecation")
public double getAvailableSpace() { public double getAvailableSpace() {
File dir = app.getAppPath("").getParentFile(); return AndroidUtils.getAvailableSpace(app) / (1 << 20);
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;
} }
/// PRIVATE IMPL /// PRIVATE IMPL

View file

@ -3,12 +3,14 @@ package net.osmand.plus.download;
import android.content.Context; import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.osmand.map.OsmandRegions; import net.osmand.map.OsmandRegions;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
import java.io.File; import java.io.File;
import java.text.DateFormat;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -55,6 +57,12 @@ public abstract class DownloadItem {
return type.getBasename(this); return type.getBasename(this);
} }
@NonNull
public abstract List<File> getDownloadedFiles(@NonNull OsmandApplication app);
@Nullable
public abstract String getAdditionalDescription(Context ctx);
protected abstract double getSizeToDownloadInMb(); protected abstract double getSizeToDownloadInMb();
public abstract double getArchiveSizeMB(); public abstract double getArchiveSizeMB();
@ -69,8 +77,7 @@ public abstract class DownloadItem {
public abstract String getFileName(); public abstract String getFileName();
@NonNull public abstract String getDate(@NonNull DateFormat dateFormat, boolean remote);
public abstract List<File> getDownloadedFiles(@NonNull OsmandApplication app);
@NonNull @NonNull
public static String getFormattedMb(@NonNull Context ctx, double sizeInMb) { public static String getFormattedMb(@NonNull Context ctx, double sizeInMb) {

View file

@ -1,5 +1,26 @@
package net.osmand.plus.download; 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.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -11,29 +32,9 @@ import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.zip.GZIPInputStream; 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 { public class DownloadOsmandIndexesHelper {
private final static Log log = PlatformUtil.getLog(DownloadOsmandIndexesHelper.class); private final static Log log = PlatformUtil.getLog(DownloadOsmandIndexesHelper.class);
public static class IndexFileList implements Serializable { public static class IndexFileList implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -41,29 +42,29 @@ public class DownloadOsmandIndexesHelper {
IndexItem basemap; IndexItem basemap;
ArrayList<IndexItem> indexFiles = new ArrayList<IndexItem>(); ArrayList<IndexItem> indexFiles = new ArrayList<IndexItem>();
private String mapversion; private String mapversion;
private Comparator<IndexItem> comparator = new Comparator<IndexItem>(){ private Comparator<IndexItem> comparator = new Comparator<IndexItem>() {
@Override @Override
public int compare(IndexItem o1, IndexItem o2) { public int compare(IndexItem o1, IndexItem o2) {
String object1 = o1.getFileName(); String object1 = o1.getFileName();
String object2 = o2.getFileName(); String object2 = o2.getFileName();
if(object1.endsWith(IndexConstants.ANYVOICE_INDEX_EXT_ZIP)){ if (object1.endsWith(IndexConstants.ANYVOICE_INDEX_EXT_ZIP)) {
if(object2.endsWith(IndexConstants.ANYVOICE_INDEX_EXT_ZIP)){ if (object2.endsWith(IndexConstants.ANYVOICE_INDEX_EXT_ZIP)) {
return object1.compareTo(object2); return object1.compareTo(object2);
} else { } else {
return -1; return -1;
} }
} else if(object2.endsWith(IndexConstants.ANYVOICE_INDEX_EXT_ZIP)){ } else if (object2.endsWith(IndexConstants.ANYVOICE_INDEX_EXT_ZIP)) {
return 1; return 1;
} }
return object1.compareTo(object2); return object1.compareTo(object2);
} }
}; };
public void setDownloadedFromInternet(boolean downloadedFromInternet) { public void setDownloadedFromInternet(boolean downloadedFromInternet) {
this.downloadedFromInternet = downloadedFromInternet; this.downloadedFromInternet = downloadedFromInternet;
} }
public boolean isDownloadedFromInternet() { public boolean isDownloadedFromInternet() {
return downloadedFromInternet; return downloadedFromInternet;
} }
@ -75,12 +76,12 @@ public class DownloadOsmandIndexesHelper {
@SuppressLint("DefaultLocale") @SuppressLint("DefaultLocale")
public void add(IndexItem indexItem) { public void add(IndexItem indexItem) {
indexFiles.add(indexItem); indexFiles.add(indexItem);
if(indexItem.getFileName().toLowerCase().startsWith("world_basemap")) { if (indexItem.getFileName().toLowerCase().startsWith("world_basemap")) {
basemap = indexItem; basemap = indexItem;
} }
} }
public void sort(){ public void sort() {
Collections.sort(indexFiles, comparator); Collections.sort(indexFiles, comparator);
} }
@ -91,7 +92,7 @@ public class DownloadOsmandIndexesHelper {
public List<IndexItem> getIndexFiles() { public List<IndexItem> getIndexFiles() {
return indexFiles; return indexFiles;
} }
public IndexItem getBasemap() { public IndexItem getBasemap() {
return basemap; return basemap;
} }
@ -106,7 +107,7 @@ public class DownloadOsmandIndexesHelper {
return false; return false;
} }
} }
public static IndexFileList getIndexesList(OsmandApplication app) { public static IndexFileList getIndexesList(OsmandApplication app) {
PackageManager pm = app.getPackageManager(); PackageManager pm = app.getPackageManager();
@ -141,16 +142,16 @@ public class DownloadOsmandIndexesHelper {
} }
private static void listVoiceAssets(IndexFileList result, AssetManager amanager, PackageManager pm, private static void listVoiceAssets(IndexFileList result, AssetManager amanager, PackageManager pm,
OsmandSettings settings) { OsmandSettings settings) {
try { try {
File voicePath = settings.getContext().getAppPath(IndexConstants.VOICE_INDEX_DIR); File voicePath = settings.getContext().getAppPath(IndexConstants.VOICE_INDEX_DIR);
// list = amanager.list("voice"); // list = amanager.list("voice");
String date = ""; String date = "";
long dateModified = System.currentTimeMillis(); long dateModified = System.currentTimeMillis();
try { try {
OsmandApplication app = settings.getContext(); OsmandApplication app = settings.getContext();
ApplicationInfo appInfo = pm.getApplicationInfo(app.getPackageName(), 0); ApplicationInfo appInfo = pm.getApplicationInfo(app.getPackageName(), 0);
dateModified = new File(appInfo.sourceDir).lastModified(); dateModified = new File(appInfo.sourceDir).lastModified();
date = AndroidUtils.formatDate((Context) settings.getContext(), dateModified); date = AndroidUtils.formatDate((Context) settings.getContext(), dateModified);
} catch (NameNotFoundException e) { } catch (NameNotFoundException e) {
log.error(e); log.error(e);
@ -177,17 +178,17 @@ public class DownloadOsmandIndexesHelper {
log.error("Error while loading tts files from assets", e); //$NON-NLS-1$ log.error("Error while loading tts files from assets", e); //$NON-NLS-1$
} }
} }
private static IndexFileList downloadIndexesListFromInternet(OsmandApplication ctx){
private static IndexFileList downloadIndexesListFromInternet(OsmandApplication ctx) {
try { try {
IndexFileList result = new IndexFileList(); IndexFileList result = new IndexFileList();
log.debug("Start loading list of index files"); //$NON-NLS-1$ log.debug("Start loading list of index files"); //$NON-NLS-1$
try { try {
String strUrl = ctx.getAppCustomization().getIndexesUrl(); String strUrl = ctx.getAppCustomization().getIndexesUrl();
long nd = ctx.getAppInitializer().getFirstInstalledDays(); long nd = ctx.getAppInitializer().getFirstInstalledDays();
if(nd > 0) { if (nd > 0) {
strUrl += "&nd=" + nd; strUrl += "&nd=" + nd;
} }
strUrl += "&ns=" + ctx.getAppInitializer().getNumberOfStarts(); strUrl += "&ns=" + ctx.getAppInitializer().getNumberOfStarts();
try { try {
@ -202,12 +203,12 @@ public class DownloadOsmandIndexesHelper {
GZIPInputStream gzin = new GZIPInputStream(in); GZIPInputStream gzin = new GZIPInputStream(in);
parser.setInput(gzin, "UTF-8"); //$NON-NLS-1$ parser.setInput(gzin, "UTF-8"); //$NON-NLS-1$
int next; int next;
while((next = parser.next()) != XmlPullParser.END_DOCUMENT) { while ((next = parser.next()) != XmlPullParser.END_DOCUMENT) {
if (next == XmlPullParser.START_TAG) { if (next == XmlPullParser.START_TAG) {
DownloadActivityType tp = DownloadActivityType.getIndexType(parser.getAttributeValue(null, "type")); DownloadActivityType tp = DownloadActivityType.getIndexType(parser.getAttributeValue(null, "type"));
if (tp != null) { if (tp != null) {
IndexItem it = tp.parseIndexItem(ctx, parser); IndexItem it = tp.parseIndexItem(ctx, parser);
if(it != null) { if (it != null) {
result.add(it); result.add(it);
} }
} else if ("osmand_regions".equals(parser.getName())) { } else if ("osmand_regions".equals(parser.getName())) {
@ -226,7 +227,7 @@ public class DownloadOsmandIndexesHelper {
log.error("Error while loading indexes from repository", e); //$NON-NLS-1$ log.error("Error while loading indexes from repository", e); //$NON-NLS-1$
return null; return null;
} }
if (result.isAcceptable()) { if (result.isAcceptable()) {
return result; return result;
} else { } else {
@ -239,19 +240,19 @@ public class DownloadOsmandIndexesHelper {
} }
public static class AssetIndexItem extends IndexItem { public static class AssetIndexItem extends IndexItem {
private final String assetName; private final String assetName;
private final String destFile; private final String destFile;
private final long dateModified; private final long dateModified;
public AssetIndexItem(String fileName, String description, String date, public AssetIndexItem(String fileName, String description, String date,
long dateModified, String size, long sizeL, String assetName, String destFile, DownloadActivityType type) { long dateModified, String size, long sizeL, String assetName, String destFile, DownloadActivityType type) {
super(fileName, description, dateModified, size, sizeL, sizeL, type); super(fileName, description, dateModified, size, sizeL, sizeL, type);
this.dateModified = dateModified; this.dateModified = dateModified;
this.assetName = assetName; this.assetName = assetName;
this.destFile = destFile; this.destFile = destFile;
} }
public long getDateModified() { public long getDateModified() {
return dateModified; return dateModified;
} }
@ -261,7 +262,7 @@ public class DownloadOsmandIndexesHelper {
return new DownloadEntry(assetName, destFile, dateModified); return new DownloadEntry(assetName, destFile, dateModified);
} }
public String getDestFile(){ public String getDestFile() {
return destFile; return destFile;
} }
} }

View file

@ -25,12 +25,11 @@ import java.io.InputStream;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.ParseException; import java.text.ParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import static net.osmand.plus.download.DownloadResourceGroup.DownloadResourceGroupType.REGION_MAPS; import static net.osmand.plus.download.DownloadResourceGroup.DownloadResourceGroupType.REGION_MAPS;
@ -117,6 +116,16 @@ public class DownloadResources extends DownloadResourceGroup {
return res; 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) { public List<IndexItem> getIndexItems(WorldRegion region) {
if (groupByRegion != null) { if (groupByRegion != null) {
List<IndexItem> res = groupByRegion.get(region); List<IndexItem> res = groupByRegion.get(region);
@ -124,7 +133,7 @@ public class DownloadResources extends DownloadResourceGroup {
return res; return res;
} }
} }
return new LinkedList<>(); return Collections.emptyList();
} }
public void updateLoadedFiles() { public void updateLoadedFiles() {
@ -471,30 +480,60 @@ public class DownloadResources extends DownloadResourceGroup {
addGroup(otherGroup); addGroup(otherGroup);
createHillshadeSRTMGroups(); createHillshadeSRTMGroups();
collectMultipleIndexesItems(); replaceIndividualSrtmWithGroups(region);
createMultipleDownloadItems(region);
trimEmptyGroups(); trimEmptyGroups();
updateLoadedFiles(); updateLoadedFiles();
return true; return true;
} }
private void collectMultipleIndexesItems() { private void replaceIndividualSrtmWithGroups(@NonNull WorldRegion region) {
collectMultipleIndexesItems(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);
}
}
List<WorldRegion> subRegions = region.getSubregions();
if (!Algorithms.isEmpty(subRegions)) {
for (WorldRegion subRegion : subRegions) {
replaceIndividualSrtmWithGroups(subRegion);
}
}
} }
private void collectMultipleIndexesItems(@NonNull WorldRegion region) { private void createMultipleDownloadItems(@NonNull WorldRegion region) {
List<WorldRegion> subRegions = region.getSubregions(); List<WorldRegion> subRegions = region.getSubregions();
if (Algorithms.isEmpty(subRegions)) return; if (Algorithms.isEmpty(subRegions)) return;
DownloadResourceGroup group = getRegionMapsGroup(region); DownloadResourceGroup group = getRegionMapsGroup(region);
if (group != null) { if (group != null) {
boolean listModified = false; boolean listModified = false;
List<IndexItem> indexesList = group.getIndividualResources(); List<DownloadItem> downloadItems = group.getIndividualDownloadItems();
List<WorldRegion> regionsToCollect = removeDuplicateRegions(subRegions); List<WorldRegion> uniqueSubRegions = WorldRegion.removeDuplicates(subRegions);
for (DownloadActivityType type : DownloadActivityType.values()) { for (DownloadActivityType type : DownloadActivityType.values()) {
if (!doesListContainIndexWithType(indexesList, type)) { if (!isListContainsType(downloadItems, type)) {
List<IndexItem> indexesFromSubRegions = collectIndexesOfType(regionsToCollect, type); List<DownloadItem> itemsFromSubRegions = collectItemsOfType(uniqueSubRegions, type);
if (indexesFromSubRegions != null) { if (itemsFromSubRegions != null) {
group.addItem(new MultipleIndexItem(region, indexesFromSubRegions, type)); group.addItem(new MultipleDownloadItem(region, itemsFromSubRegions, type));
listModified = true; listModified = true;
} }
} }
@ -504,7 +543,7 @@ public class DownloadResources extends DownloadResourceGroup {
} }
} }
for (WorldRegion subRegion : subRegions) { for (WorldRegion subRegion : subRegions) {
collectMultipleIndexesItems(subRegion); createMultipleDownloadItems(subRegion);
} }
} }
@ -517,43 +556,21 @@ public class DownloadResources extends DownloadResourceGroup {
} }
@Nullable @Nullable
private List<IndexItem> collectIndexesOfType(@NonNull List<WorldRegion> regions, private List<DownloadItem> collectItemsOfType(@NonNull List<WorldRegion> regions,
@NonNull DownloadActivityType type) { @NonNull DownloadActivityType type) {
List<IndexItem> collectedIndexes = new ArrayList<>(); List<DownloadItem> collectedItems = new ArrayList<>();
for (WorldRegion region : regions) { for (WorldRegion region : regions) {
List<IndexItem> regionIndexes = getIndexItems(region);
boolean found = false; boolean found = false;
if (regionIndexes != null) { for (DownloadItem item : getDownloadItems(region)) {
for (IndexItem index : regionIndexes) { if (item.getType() == type) {
if (index.getType() == type) { found = true;
found = true; collectedItems.add(item);
collectedIndexes.add(index); break;
break;
}
} }
} }
if (!found) return null; if (!found) return null;
} }
return collectedIndexes; return collectedItems;
}
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;
} }
private void buildRegionsGroups(WorldRegion region, DownloadResourceGroup group) { private void buildRegionsGroups(WorldRegion region, DownloadResourceGroup group) {
@ -680,11 +697,11 @@ public class DownloadResources extends DownloadResourceGroup {
&& isIndexItemDownloaded(downloadThread, type, downloadRegion.getSuperregion(), res); && isIndexItemDownloaded(downloadThread, type, downloadRegion.getSuperregion(), res);
} }
private boolean doesListContainIndexWithType(List<IndexItem> indexItems, private boolean isListContainsType(List<DownloadItem> items,
DownloadActivityType type) { DownloadActivityType type) {
if (indexItems != null) { if (items != null) {
for (IndexItem indexItem : indexItems) { for (DownloadItem item : items) {
if (indexItem.getType() == type) { if (item.getType() == type) {
return true; return true;
} }
} }

View file

@ -1,6 +1,9 @@
package net.osmand.plus.download; package net.osmand.plus.download;
import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.osmand.IndexConstants; import net.osmand.IndexConstants;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
@ -19,6 +22,7 @@ import java.util.Date;
import java.util.List; import java.util.List;
public class IndexItem extends DownloadItem implements Comparable<IndexItem> { public class IndexItem extends DownloadItem implements Comparable<IndexItem> {
private static final Log log = PlatformUtil.getLog(IndexItem.class); private static final Log log = PlatformUtil.getLog(IndexItem.class);
String description; String description;
@ -225,6 +229,15 @@ public class IndexItem extends DownloadItem implements Comparable<IndexItem> {
public String getDate(java.text.DateFormat format) { public String getDate(java.text.DateFormat format) {
return format.format(new Date(timestamp)); 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 static class DownloadEntry {
public long dateModified; public long dateModified;
@ -254,5 +267,4 @@ public class IndexItem extends DownloadItem implements Comparable<IndexItem> {
} }
} }
} }

View file

@ -1,32 +1,47 @@
package net.osmand.plus.download; package net.osmand.plus.download;
import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.osmand.map.WorldRegion; import net.osmand.map.WorldRegion;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import java.io.File; import java.io.File;
import java.text.DateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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, public MultipleDownloadItem(@NonNull WorldRegion region,
@NonNull List<IndexItem> items, @NonNull List<DownloadItem> items,
@NonNull DownloadActivityType type) { @NonNull DownloadActivityType type) {
super(type); super(type);
this.items = items; this.items = items;
} }
public List<IndexItem> getAllIndexes() { 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; return items;
} }
@Override @Override
public boolean isOutdated() { public boolean isOutdated() {
for (IndexItem item : items) { for (DownloadItem item : items) {
if (item.isOutdated()) { if (item.isOutdated()) {
return true; return true;
} }
@ -36,7 +51,7 @@ public class MultipleIndexItem extends DownloadItem {
@Override @Override
public boolean isDownloaded() { public boolean isDownloaded() {
for (IndexItem item : items) { for (DownloadItem item : items) {
if (item.isDownloaded()) { if (item.isDownloaded()) {
return true; return true;
} }
@ -46,8 +61,8 @@ public class MultipleIndexItem extends DownloadItem {
@Override @Override
public boolean isDownloading(@NonNull DownloadIndexesThread thread) { public boolean isDownloading(@NonNull DownloadIndexesThread thread) {
for (IndexItem item : items) { for (DownloadItem item : items) {
if (thread.isDownloading(item)) { if (item.isDownloading(thread)) {
return true; return true;
} }
} }
@ -78,31 +93,31 @@ public class MultipleIndexItem extends DownloadItem {
@Override @Override
public List<File> getDownloadedFiles(@NonNull OsmandApplication app) { public List<File> getDownloadedFiles(@NonNull OsmandApplication app) {
List<File> result = new ArrayList<>(); List<File> result = new ArrayList<>();
for (IndexItem item : items) { for (DownloadItem item : items) {
result.addAll(item.getDownloadedFiles(app)); result.addAll(item.getDownloadedFiles(app));
} }
return result; return result;
} }
public List<IndexItem> getIndexesToDownload() { public List<DownloadItem> getItemsToDownload() {
List<IndexItem> indexesToDownload = new ArrayList<>(); List<DownloadItem> itemsToDownload = new ArrayList<>();
for (IndexItem item : items) { for (DownloadItem item : getAllItems()) {
if (item.hasActualDataToDownload()) { if (item.hasActualDataToDownload()) {
indexesToDownload.add(item); itemsToDownload.add(item);
} }
} }
return indexesToDownload; return itemsToDownload;
} }
@Override @Override
public boolean hasActualDataToDownload() { public boolean hasActualDataToDownload() {
return getIndexesToDownload().size() > 0; return getItemsToDownload().size() > 0;
} }
@Override @Override
public double getSizeToDownloadInMb() { public double getSizeToDownloadInMb() {
double totalSizeMb = 0.0d; double totalSizeMb = 0.0d;
for (IndexItem item : items) { for (DownloadItem item : items) {
if (item.hasActualDataToDownload()) { if (item.hasActualDataToDownload()) {
totalSizeMb += item.getSizeToDownloadInMb(); totalSizeMb += item.getSizeToDownloadInMb();
} }
@ -113,10 +128,30 @@ public class MultipleIndexItem extends DownloadItem {
@Override @Override
public double getArchiveSizeMB() { public double getArchiveSizeMB() {
double result = 0.0d; double result = 0.0d;
for (IndexItem item : items) { for (DownloadItem item : items) {
result += item.getArchiveSizeMB(); result += item.getArchiveSizeMB();
} }
return result; 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 "";
}
} }

View file

@ -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);
}
}

View 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);
}
}

View 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;
}
}

View file

@ -87,7 +87,7 @@ public class ActiveDownloadsDialogFragment extends DialogFragment implements Dow
} }
ItemViewHolder viewHolder = (ItemViewHolder) convertView.getTag(); ItemViewHolder viewHolder = (ItemViewHolder) convertView.getTag();
IndexItem item = getItem(position); IndexItem item = getItem(position);
viewHolder.bindIndexItem(item); viewHolder.bindDownloadItem(item);
return convertView; return convertView;
} }

View file

@ -5,7 +5,6 @@ import android.content.DialogInterface;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.StatFs;
import android.view.Gravity; import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -17,8 +16,6 @@ import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.ibm.icu.impl.IllegalIcuArgumentException;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
@ -28,12 +25,12 @@ import net.osmand.IProgress;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
import net.osmand.plus.OnDismissDialogFragmentListener; import net.osmand.plus.OnDismissDialogFragmentListener;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.base.BottomSheetDialogFragment; import net.osmand.plus.base.BottomSheetDialogFragment;
import net.osmand.plus.dashboard.DashChooseAppDirFragment; import net.osmand.plus.dashboard.DashChooseAppDirFragment;
import net.osmand.plus.download.DownloadActivity; import net.osmand.plus.download.DownloadActivity;
import net.osmand.plus.download.DownloadIndexesThread; import net.osmand.plus.download.DownloadIndexesThread;
import net.osmand.plus.settings.backend.OsmandSettings;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -119,7 +116,7 @@ public class DataStoragePlaceDialogFragment extends BottomSheetDialogFragment {
deviceStorageImageView.setImageDrawable(getContentIcon(R.drawable.ic_action_phone)); deviceStorageImageView.setImageDrawable(getContentIcon(R.drawable.ic_action_phone));
TextView deviceStorageDescription = (TextView) view.findViewById(R.id.deviceMemoryDescription); TextView deviceStorageDescription = (TextView) view.findViewById(R.id.deviceMemoryDescription);
deviceStorageDescription.setText(deviceStorageName); deviceStorageDescription.setText(deviceStorageName);
deviceStorageDescription.setText(getFreeSpace(deviceStorage)); deviceStorageDescription.setText(AndroidUtils.getFreeSpace(activity, deviceStorage));
View sharedMemoryRow = view.findViewById(R.id.sharedMemoryRow); View sharedMemoryRow = view.findViewById(R.id.sharedMemoryRow);
if (hasExternalStoragePermission && sharedStorage != null) { if (hasExternalStoragePermission && sharedStorage != null) {
@ -127,7 +124,7 @@ public class DataStoragePlaceDialogFragment extends BottomSheetDialogFragment {
ImageView sharedMemoryImageView = (ImageView) view.findViewById(R.id.sharedMemoryImageView); ImageView sharedMemoryImageView = (ImageView) view.findViewById(R.id.sharedMemoryImageView);
sharedMemoryImageView.setImageDrawable(getContentIcon(R.drawable.ic_action_phone)); sharedMemoryImageView.setImageDrawable(getContentIcon(R.drawable.ic_action_phone));
TextView sharedMemoryDescription = (TextView) view.findViewById(R.id.sharedMemoryDescription); TextView sharedMemoryDescription = (TextView) view.findViewById(R.id.sharedMemoryDescription);
sharedMemoryDescription.setText(getFreeSpace(sharedStorage)); sharedMemoryDescription.setText(AndroidUtils.getFreeSpace(activity, sharedStorage));
} else { } else {
view.findViewById(R.id.divSharedStorage).setVisibility(View.GONE); view.findViewById(R.id.divSharedStorage).setVisibility(View.GONE);
sharedMemoryRow.setVisibility(View.GONE); sharedMemoryRow.setVisibility(View.GONE);
@ -139,7 +136,7 @@ public class DataStoragePlaceDialogFragment extends BottomSheetDialogFragment {
ImageView memoryStickImageView = (ImageView) view.findViewById(R.id.memoryStickImageView); ImageView memoryStickImageView = (ImageView) view.findViewById(R.id.memoryStickImageView);
memoryStickImageView.setImageDrawable(getContentIcon(R.drawable.ic_sdcard)); memoryStickImageView.setImageDrawable(getContentIcon(R.drawable.ic_sdcard));
TextView memoryStickDescription = (TextView) view.findViewById(R.id.memoryStickDescription); TextView memoryStickDescription = (TextView) view.findViewById(R.id.memoryStickDescription);
memoryStickDescription.setText(getFreeSpace(cardStorage)); memoryStickDescription.setText(AndroidUtils.getFreeSpace(activity, cardStorage));
} else { } else {
view.findViewById(R.id.divExtStorage).setVisibility(View.GONE); view.findViewById(R.id.divExtStorage).setVisibility(View.GONE);
memoryStickRow.setVisibility(View.GONE); memoryStickRow.setVisibility(View.GONE);
@ -192,23 +189,6 @@ public class DataStoragePlaceDialogFragment extends BottomSheetDialogFragment {
.getDefaultInternalStorage(); .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() { private void checkAssets() {
getMyApplication().getResourceManager().checkAssets(IProgress.EMPTY_PROGRESS, true); getMyApplication().getResourceManager().checkAssets(IProgress.EMPTY_PROGRESS, true);
} }

View file

@ -78,7 +78,7 @@ public class DownloadResourceGroupAdapter extends OsmandBaseExpandableListAdapte
} else { } else {
viewHolder.setShowTypeInDesc(true); viewHolder.setShowTypeInDesc(true);
} }
viewHolder.bindIndexItem(item); viewHolder.bindDownloadItem(item);
} else { } else {
DownloadResourceGroup group = (DownloadResourceGroup) child; DownloadResourceGroup group = (DownloadResourceGroup) child;
DownloadGroupViewHolder viewHolder; DownloadGroupViewHolder viewHolder;

View file

@ -41,9 +41,9 @@ import net.osmand.plus.download.DownloadActivityType;
import net.osmand.plus.download.DownloadResourceGroup; import net.osmand.plus.download.DownloadResourceGroup;
import net.osmand.plus.download.DownloadResources; import net.osmand.plus.download.DownloadResources;
import net.osmand.plus.download.IndexItem; import net.osmand.plus.download.IndexItem;
import net.osmand.plus.download.MultipleIndexesUiHelper; import net.osmand.plus.download.SelectIndexesHelper;
import net.osmand.plus.download.MultipleIndexesUiHelper.SelectItemsToDownloadListener; import net.osmand.plus.download.SelectIndexesHelper.ItemsToDownloadSelectedListener;
import net.osmand.plus.download.MultipleIndexItem; import net.osmand.plus.download.MultipleDownloadItem;
import net.osmand.plus.download.ui.LocalIndexesFragment.LocalIndexOperationTask; import net.osmand.plus.download.ui.LocalIndexesFragment.LocalIndexOperationTask;
import net.osmand.plus.helpers.FileNameTranslationHelper; import net.osmand.plus.helpers.FileNameTranslationHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper; import net.osmand.plus.inapp.InAppPurchaseHelper;
@ -146,11 +146,11 @@ public class ItemViewHolder {
depthContoursPurchased = InAppPurchaseHelper.isDepthContoursPurchased(context.getMyApplication()); depthContoursPurchased = InAppPurchaseHelper.isDepthContoursPurchased(context.getMyApplication());
} }
public void bindIndexItem(final DownloadItem downloadItem) { public void bindDownloadItem(final DownloadItem downloadItem) {
bindIndexItem(downloadItem, null); bindDownloadItem(downloadItem, null);
} }
public void bindIndexItem(final DownloadItem downloadItem, final String cityName) { public void bindDownloadItem(final DownloadItem downloadItem, final String cityName) {
initAppStatusVariables(); initAppStatusVariables();
boolean isDownloading = downloadItem.isDownloading(context.getDownloadThread()); boolean isDownloading = downloadItem.isDownloading(context.getDownloadThread());
int progress = -1; int progress = -1;
@ -160,20 +160,20 @@ public class ItemViewHolder {
boolean disabled = checkDisabledAndClickAction(downloadItem); boolean disabled = checkDisabledAndClickAction(downloadItem);
/// name and left item /// name and left item
String name; String name;
if(showTypeInName) { if (showTypeInName) {
name = downloadItem.getType().getString(context); name = downloadItem.getType().getString(context);
} else { } else {
name = downloadItem.getVisibleName(context, context.getMyApplication().getRegions(), showParentRegionName); name = downloadItem.getVisibleName(context, context.getMyApplication().getRegions(), showParentRegionName);
} }
String text = (!Algorithms.isEmpty(cityName) && !cityName.equals(name) ? cityName + "\n" : "") + name; String text = (!Algorithms.isEmpty(cityName) && !cityName.equals(name) ? cityName + "\n" : "") + name;
nameTextView.setText(text); nameTextView.setText(text);
if(!disabled) { if (!disabled) {
nameTextView.setTextColor(textColorPrimary); nameTextView.setTextColor(textColorPrimary);
} else { } else {
nameTextView.setTextColor(textColorSecondary); nameTextView.setTextColor(textColorSecondary);
} }
int color = textColorSecondary; int color = textColorSecondary;
if(downloadItem.isDownloaded() && !isDownloading) { if (downloadItem.isDownloaded() && !isDownloading) {
int colorId = downloadItem.isOutdated() ? R.color.color_distance : R.color.color_ok; int colorId = downloadItem.isOutdated() ? R.color.color_distance : R.color.color_ok;
color = context.getResources().getColor(colorId); color = context.getResources().getColor(colorId);
} }
@ -203,12 +203,12 @@ public class ItemViewHolder {
} else { } else {
descrTextView.setText(downloadItem.getType().getString(context)); descrTextView.setText(downloadItem.getType().getString(context));
} }
} else if (downloadItem instanceof MultipleIndexItem) { } else if (downloadItem instanceof MultipleDownloadItem) {
MultipleIndexItem item = (MultipleIndexItem) downloadItem; MultipleDownloadItem item = (MultipleDownloadItem) downloadItem;
String allRegionsHeader = context.getString(R.string.shared_strings_all_regions); String allRegionsHeader = context.getString(R.string.shared_strings_all_regions);
String regionsHeader = context.getString(R.string.regions); String regionsHeader = context.getString(R.string.regions);
String allRegionsCount = String.valueOf(item.getAllIndexes().size()); String allRegionsCount = String.valueOf(item.getAllItems().size());
String leftToDownloadCount = String.valueOf(item.getIndexesToDownload().size()); String leftToDownloadCount = String.valueOf(item.getItemsToDownload().size());
String header; String header;
String count; String count;
if (item.hasActualDataToDownload()) { if (item.hasActualDataToDownload()) {
@ -226,8 +226,11 @@ public class ItemViewHolder {
header = allRegionsHeader; header = allRegionsHeader;
count = allRegionsCount; count = allRegionsCount;
} }
String fullDescription = String fullDescription = context.getString(R.string.ltr_or_rtl_combine_via_colon, header, count);
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()) { if (item.hasActualDataToDownload()) {
fullDescription = context.getString( fullDescription = context.getString(
R.string.ltr_or_rtl_combine_via_bold_point, fullDescription, R.string.ltr_or_rtl_combine_via_bold_point, fullDescription,
@ -235,11 +238,14 @@ public class ItemViewHolder {
} }
descrTextView.setText(fullDescription); descrTextView.setText(fullDescription);
} else { } else {
IndexItem item = (IndexItem) downloadItem;
String pattern = context.getString(R.string.ltr_or_rtl_combine_via_bold_point); String pattern = context.getString(R.string.ltr_or_rtl_combine_via_bold_point);
String type = item.getType().getString(context); String type = downloadItem.getType().getString(context);
String size = item.getSizeDescription(context); String size = downloadItem.getSizeDescription(context);
String date = item.getDate(dateFormat, showRemoteDate); String addDescr = downloadItem.getAdditionalDescription(context);
if (addDescr != null) {
size += " " + addDescr;
}
String date = downloadItem.getDate(dateFormat, showRemoteDate);
String fullDescription = String.format(pattern, size, date); String fullDescription = String.format(pattern, size, date);
if (showTypeInDesc) { if (showTypeInDesc) {
fullDescription = String.format(pattern, type, fullDescription); fullDescription = String.format(pattern, type, fullDescription);
@ -254,14 +260,14 @@ public class ItemViewHolder {
if (showProgressInDesc) { if (showProgressInDesc) {
double mb = downloadItem.getArchiveSizeMB(); double mb = downloadItem.getArchiveSizeMB();
String v ; String v;
if (progress != -1) { if (progress != -1) {
v = context.getString(R.string.value_downloaded_of_max, mb * progress / 100, mb); v = context.getString(R.string.value_downloaded_of_max, mb * progress / 100, mb);
} else { } else {
v = context.getString(R.string.file_size_in_mb, mb); v = context.getString(R.string.file_size_in_mb, mb);
} }
String fullDescription = v; String fullDescription = v;
if(showTypeInDesc && downloadItem.getType() == DownloadActivityType.ROADS_FILE) { if (showTypeInDesc && downloadItem.getType() == DownloadActivityType.ROADS_FILE) {
fullDescription = context.getString(R.string.ltr_or_rtl_combine_via_bold_point, fullDescription = context.getString(R.string.ltr_or_rtl_combine_via_bold_point,
downloadItem.getType().getString(context), fullDescription); downloadItem.getType().getString(context), fullDescription);
} }
@ -274,9 +280,9 @@ public class ItemViewHolder {
} }
} }
public void bindIndexItem(final CityItem cityItem) { public void bindDownloadItem(final CityItem cityItem) {
if (cityItem.getIndexItem() != null) { if (cityItem.getIndexItem() != null) {
bindIndexItem(cityItem.getIndexItem(), cityItem.getName()); bindDownloadItem(cityItem.getIndexItem(), cityItem.getName());
} else { } else {
nameTextView.setText(cityItem.getName()); nameTextView.setText(cityItem.getName());
nameTextView.setTextColor(textColorPrimary); nameTextView.setTextColor(textColorPrimary);
@ -302,7 +308,7 @@ public class ItemViewHolder {
if (isDownloading) { if (isDownloading) {
rightImageButton.setImageDrawable(getContentIcon(context, R.drawable.ic_action_remove_dark)); rightImageButton.setImageDrawable(getContentIcon(context, R.drawable.ic_action_remove_dark));
rightImageButton.setContentDescription(context.getString(R.string.shared_string_cancel)); rightImageButton.setContentDescription(context.getString(R.string.shared_string_cancel));
} else if(!item.hasActualDataToDownload()) { } else if (!item.hasActualDataToDownload()) {
rightImageButton.setImageDrawable(getContentIcon(context, R.drawable.ic_overflow_menu_white)); rightImageButton.setImageDrawable(getContentIcon(context, R.drawable.ic_overflow_menu_white));
rightImageButton.setContentDescription(context.getString(R.string.shared_string_more)); rightImageButton.setContentDescription(context.getString(R.string.shared_string_more));
} else { } else {
@ -316,9 +322,9 @@ public class ItemViewHolder {
} }
private int getDownloadActionIconId(@NonNull DownloadItem item) { private int getDownloadActionIconId(@NonNull DownloadItem item) {
return item instanceof MultipleIndexItem ? return item instanceof MultipleDownloadItem ?
R.drawable.ic_action_multi_download : R.drawable.ic_action_multi_download :
R.drawable.ic_action_import; R.drawable.ic_action_gsave_dark;
} }
@SuppressLint("DefaultLocale") @SuppressLint("DefaultLocale")
@ -389,13 +395,13 @@ public class ItemViewHolder {
return new View.OnClickListener() { return new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if(isDownloading) { if (isDownloading) {
if(silentCancelDownload) { if (silentCancelDownload) {
context.getDownloadThread().cancelDownload(item); context.getDownloadThread().cancelDownload(item);
} else { } else {
context.makeSureUserCancelDownload(item); context.makeSureUserCancelDownload(item);
} }
} else if(!item.hasActualDataToDownload()){ } else if (!item.hasActualDataToDownload()) {
showContextMenu(v, item, item.getRelatedGroup()); showContextMenu(v, item, item.getRelatedGroup());
} else { } else {
download(item, item.getRelatedGroup()); download(item, item.getRelatedGroup());
@ -406,8 +412,8 @@ public class ItemViewHolder {
} }
protected void showContextMenu(View v, protected void showContextMenu(View v,
final DownloadItem downloadItem, final DownloadItem downloadItem,
final DownloadResourceGroup parentOptional) { final DownloadResourceGroup parentOptional) {
OsmandApplication app = context.getMyApplication(); OsmandApplication app = context.getMyApplication();
PopupMenu optionsMenu = new PopupMenu(context, v); PopupMenu optionsMenu = new PopupMenu(context, v);
MenuItem item; MenuItem item;
@ -455,10 +461,11 @@ public class ItemViewHolder {
} }
} }
} }
if(!handled) { if (!handled) {
startDownload(item); startDownload(item);
} }
} }
private void confirmDownload(final DownloadItem item) { private void confirmDownload(final DownloadItem item) {
AlertDialog.Builder builder = new AlertDialog.Builder(context); AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.are_you_sure); builder.setTitle(R.string.are_you_sure);
@ -476,18 +483,17 @@ public class ItemViewHolder {
} }
private void startDownload(DownloadItem item) { private void startDownload(DownloadItem item) {
if (item instanceof MultipleIndexItem) { if (item instanceof IndexItem) {
selectIndexesToDownload((MultipleIndexItem) item);
} else if (item instanceof IndexItem) {
IndexItem indexItem = (IndexItem) item; IndexItem indexItem = (IndexItem) item;
context.startDownload(indexItem); context.startDownload(indexItem);
} else {
selectIndexesToDownload(item);
} }
} }
private void selectIndexesToDownload(MultipleIndexItem item) { private void selectIndexesToDownload(DownloadItem item) {
OsmandApplication app = context.getMyApplication(); SelectIndexesHelper.showDialog(item, context, dateFormat, showRemoteDate,
MultipleIndexesUiHelper.showDialog(item, context, app, dateFormat, showRemoteDate, new ItemsToDownloadSelectedListener() {
new SelectItemsToDownloadListener() {
@Override @Override
public void onItemsToDownloadSelected(List<IndexItem> indexes) { public void onItemsToDownloadSelected(List<IndexItem> indexes) {
IndexItem[] indexesArray = new IndexItem[indexes.size()]; IndexItem[] indexesArray = new IndexItem[indexes.size()];
@ -498,7 +504,7 @@ public class ItemViewHolder {
} }
private void confirmRemove(@NonNull final DownloadItem downloadItem, private void confirmRemove(@NonNull final DownloadItem downloadItem,
@NonNull final List<File> downloadedFiles) { @NonNull final List<File> downloadedFiles) {
OsmandApplication app = context.getMyApplication(); OsmandApplication app = context.getMyApplication();
AlertDialog.Builder confirm = new AlertDialog.Builder(context); AlertDialog.Builder confirm = new AlertDialog.Builder(context);
@ -526,7 +532,7 @@ public class ItemViewHolder {
} }
private void remove(@NonNull LocalIndexType type, private void remove(@NonNull LocalIndexType type,
@NonNull List<File> filesToDelete) { @NonNull List<File> filesToDelete) {
OsmandApplication app = context.getMyApplication(); OsmandApplication app = context.getMyApplication();
LocalIndexOperationTask removeTask = new LocalIndexOperationTask( LocalIndexOperationTask removeTask = new LocalIndexOperationTask(
context, context,

View file

@ -55,6 +55,7 @@ import net.osmand.plus.dialogs.DirectionsDialogs;
import net.osmand.plus.download.DownloadActivity; import net.osmand.plus.download.DownloadActivity;
import net.osmand.plus.download.DownloadIndexesThread.DownloadEvents; import net.osmand.plus.download.DownloadIndexesThread.DownloadEvents;
import net.osmand.plus.download.IndexItem; import net.osmand.plus.download.IndexItem;
import net.osmand.plus.download.SrtmDownloadItem;
import net.osmand.plus.helpers.FileNameTranslationHelper; import net.osmand.plus.helpers.FileNameTranslationHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper; import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.mapsource.EditMapSourceDialogFragment.OnMapSourceUpdateListener; import net.osmand.plus.mapsource.EditMapSourceDialogFragment.OnMapSourceUpdateListener;
@ -74,6 +75,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
public class LocalIndexesFragment extends OsmandExpandableListFragment implements DownloadEvents, public class LocalIndexesFragment extends OsmandExpandableListFragment implements DownloadEvents,
OnMapSourceUpdateListener, RenameCallback { OnMapSourceUpdateListener, RenameCallback {
private LoadLocalIndexTask asyncLoader; private LoadLocalIndexTask asyncLoader;
@ -351,10 +353,10 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
getMyApplication().getResourceManager().closeFile(info.getFileName()); getMyApplication().getResourceManager().closeFile(info.getFileName());
File tShm = new File(f.getParentFile(), f.getName() + "-shm"); File tShm = new File(f.getParentFile(), f.getName() + "-shm");
File tWal = new File(f.getParentFile(), f.getName() + "-wal"); File tWal = new File(f.getParentFile(), f.getName() + "-wal");
if(tShm.exists()) { if (tShm.exists()) {
Algorithms.removeAllFiles(tShm); Algorithms.removeAllFiles(tShm);
} }
if(tWal.exists()) { if (tWal.exists()) {
Algorithms.removeAllFiles(tWal); Algorithms.removeAllFiles(tWal);
} }
} }
@ -370,8 +372,8 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
getMyApplication().getResourceManager().closeFile(info.getFileName()); getMyApplication().getResourceManager().closeFile(info.getFileName());
} }
} else if (operation == CLEAR_TILES_OPERATION) { } else if (operation == CLEAR_TILES_OPERATION) {
ITileSource src = (ITileSource) info.getAttachedObject(); ITileSource src = (ITileSource) info.getAttachedObject();
if(src != null) { if (src != null) {
src.deleteTiles(info.getPathToData()); src.deleteTiles(info.getPathToData());
} }
} }
@ -419,10 +421,10 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
@Override @Override
protected void onPostExecute(String result) { protected void onPostExecute(String result) {
a.setProgressBarIndeterminateVisibility(false); a.setProgressBarIndeterminateVisibility(false);
if(result != null && result.length() > 0) { if (result != null && result.length() > 0) {
Toast.makeText(a, result, Toast.LENGTH_LONG).show(); Toast.makeText(a, result, Toast.LENGTH_LONG).show();
} }
if (operation == RESTORE_OPERATION || operation == BACKUP_OPERATION || operation == CLEAR_TILES_OPERATION) { if (operation == RESTORE_OPERATION || operation == BACKUP_OPERATION || operation == CLEAR_TILES_OPERATION) {
a.reloadLocalIndexes(); a.reloadLocalIndexes();
} else { } else {
@ -507,7 +509,7 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
ItemClickListener listener = new ContextMenuAdapter.ItemClickListener() { ItemClickListener listener = new ContextMenuAdapter.ItemClickListener() {
@Override @Override
public boolean onContextMenuClick(ArrayAdapter<ContextMenuItem> adapter, public boolean onContextMenuClick(ArrayAdapter<ContextMenuItem> adapter,
int itemId, int pos, boolean isChecked, int[] viewCoordinates) { int itemId, int pos, boolean isChecked, int[] viewCoordinates) {
localOptionsMenu(itemId); localOptionsMenu(itemId);
return true; return true;
} }
@ -608,7 +610,7 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
} }
private void openSelectionMode(final int actionResId, final int actionIconId, private void openSelectionMode(final int actionResId, final int actionIconId,
final DialogInterface.OnClickListener listener) { final DialogInterface.OnClickListener listener) {
final int colorResId = getMyApplication().getSettings().isLightContent() ? R.color.active_buttons_and_links_text_light : R.color.active_buttons_and_links_text_dark; final int colorResId = getMyApplication().getSettings().isLightContent() ? R.color.active_buttons_and_links_text_light : R.color.active_buttons_and_links_text_dark;
String value = getString(actionResId); String value = getString(actionResId);
if (value.endsWith("...")) { if (value.endsWith("...")) {
@ -709,7 +711,7 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
} }
public void openSelectionMode(int stringRes, int darkIcon, DialogInterface.OnClickListener listener, public void openSelectionMode(int stringRes, int darkIcon, DialogInterface.OnClickListener listener,
EnumSet<LocalIndexType> filter) { EnumSet<LocalIndexType> filter) {
if (filter != null) { if (filter != null) {
listAdapter.filterCategories(filter); listAdapter.filterCategories(filter);
} }
@ -860,7 +862,7 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
@Override @Override
public View getChildView(final int groupPosition, final int childPosition, public View getChildView(final int groupPosition, final int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) { boolean isLastChild, View convertView, ViewGroup parent) {
LocalIndexInfoViewHolder viewHolder; LocalIndexInfoViewHolder viewHolder;
if (convertView == null) { if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(ctx); LayoutInflater inflater = LayoutInflater.from(ctx);
@ -878,8 +880,8 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
private String getNameToDisplay(LocalIndexInfo child) { private String getNameToDisplay(LocalIndexInfo child) {
return child.getType() == LocalIndexType.VOICE_DATA ? FileNameTranslationHelper.getVoiceName(ctx, child.getFileName()) : return child.getType() == LocalIndexType.VOICE_DATA ? FileNameTranslationHelper.getVoiceName(ctx, child.getFileName()) :
FileNameTranslationHelper.getFileName(ctx, FileNameTranslationHelper.getFileName(ctx,
ctx.getMyApplication().getResourceManager().getOsmandRegions(), ctx.getMyApplication().getResourceManager().getOsmandRegions(),
child.getFileName()); child.getFileName());
} }
@Override @Override
@ -963,7 +965,7 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
return ctx.getString(R.string.download_roads_only_item); return ctx.getString(R.string.download_roads_only_item);
} else if (child.isBackupedData() && child.getFileName().endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) { } else if (child.isBackupedData() && child.getFileName().endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) {
return ctx.getString(R.string.download_wikipedia_maps); 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 ctx.getString(R.string.download_srtm_maps);
} }
return ""; return "";
@ -1029,6 +1031,10 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
builder.append(AndroidUtils.formatSize(ctx, child.getSize() * 1024l)); 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 (!Algorithms.isEmpty(child.getDescription())) {
if (builder.length() > 0) { if (builder.length() > 0) {
builder.append(""); builder.append("");
@ -1150,5 +1156,4 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
private DownloadActivity getDownloadActivity() { private DownloadActivity getDownloadActivity() {
return (DownloadActivity) getActivity(); return (DownloadActivity) getActivity();
} }
} }

View file

@ -382,10 +382,10 @@ public class SearchDialogFragment extends DialogFragment implements DownloadEven
if (obj instanceof IndexItem) { if (obj instanceof IndexItem) {
IndexItem item = (IndexItem) obj; IndexItem item = (IndexItem) obj;
viewHolder.setShowTypeInDesc(true); viewHolder.setShowTypeInDesc(true);
viewHolder.bindIndexItem(item); viewHolder.bindDownloadItem(item);
} else { } else {
CityItem item = (CityItem) obj; CityItem item = (CityItem) obj;
viewHolder.bindIndexItem(item); viewHolder.bindDownloadItem(item);
if (item.getIndexItem() == null) { if (item.getIndexItem() == null) {
new IndexItemResolverTask(viewHolder, item).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); new IndexItemResolverTask(viewHolder, item).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
@ -461,7 +461,7 @@ public class SearchDialogFragment extends DialogFragment implements DownloadEven
if (viewHolder != null) { if (viewHolder != null) {
if (indexItem != null) { if (indexItem != null) {
cityItem.setIndexItem(indexItem); cityItem.setIndexItem(indexItem);
viewHolder.bindIndexItem(indexItem, cityItem.getName()); viewHolder.bindDownloadItem(indexItem, cityItem.getName());
} }
} }
} }

View file

@ -410,7 +410,7 @@ public class UpdatesIndexFragment extends OsmAndListFragment implements Download
holder.setShowRemoteDate(true); holder.setShowRemoteDate(true);
holder.setShowTypeInDesc(true); holder.setShowTypeInDesc(true);
holder.setShowParentRegionName(true); holder.setShowParentRegionName(true);
holder.bindIndexItem(getItem(position)); holder.bindDownloadItem(getItem(position));
} }
return view; return view;
} }

View file

@ -5,7 +5,6 @@ import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.os.StatFs;
import android.provider.Settings.Secure; import android.provider.Settings.Secure;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -37,7 +36,6 @@ import net.osmand.plus.AppInitializer.AppInitializeListener;
import net.osmand.plus.OsmAndLocationProvider; import net.osmand.plus.OsmAndLocationProvider;
import net.osmand.plus.OsmAndLocationProvider.OsmAndLocationListener; import net.osmand.plus.OsmAndLocationProvider.OsmAndLocationListener;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.Version; import net.osmand.plus.Version;
import net.osmand.plus.activities.MapActivity; 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.download.ui.DataStoragePlaceDialogFragment;
import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.resources.ResourceManager; import net.osmand.plus.resources.ResourceManager;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils; import net.osmand.util.MapUtils;
import org.json.JSONObject; import org.json.JSONObject;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -331,7 +329,7 @@ public class FirstUsageWizardFragment extends BaseOsmAndFragment implements OsmA
FragmentActivity activity = getActivity(); FragmentActivity activity = getActivity();
if (!OsmAndLocationProvider.isLocationPermissionAvailable(activity)) { if (!OsmAndLocationProvider.isLocationPermissionAvailable(activity)) {
ActivityCompat.requestPermissions(activity, ActivityCompat.requestPermissions(activity,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, new String[] {Manifest.permission.ACCESS_FINE_LOCATION},
FIRST_USAGE_LOCATION_PERMISSION); FIRST_USAGE_LOCATION_PERMISSION);
} else { } else {
app.getLocationProvider().addLocationListener(this); app.getLocationProvider().addLocationListener(this);
@ -387,13 +385,13 @@ public class FirstUsageWizardFragment extends BaseOsmAndFragment implements OsmA
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
((MapActivity)getActivity()).disableDrawer(); ((MapActivity) getActivity()).disableDrawer();
} }
@Override @Override
public void onPause() { public void onPause() {
super.onPause(); super.onPause();
((MapActivity)getActivity()).enableDrawer(); ((MapActivity) getActivity()).enableDrawer();
} }
@Override @Override
@ -697,7 +695,7 @@ public class FirstUsageWizardFragment extends BaseOsmAndFragment implements OsmA
TextView freeSpaceValue = (TextView) storageView.findViewById(R.id.storage_free_space_value); TextView freeSpaceValue = (TextView) storageView.findViewById(R.id.storage_free_space_value);
String freeSpaceStr = getString(R.string.storage_free_space) + ": "; String freeSpaceStr = getString(R.string.storage_free_space) + ": ";
freeSpace.setText(freeSpaceStr); 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); AppCompatButton changeStorageButton = (AppCompatButton) storageView.findViewById(R.id.storage_change_button);
if (wizardType == WizardType.MAP_DOWNLOAD) { if (wizardType == WizardType.MAP_DOWNLOAD) {
@ -709,7 +707,7 @@ public class FirstUsageWizardFragment extends BaseOsmAndFragment implements OsmA
public void onClick(View v) { public void onClick(View v) {
if (!DownloadActivity.hasPermissionToWriteExternalStorage(getContext())) { if (!DownloadActivity.hasPermissionToWriteExternalStorage(getContext())) {
ActivityCompat.requestPermissions(getActivity(), ActivityCompat.requestPermissions(getActivity(),
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
FIRST_USAGE_REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION); FIRST_USAGE_REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION);
} else { } else {
@ -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) { public static void showSearchLocationFragment(FragmentActivity activity, boolean searchByIp) {
Fragment fragment = new FirstUsageWizardFragment(); Fragment fragment = new FirstUsageWizardFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();

View file

@ -1,9 +1,11 @@
package net.osmand.plus.helpers; package net.osmand.plus.helpers;
import android.content.Context; import android.content.Context;
import net.osmand.IndexConstants; import net.osmand.IndexConstants;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
import net.osmand.map.OsmandRegions; import net.osmand.map.OsmandRegions;
import net.osmand.map.WorldRegion;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.download.DownloadResources; import net.osmand.plus.download.DownloadResources;
@ -19,6 +21,7 @@ import java.lang.reflect.Field;
public class FileNameTranslationHelper { public class FileNameTranslationHelper {
private static final Log LOG = PlatformUtil.getLog(FileNameTranslationHelper.class); private static final Log LOG = PlatformUtil.getLog(FileNameTranslationHelper.class);
public static final String WIKI_NAME = "_wiki"; 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 HILL_SHADE = "Hillshade";
public static final String SLOPE = "Slope"; public static final String SLOPE = "Slope";
public static final String SEA_DEPTH = "Depth_"; public static final String SEA_DEPTH = "Depth_";
@ -31,6 +34,8 @@ public class FileNameTranslationHelper {
String basename = getBasename(fileName); String basename = getBasename(fileName);
if (basename.endsWith(WIKI_NAME)) { //wiki files if (basename.endsWith(WIKI_NAME)) { //wiki files
return getWikiName(ctx, basename); return getWikiName(ctx, basename);
} else if (basename.endsWith(WIKIVOYAGE_NAME)) {
return getWikivoyageName(ctx, basename);
} else if (fileName.endsWith("tts")) { //tts files } else if (fileName.endsWith("tts")) { //tts files
return getVoiceName(ctx, fileName); return getVoiceName(ctx, fileName);
} else if (fileName.endsWith(IndexConstants.FONT_INDEX_EXT)) { //otf files } else if (fileName.endsWith(IndexConstants.FONT_INDEX_EXT)) { //otf files
@ -75,10 +80,10 @@ public class FileNameTranslationHelper {
return ctx.getString(R.string.ltr_or_rtl_combine_via_space, locName, "(" + terrain + ")"); return ctx.getString(R.string.ltr_or_rtl_combine_via_space, locName, "(" + terrain + ")");
} }
public static String getWikiName(Context ctx, String basename){ public static String getWikiName(Context ctx, String basename) {
String cutted = basename.substring(0, basename.indexOf("_wiki")); String cutted = basename.substring(0, basename.indexOf("_wiki"));
String wikiName = getStandardLangName(ctx, cutted); String wikiName = getStandardLangName(ctx, cutted);
if (wikiName == null){ if (wikiName == null) {
wikiName = cutted; wikiName = cutted;
} }
String wikiWord = ctx.getString(R.string.amenity_type_osmwiki); String wikiWord = ctx.getString(R.string.amenity_type_osmwiki);
@ -87,7 +92,18 @@ public class FileNameTranslationHelper {
//removing word in "()" from recourse file //removing word in "()" from recourse file
return wikiName + " " + wikiWord.substring(0, index).trim(); return wikiName + " " + wikiWord.substring(0, index).trim();
} }
return wikiName + " " + ctx.getString(R.string.amenity_type_osmwiki); 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) { public static String getVoiceName(Context ctx, String fileName) {
@ -196,8 +212,8 @@ public class FileNameTranslationHelper {
return ctx.getString(R.string.lang_pl); return ctx.getString(R.string.lang_pl);
} else if (filename.equalsIgnoreCase("Portuguese")) { } else if (filename.equalsIgnoreCase("Portuguese")) {
return ctx.getString(R.string.lang_pt); return ctx.getString(R.string.lang_pt);
//} else if (filename.equalsIgnoreCase("Portuguese")) { //} else if (filename.equalsIgnoreCase("Portuguese")) {
// return ctx.getString(R.string.lang_pt_br); // return ctx.getString(R.string.lang_pt_br);
} else if (filename.equalsIgnoreCase("Romanian")) { } else if (filename.equalsIgnoreCase("Romanian")) {
return ctx.getString(R.string.lang_ro); return ctx.getString(R.string.lang_ro);
} else if (filename.equalsIgnoreCase("Russian")) { } else if (filename.equalsIgnoreCase("Russian")) {
@ -227,11 +243,11 @@ public class FileNameTranslationHelper {
return ctx.getString(R.string.index_item_world_altitude_correction); return ctx.getString(R.string.index_item_world_altitude_correction);
} else if (basename.equals("world_basemap")) { } else if (basename.equals("world_basemap")) {
return ctx.getString(R.string.index_item_world_basemap); return ctx.getString(R.string.index_item_world_basemap);
} else if (basename.equals("world_basemap_detailed")){ } else if (basename.equals("world_basemap_detailed")) {
return ctx.getString(R.string.index_item_world_basemap_detailed); return ctx.getString(R.string.index_item_world_basemap_detailed);
} else if (basename.equals("world_bitcoin_payments")) { } else if (basename.equals("world_bitcoin_payments")) {
return ctx.getString(R.string.index_item_world_bitcoin_payments); return ctx.getString(R.string.index_item_world_bitcoin_payments);
} else if (basename.equals(DownloadResources.WORLD_SEAMARKS_KEY) || } else if (basename.equals(DownloadResources.WORLD_SEAMARKS_KEY) ||
basename.equals(DownloadResources.WORLD_SEAMARKS_OLD_KEY)) { basename.equals(DownloadResources.WORLD_SEAMARKS_OLD_KEY)) {
return ctx.getString(R.string.index_item_world_seamarks); return ctx.getString(R.string.index_item_world_seamarks);
} else if (basename.equals("world_wikivoyage")) { } else if (basename.equals("world_wikivoyage")) {
@ -245,4 +261,27 @@ public class FileNameTranslationHelper {
} }
return null; 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;
}
} }

View file

@ -79,6 +79,7 @@ import net.osmand.plus.ContextMenuItem;
import net.osmand.plus.GPXDatabase.GpxDataItem; import net.osmand.plus.GPXDatabase.GpxDataItem;
import net.osmand.plus.GpxDbHelper; import net.osmand.plus.GpxDbHelper;
import net.osmand.plus.GpxDbHelper.GpxDataItemCallback; import net.osmand.plus.GpxDbHelper.GpxDataItemCallback;
import net.osmand.plus.GpxSelectionHelper;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayGroup; import net.osmand.plus.GpxSelectionHelper.GpxDisplayGroup;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem; import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile; import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
@ -2228,17 +2229,18 @@ public class GpxUiHelper {
return dataSet; return dataSet;
} }
public static GpxDisplayItem makeGpxDisplayItem(OsmandApplication app, GPXUtilities.GPXFile gpx) { public static GpxDisplayItem makeGpxDisplayItem(OsmandApplication app, GPXFile gpxFile) {
GpxDisplayItem gpxItem = null; GpxSelectionHelper helper = app.getSelectedGpxHelper();
String groupName = app.getString(R.string.current_route); String groupName = helper.getGroupName(gpxFile);
GpxDisplayGroup group = app.getSelectedGpxHelper().buildGpxDisplayGroup(gpx, 0, groupName); GpxDisplayGroup group = helper.buildGpxDisplayGroup(gpxFile, 0, groupName);
if (group != null && group.getModifiableList().size() > 0) { if (group != null && group.getModifiableList().size() > 0) {
gpxItem = group.getModifiableList().get(0); GpxDisplayItem gpxItem = group.getModifiableList().get(0);
if (gpxItem != null) { if (gpxItem != null) {
gpxItem.route = true; gpxItem.route = true;
} }
return gpxItem;
} }
return gpxItem; return null;
} }
public static void saveAndShareGpx(@NonNull final Context context, @NonNull final GPXFile gpxFile) { public static void saveAndShareGpx(@NonNull final Context context, @NonNull final GPXFile gpxFile) {

View file

@ -8,6 +8,7 @@ import androidx.fragment.app.FragmentActivity;
import net.osmand.GPXUtilities.GPXFile; import net.osmand.GPXUtilities.GPXFile;
import net.osmand.data.FavouritePoint; import net.osmand.data.FavouritePoint;
import net.osmand.plus.FavouritesDbHelper; import net.osmand.plus.FavouritesDbHelper;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.base.BaseLoadAsyncTask; 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.FAV_TAB;
import static net.osmand.plus.myplaces.FavoritesActivity.TAB_ID; 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 GPXFile gpxFile;
private String fileName; private String fileName;
@ -33,6 +34,12 @@ class FavoritesImportTask extends BaseLoadAsyncTask<Void, Void, GPXFile> {
@Override @Override
protected GPXFile doInBackground(Void... nothing) { 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); List<FavouritePoint> favourites = asFavourites(app, gpxFile.getPoints(), fileName, forceImportFavourites);
FavouritesDbHelper favoritesHelper = app.getFavorites(); FavouritesDbHelper favoritesHelper = app.getFavorites();
checkDuplicateNames(favourites); checkDuplicateNames(favourites);
@ -42,10 +49,9 @@ class FavoritesImportTask extends BaseLoadAsyncTask<Void, Void, GPXFile> {
} }
favoritesHelper.sortAll(); favoritesHelper.sortAll();
favoritesHelper.saveCurrentPointsIntoFile(); favoritesHelper.saveCurrentPointsIntoFile();
return null;
} }
public void checkDuplicateNames(List<FavouritePoint> favourites) { public static void checkDuplicateNames(List<FavouritePoint> favourites) {
for (FavouritePoint fp : favourites) { for (FavouritePoint fp : favourites) {
int number = 1; int number = 1;
String index; String index;

View file

@ -10,7 +10,7 @@ import android.util.Log;
import net.osmand.AndroidNetworkUtils; import net.osmand.AndroidNetworkUtils;
import net.osmand.AndroidNetworkUtils.OnRequestResultListener; import net.osmand.AndroidNetworkUtils.OnRequestResultListener;
import net.osmand.AndroidNetworkUtils.OnRequestsResultListener; import net.osmand.AndroidNetworkUtils.OnSendRequestsListener;
import net.osmand.AndroidNetworkUtils.RequestResponse; import net.osmand.AndroidNetworkUtils.RequestResponse;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
@ -608,9 +608,14 @@ public abstract class InAppPurchaseHelper {
addUserInfo(parameters); addUserInfo(parameters);
requests.add(new AndroidNetworkUtils.Request(url, parameters, userOperation, true, true)); requests.add(new AndroidNetworkUtils.Request(url, parameters, userOperation, true, true));
} }
AndroidNetworkUtils.sendRequestsAsync(ctx, requests, new OnRequestsResultListener() { AndroidNetworkUtils.sendRequestsAsync(ctx, requests, new OnSendRequestsListener() {
@Override @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) { for (RequestResponse rr : results) {
String sku = rr.getRequest().getParameters().get("sku"); String sku = rr.getRequest().getParameters().get("sku");
PurchaseInfo info = getPurchaseInfo(sku); PurchaseInfo info = getPurchaseInfo(sku);

View file

@ -282,6 +282,9 @@ public class LiveUpdatesFragment extends BaseOsmAndDialogFragment implements OnL
dismiss(); dismiss();
} }
}); });
if (closeButton instanceof ImageView) {
UiUtilities.rotateImageByLayoutDirection((ImageView) closeButton);
}
FrameLayout iconHelpContainer = toolbar.findViewById(R.id.action_button); 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; 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