Merge branch 'r3.9' into finish_wikivoyage_#475

# Conflicts:
#	OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java
This commit is contained in:
Dima-1 2021-02-18 22:12:14 +02:00
commit 5483c17960
129 changed files with 3949 additions and 869 deletions

View file

@ -11,6 +11,7 @@ public interface OsmAndCustomizationConstants {
String DRAWER_MY_PLACES_ID = DRAWER_ITEM_ID_SCHEME + "my_places";
String DRAWER_SEARCH_ID = DRAWER_ITEM_ID_SCHEME + "search";
String DRAWER_DIRECTIONS_ID = DRAWER_ITEM_ID_SCHEME + "directions";
String DRAWER_TRIP_RECORDING_ID = DRAWER_ITEM_ID_SCHEME + "trip_recording";
String DRAWER_CONFIGURE_MAP_ID = DRAWER_ITEM_ID_SCHEME + "configure_map";
String DRAWER_DOWNLOAD_MAPS_ID = DRAWER_ITEM_ID_SCHEME + "download_maps";
String DRAWER_OSMAND_LIVE_ID = DRAWER_ITEM_ID_SCHEME + "osmand_live";

View file

@ -436,6 +436,7 @@ public class OsmandRegions {
cx /= object.getPointsLength();
cy /= object.getPointsLength();
rd.regionCenter = new LatLon(MapUtils.get31LatitudeY((int) cy), MapUtils.get31LongitudeX((int) cx));
rd.boundingBox = findBoundingBox(object);
}
rd.regionParentFullName = mapIndexFields.get(mapIndexFields.parentFullName, object);
@ -461,6 +462,43 @@ public class OsmandRegions {
return rd;
}
private QuadRect findBoundingBox(BinaryMapDataObject object) {
if (object.getPointsLength() == 0) {
return new QuadRect(0, 0, 0, 0);
}
double currentX = object.getPoint31XTile(0);
double currentY = object.getPoint31YTile(0);
double minX = currentX;
double maxX = currentX;
double minY = currentY;
double maxY = currentY;
if (object.getPointsLength() > 1) {
for (int i = 1; i < object.getPointsLength(); i++) {
currentX = object.getPoint31XTile(i);
currentY = object.getPoint31YTile(i);
if (currentX > maxX) {
maxX = currentX;
} else if (currentX < minX) {
minX = currentX;
}
if (currentY > maxY) {
maxY = currentY;
} else if (currentY < minY) {
minY = currentY;
}
}
}
minX = MapUtils.get31LongitudeX((int) minX);
maxX = MapUtils.get31LongitudeX((int) maxX);
double revertedMinY = MapUtils.get31LatitudeY((int) maxY);
double revertedMaxY = MapUtils.get31LatitudeY((int) minY);
return new QuadRect(minX, revertedMinY, maxX, revertedMaxY);
}
private String getSearchIndex(BinaryMapDataObject object) {
MapIndex mi = object.getMapIndex();
TIntObjectIterator<String> it = object.getObjectNames().iterator();

View file

@ -1,6 +1,7 @@
package net.osmand.map;
import net.osmand.data.LatLon;
import net.osmand.data.QuadRect;
import net.osmand.util.Algorithms;
import java.io.Serializable;
@ -40,6 +41,7 @@ public class WorldRegion implements Serializable {
protected String regionDownloadName;
protected boolean regionMapDownload;
protected LatLon regionCenter;
protected QuadRect boundingBox;
public static class RegionParams {
protected String regionLeftHandDriving;
@ -182,4 +184,20 @@ public class WorldRegion implements Serializable {
}
return res;
}
public boolean containsRegion(WorldRegion region) {
if (this.boundingBox != null && region.boundingBox != null) {
return this.boundingBox.contains(region.boundingBox);
}
return false;
}
public boolean isContinent() {
if (superregion != null) {
String superRegionId = superregion.getRegionId();
String thisRegionId = getRegionId();
return WORLD.equals(superRegionId) && !RUSSIA_REGION_ID.equals(thisRegionId);
}
return false;
}
}

View file

@ -127,6 +127,17 @@ public class Algorithms {
return def;
}
public static double parseDoubleSilently(String input, double def) {
if (input != null && input.length() > 0) {
try {
return Double.parseDouble(input);
} catch (NumberFormatException e) {
return def;
}
}
return def;
}
public static String getFileNameWithoutExtension(File f) {
return getFileNameWithoutExtension(f.getName());
}

View file

@ -36,9 +36,9 @@ android {
defaultConfig {
minSdkVersion System.getenv("MIN_SDK_VERSION") ? System.getenv("MIN_SDK_VERSION").toInteger() : 15
versionCode 400
versionCode 390
versionCode System.getenv("APK_NUMBER_VERSION") ? System.getenv("APK_NUMBER_VERSION").toInteger() : versionCode
versionName "4.0.0"
versionName "3.9.0"
versionName System.getenv("APK_VERSION")? System.getenv("APK_VERSION").toString(): versionName
versionName System.getenv("APK_VERSION_SUFFIX")? versionName + System.getenv("APK_VERSION_SUFFIX").toString(): versionName
}
@ -85,6 +85,7 @@ android {
}
amazonFree {
java.srcDirs = ["src-nogms", "src-google"]
manifest.srcFile "AndroidManifest-gplayFree.xml"
}
amazonFull {
java.srcDirs = ["src-nogms", "src-google"]

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/active_buttons_and_links_bg_pressed_dark" />
<corners android:radius="3dp" />
</shape>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/inactive_buttons_and_links_bg_dark" />
<corners android:radius="3dp" />
</shape>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/inactive_buttons_and_links_bg_light" />
<corners android:radius="3dp" />
</shape>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke android:width="1dp" android:color="@color/active_buttons_and_links_bg_pressed_dark" />
<corners android:radius="3dp" />
</shape>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke android:width="1dp" android:color="@color/active_buttons_and_links_bg_pressed_light" />
<corners android:radius="3dp" />
</shape>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke android:width="1dp" android:color="@color/inactive_buttons_and_links_bg_dark" />
<corners android:radius="3dp" />
</shape>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke android:width="1dp" android:color="@color/inactive_buttons_and_links_bg_light" />
<corners android:radius="3dp" />
</shape>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/active_buttons_and_links_bg_pressed_light" />
<corners android:radius="3dp" />
</shape>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="@color/active_buttons_and_links_bg_pressed_dark" />
<corners android:radius="@dimen/dlg_button_rect_rad" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="@null" />
<corners android:radius="@dimen/dlg_button_rect_rad" />
</shape>
</item>
</selector>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="@color/active_buttons_and_links_bg_pressed_light" />
<corners android:radius="@dimen/dlg_button_rect_rad" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="@null" />
<corners android:radius="@dimen/dlg_button_rect_rad" />
</shape>
</item>
</selector>

View file

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/button_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true"
android:gravity="center_vertical"
android:minHeight="@dimen/bottom_sheet_list_item_height"
android:orientation="horizontal"
android:paddingStart="@dimen/content_padding_small"
android:paddingLeft="@dimen/content_padding_small"
android:paddingTop="@dimen/text_margin_small"
android:paddingEnd="@dimen/content_padding_small"
android:paddingRight="@dimen/content_padding_small"
android:paddingBottom="@dimen/text_margin_small"
tools:background="@drawable/btn_background_inactive_dark"
tools:ignore="UselessParent">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:duplicateParentState="true"
android:orientation="vertical">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/button_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:duplicateParentState="true"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="Title"
tools:textColor="@color/active_color_primary_dark" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:duplicateParentState="true"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:textSize="@dimen/default_desc_text_size"
android:visibility="gone"
osmand:typeface="@string/font_roboto_medium"
tools:text="Description"
tools:textColor="@color/text_color_secondary_dark"
tools:visibility="visible" />
</LinearLayout>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon"
android:layout_width="@dimen/map_widget_icon"
android:layout_height="@dimen/map_widget_icon"
android:layout_marginStart="@dimen/context_menu_padding_margin_large"
android:layout_marginLeft="@dimen/context_menu_padding_margin_large"
android:duplicateParentState="true"
tools:srcCompat="@drawable/ic_action_appearance"
tools:tint="@color/icon_color_active_dark" />
</LinearLayout>
</FrameLayout>

View file

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/measurement_tool_menu_title_padding_top"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/measurement_tool_button_padding_top">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/widget_turn_lane_margin"
android:ellipsize="end"
android:gravity="center_vertical"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:lineSpacingExtra="@dimen/titleLineSpacingExtra"
android:maxLines="1"
android:text="@string/select_segments"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_medium" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/list_header_settings_top_margin"
android:letterSpacing="@dimen/description_letter_spacing"
android:lineSpacingMultiplier="@dimen/bottom_sheet_text_spacing_multiplier"
android:lineSpacingExtra="@dimen/descriptionLineSpacingExtra"
android:text="@string/select_segments_description"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_regular" />
</LinearLayout>
<include
android:id="@+id/gpx_track_container"
layout="@layout/gpx_track_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dashPluginMargin" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dashboard_divider" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/gpx_segment_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
tools:itemCount="1"
tools:listitem="@layout/gpx_segment_list_item">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>

View file

@ -21,11 +21,13 @@
android:layout_marginLeft="@dimen/card_padding"
android:padding="@dimen/context_menu_padding_margin_small"
android:paddingStart="@dimen/context_menu_padding_margin_small"
android:paddingEnd="@dimen/context_menu_padding_margin_small">
android:paddingEnd="@dimen/context_menu_padding_margin_small"
android:background="@null">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="@dimen/favorites_icon_size_small"
android:layout_height="@dimen/favorites_icon_size_small"
android:background="?attr/selectableItemBackgroundBorderless"
android:tint="?attr/default_icon_color"
osmand:srcCompat="@drawable/ic_action_close" />
</FrameLayout>
@ -43,18 +45,20 @@
osmand:typeface="@string/font_roboto_medium" />
<FrameLayout
android:id="@+id/btn_save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/content_padding_half"
android:layout_marginEnd="@dimen/content_padding_half"
android:layout_gravity="center_vertical"
android:background="@drawable/btn_border_active">
android:layout_gravity="center_vertical">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/btn_save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:layout_gravity="start"
android:gravity="center_vertical"
android:duplicateParentState="true"
android:background="@drawable/btn_border_active"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding_half"
@ -77,18 +81,18 @@
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<net.osmand.plus.widgets.EditTextEx
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding_half"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginBottom="@dimen/content_padding_half"
android:layout_marginBottom="@dimen/content_padding_half">
<net.osmand.plus.widgets.EditTextEx
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/card_and_list_background_basic"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/default_list_text_size"

View file

@ -1,31 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="?attr/list_background_color">
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/pstsTabBackground">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/action_bar_height"
app:titleTextColor="?attr/list_background_color" />
android:background="?attr/pstsTabBackground"
android:orientation="horizontal"
android:gravity="center_vertical">
</com.google.android.material.appbar.AppBarLayout>
<FrameLayout
android:id="@+id/toolbar_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding_small"
android:layout_marginLeft="@dimen/content_padding_small"
android:background="@null"
android:padding="@dimen/content_padding_half"
android:paddingStart="@dimen/content_padding_half"
android:paddingEnd="@dimen/content_padding_half">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:background="?attr/selectableItemBackgroundBorderless"
osmand:srcCompat="@drawable/ic_arrow_back"/>
</FrameLayout>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/toolbar_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dialog_button_height"
android:layout_marginLeft="@dimen/dialog_button_height"
android:layout_weight="1"
android:ellipsize="end"
android:textColor="@color/list_background_color_light"
android:textSize="@dimen/dialog_header_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="Amsterdam" />
<FrameLayout
android:id="@+id/toolbar_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding_small"
android:layout_marginLeft="@dimen/content_padding_small"
android:layout_marginRight="@dimen/content_padding_small"
android:layout_marginEnd="@dimen/content_padding_small"
android:background="@null"
android:padding="@dimen/content_padding_half"
android:paddingStart="@dimen/content_padding_half"
android:paddingEnd="@dimen/content_padding_half">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:background="?attr/selectableItemBackgroundBorderless"
osmand:srcCompat="@drawable/ic_action_edit_dark"/>
</FrameLayout>
</LinearLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:background="?attr/activity_background_basic">
<LinearLayout
android:id="@+id/ll"
@ -61,33 +109,32 @@
tools:visibility="visible"/>
<FrameLayout
android:id="@+id/btn_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginTop="@dimen/context_menu_padding_margin_small"
android:layout_marginBottom="@dimen/context_menu_padding_margin_small"
android:background="@drawable/rounded_background_3dp">
android:visibility="gone"
tools:visibility="visible">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/btn_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="@dimen/context_menu_padding_margin_small"
android:paddingStart="@dimen/context_menu_padding_margin_small"
android:paddingEnd="@dimen/context_menu_padding_margin_small"
android:duplicateParentState="true"
android:padding="@dimen/bottom_sheet_content_padding_small"
android:paddingStart="@dimen/bottom_sheet_content_padding_small"
android:paddingEnd="@dimen/bottom_sheet_content_padding_small"
android:drawablePadding="@dimen/list_content_padding_large"
osmand:drawableLeftCompat="@drawable/ic_action_edit_dark"
osmand:drawableStartCompat="@drawable/ic_action_edit_dark"
osmand:drawableLeftCompat="@drawable/ic_action_edit_dark"
osmand:drawableTint="?attr/active_color_basic"
android:visibility="gone"
android:text="@string/shared_string_edit"
android:textColor="?attr/active_color_basic"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:visibility="visible" />
osmand:typeface="@string/font_roboto_medium" />
</FrameLayout>

View file

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
@ -20,16 +19,16 @@
android:id="@+id/list_divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dashboard_divider"
android:visibility="gone"
android:layout_marginStart="@dimen/settings_divider_margin_start"
android:layout_marginLeft="@dimen/settings_divider_margin_start"
android:layout_marginStart="@dimen/settings_divider_margin_start" />
android:background="?attr/dashboard_divider"
android:visibility="gone" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/favorites_list_item_height"
android:layout_gravity="center_vertical"
android:minHeight="@dimen/favorites_list_item_height"
android:orientation="horizontal"
android:paddingStart="@dimen/favorites_my_places_icon_left_padding"
android:paddingLeft="@dimen/favorites_my_places_icon_left_padding"
@ -63,12 +62,12 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="vertical"
android:layout_marginStart="@dimen/favorites_my_places_icon_right_padding"
android:layout_marginLeft="@dimen/favorites_my_places_icon_right_padding"
android:layout_marginEnd="@dimen/favorites_my_places_icon_right_padding"
android:layout_marginRight="@dimen/favorites_my_places_icon_right_padding"
android:layout_weight="1"
android:orientation="vertical"
android:paddingTop="@dimen/context_menu_padding_margin_small"
android:paddingBottom="@dimen/context_menu_padding_margin_small">
@ -76,10 +75,10 @@
android:id="@+id/favourite_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/subHeaderPadding"
android:maxLines="2"
android:scrollbars="none"
android:textColor="?android:textColorPrimary"
android:layout_marginBottom="@dimen/subHeaderPadding"
android:textSize="@dimen/default_list_text_size"
tools:text="@string/lorem_ipsum" />
@ -93,6 +92,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="1sp"
android:contentDescription="@string/show_view_angle"
osmand:srcCompat="@drawable/ic_direction_arrow" />
@ -104,8 +104,8 @@
android:layout_marginLeft="@dimen/gpx_small_icon_margin"
android:maxLines="1"
android:textColor="?android:textColorSecondary"
osmand:typeface="@string/font_roboto_medium"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="100500 km" />
<androidx.appcompat.widget.AppCompatImageView
@ -141,8 +141,8 @@
android:layout_marginLeft="@dimen/dashFavIconMargin"
android:background="?attr/dashboard_button"
android:contentDescription="@string/context_menu_item_directions_to"
osmand:srcCompat="@drawable/ic_action_remove_dark"
android:visibility="gone" />
android:visibility="gone"
osmand:srcCompat="@drawable/ic_action_remove_dark" />
<ImageButton
android:id="@+id/options"
@ -151,8 +151,8 @@
android:layout_gravity="center_vertical"
android:background="?attr/dashboard_button"
android:contentDescription="@string/shared_string_more"
osmand:srcCompat="@drawable/ic_overflow_menu_white"
android:visibility="gone" />
android:visibility="gone"
osmand:srcCompat="@drawable/ic_overflow_menu_white" />
</LinearLayout>
</LinearLayout>

View file

@ -68,19 +68,18 @@
android:orientation="horizontal">
<FrameLayout
android:id="@+id/btn_read_full"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/context_menu_padding_margin_small"
android:layout_marginLeft="@dimen/context_menu_padding_margin_small"
android:background="@drawable/rounded_background_3dp">
android:layout_marginStart="@dimen/content_padding_half"
android:layout_marginLeft="@dimen/content_padding_half">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/btn_read_full"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:gravity="center_vertical"
android:background="?attr/selectableItemBackgroundBorderless"
android:duplicateParentState="true"
android:padding="@dimen/bottom_sheet_content_padding_small"
android:paddingStart="@dimen/bottom_sheet_content_padding_small"
android:paddingEnd="@dimen/bottom_sheet_content_padding_small"
@ -96,19 +95,19 @@
</FrameLayout>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/context_menu_padding_margin_small"
android:layout_marginEnd="@dimen/context_menu_padding_margin_small"
android:layout_gravity="end"
android:background="@drawable/rounded_background_3dp">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/btn_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/content_padding_half"
android:layout_marginEnd="@dimen/content_padding_half"
android:layout_gravity="end">
<net.osmand.plus.widgets.TextViewEx
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:gravity="center_vertical"
android:background="?attr/selectableItemBackgroundBorderless"
android:duplicateParentState="true"
android:padding="@dimen/bottom_sheet_content_padding_small"
android:paddingStart="@dimen/bottom_sheet_content_padding_small"
android:paddingEnd="@dimen/bottom_sheet_content_padding_small"
@ -134,7 +133,6 @@
android:layout_marginStart="@dimen/card_padding"
android:layout_marginLeft="@dimen/card_padding"
android:layout_marginTop="@dimen/content_padding"
android:background="@drawable/rounded_background_3dp"
android:visibility="gone"
tools:visibility="visible">
@ -142,7 +140,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="?attr/selectableItemBackgroundBorderless"
android:duplicateParentState="true"
android:padding="@dimen/bottom_sheet_content_padding_small"
android:paddingStart="@dimen/bottom_sheet_content_padding_small"
android:paddingEnd="@dimen/bottom_sheet_content_padding_small"

View file

@ -38,21 +38,23 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:gravity="center"
android:orientation="horizontal"
android:paddingTop="@dimen/dash_margin"
android:paddingBottom="@dimen/dash_margin">
android:layout_marginTop="@dimen/dash_margin"
android:layout_marginBottom="@dimen/dash_margin"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/direction"
android:layout_width="@dimen/context_menu_transport_icon_size"
android:layout_height="@dimen/context_menu_transport_icon_size"
android:layout_gravity="center_vertical"
android:layout_marginTop="1sp"
osmand:srcCompat="@drawable/ic_direction_arrow" />
<TextView
android:id="@+id/distance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="@dimen/content_padding_small_half"
android:layout_marginLeft="@dimen/content_padding_small_half"
android:maxLines="1"

View file

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:minHeight="@dimen/favorites_list_item_height"
android:paddingTop="@dimen/list_header_settings_top_margin"
android:paddingBottom="@dimen/list_header_settings_top_margin"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="@dimen/list_content_padding"
android:layout_marginLeft="@dimen/list_content_padding"
android:layout_marginEnd="@dimen/list_content_padding"
android:layout_marginRight="@dimen/list_content_padding"
android:contentDescription="@string/shared_string_icon"
android:visibility="visible"
osmand:srcCompat="@drawable/ic_action_split_interval" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="@dimen/list_content_padding"
android:layout_marginLeft="@dimen/list_content_padding"
android:layout_marginEnd="@dimen/list_content_padding"
android:layout_marginRight="@dimen/list_content_padding"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
tools:text="Segment" />
<LinearLayout
android:id="@+id/read_section"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingTop="@dimen/subHeaderPadding"
android:paddingBottom="@dimen/subHeaderPadding"
android:visibility="visible">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/distance_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/content_padding_half"
android:layout_marginRight="@dimen/content_padding_half"
android:contentDescription="@string/distance"
osmand:srcCompat="@drawable/ic_action_distance_16" />
<TextView
android:id="@+id/distance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
tools:text="0" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/time_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/content_padding_half"
android:layout_marginRight="@dimen/content_padding_half"
android:contentDescription="@string/track_points"
osmand:srcCompat="@drawable/ic_action_time_moving_16" />
<TextView
android:id="@+id/time_interval"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
tools:text="0" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View file

@ -51,6 +51,7 @@
<LinearLayout
android:id="@+id/name_and_read_section_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingTop="@dimen/gpx_text_top_margin"

View file

@ -6,7 +6,7 @@
android:layout_height="@dimen/list_header_height"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:gravity="center_vertical"
android:gravity="start|center_vertical"
android:orientation="horizontal">
<LinearLayout
@ -14,14 +14,13 @@
android:layout_height="match_parent"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:gravity="center_vertical"
android:maxWidth="@dimen/grid_menu_item_width"
android:gravity="start|center_vertical"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:gravity="start|center_vertical"
android:orientation="horizontal"
android:weightSum="2">
@ -31,6 +30,7 @@
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@null"
android:letterSpacing="@dimen/description_letter_spacing"
android:lines="1"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/default_desc_text_size"
@ -61,8 +61,11 @@
android:layout_height="wrap_content"
android:background="@null"
android:ellipsize="end"
android:letterSpacing="@dimen/description_letter_spacing"
android:gravity="start|center_vertical"
android:lines="1"
android:maxWidth="@dimen/grid_menu_item_width"
android:minWidth="@dimen/map_route_buttons_width"
android:textColor="?android:attr/textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
tools:text="@string/distance" />

View file

@ -73,6 +73,7 @@
android:paddingBottom="@dimen/content_padding_small">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/check_box_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/content_padding"

View file

@ -0,0 +1,172 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding_small"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding_small"
android:weightSum="2">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:text="@string/monitoring_settings"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_medium" />
<LinearLayout
android:id="@+id/status_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:clickable="true"
android:focusable="true"
android:gravity="end|center_vertical"
android:orientation="horizontal">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/text_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:letterSpacing="@dimen/description_letter_spacing"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="@string/recording_default_name"
tools:textColor="@color/icon_color_osmand_light" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon_status"
android:layout_width="@dimen/map_widget_icon"
android:layout_height="@dimen/map_widget_icon"
android:layout_marginStart="@dimen/content_padding_small"
android:layout_marginLeft="@dimen/content_padding_small"
tools:srcCompat="@drawable/ic_action_polygom_dark"
tools:tint="@color/icon_color_osmand_light" />
</LinearLayout>
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/block_statistics"
android:layout_width="match_parent"
android:layout_height="@dimen/list_header_height"
android:layout_marginTop="@dimen/content_padding_small_half"
android:clipToPadding="false"
android:orientation="horizontal"
tools:itemCount="4"
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_gpx_stat_block" />
<include
android:id="@+id/show_track_on_map"
layout="@layout/bottom_sheet_with_switch_divider_and_additional_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding_half"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginBottom="@dimen/content_padding" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dashboard_divider" />
<include
android:id="@+id/button_clear"
layout="@layout/bottom_sheet_button_with_icon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginBottom="@dimen/content_padding" />
<include
android:id="@+id/button_online"
layout="@layout/bottom_sheet_button_with_icon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding_half"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginBottom="@dimen/content_padding"
android:visibility="gone" />
<include
android:id="@+id/button_segment"
layout="@layout/bottom_sheet_button_with_icon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding_half"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding" />
<include
android:id="@+id/button_save"
layout="@layout/bottom_sheet_button_with_icon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding_small"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginBottom="@dimen/content_padding" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding_half"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginBottom="@dimen/content_padding"
android:baselineAligned="false"
android:orientation="horizontal"
android:weightSum="2">
<include
android:id="@+id/button_pause"
layout="@layout/bottom_sheet_button_with_icon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<include
android:id="@+id/button_stop"
layout="@layout/bottom_sheet_button_with_icon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>

View file

@ -2309,7 +2309,7 @@
<string name="relief_smoothness_factor_descr">التضاريس المفضلة : مسطحة أو تلال.</string>
<string name="shared_string_slope">الانحدار</string>
<string name="shared_string_move">نقل</string>
<string name="routing_attr_height_obstacles_description">استخدام بيانات ارتفاع التضاريس المقدمة بواسطة SRTM, ASTER, EU-DEM.</string>
<string name="rendering_attr_depthContours_description">إظهار نقاط ومعالم العمق.</string>
<string name="auto_split_recording_descr">بدء مقطع جديدة بعد فارق 6 دقائق، مسار جديد بعد فارق 2 ساعة، أو ملف جديد بعد فارق أطول إذا تغير التاريخ.</string>
<string name="shared_string_paused">متوقف مؤقتاً</string>

View file

@ -779,7 +779,7 @@
<string name="altitude_descent">Eniş</string>
<string name="altitude_ascent">Yoxuş</string>
<string name="routing_attr_height_obstacles_name">Yüksəklik məlumatlarını istifadə et</string>
<string name="routing_attr_height_obstacles_description">SRTM, ASTER və EU-DEM tərəfindən təmin edilən ərazi yüksəklik məlumatlarını istifadə et.</string>
<string name="rendering_attr_depthContours_description">Dərinlik konturlarını və nöqtələrini göstər.</string>
<string name="rendering_attr_depthContours_name">Dəniz dərinliyi konturları</string>
<string name="rendering_attr_contourDensity_description">Kontur xəttinin sıxlığı</string>

View file

@ -519,7 +519,7 @@
<string name="shared_string_time">Tiempu</string>
<string name="total_distance">Distancia total</string>
<string name="routing_attr_height_obstacles_name">Usar datos d\'elevación</string>
<string name="routing_attr_height_obstacles_description">Inclúi la elevación del tarrén (pelos datos de SRTM, ASTER y EU-DEM).</string>
<string name="search_another_country">Esbillar otra rexón</string>
<string name="shared_string_change">Camudar</string>
<string name="mapillary_image">Imaxe de Mapillary</string>

View file

@ -2189,7 +2189,7 @@ Praparcyjnaj pamiacі %4$s MB (Abmiežavańnie Android %5$s MB, Dalvik %6$s MB).
<string name="mapillary_image">Vyjava Mapillary</string>
<string name="mapillary_widget_descr">Dazvaliaje chutki ŭniosak ŭ Mapillary.</string>
<string name="relief_smoothness_factor_descr">Pieravažny reĺjef: raŭninny ci harysty.</string>
<string name="routing_attr_height_obstacles_description">Faktar vyšyni ziamnoj pavierchni (danyja z SRTM, ASTER i EU-DEM).</string>
<string name="rendering_attr_depthContours_description">Pakazvać kontury i punkty hlybini.</string>
<string name="rendering_attr_contourDensity_description">Ščyĺnasć haryzantaliaŭ</string>
<string name="rendering_attr_contourWidth_description">Taŭščynia haryzantaliaŭ (izahipsy)</string>

View file

@ -2194,7 +2194,7 @@
<string name="shared_string_time">Час</string>
<string name="total_distance">Агульная даўжыня</string>
<string name="routing_attr_height_obstacles_name">Выкарыстоўваць даныя вышыні</string>
<string name="routing_attr_height_obstacles_description">Фактар вышыні зямной паверхні (даныя з SRTM, ASTER і EU-DEM).</string>
<string name="auto_split_recording_title">Аўтаматычнае дзяленне запісаў пасля перапынку</string>
<string name="auto_split_recording_descr">Пачаць новы сегмент пасля 6-хвіліннага перапынку, новы след — пасля 2-гадзіннага перапынку, ці новы файл пасля доўгага перапынку (як змяніляся дата).</string>
<string name="lang_ber">Берберская</string>

View file

@ -2162,7 +2162,7 @@
<string name="rendering_attr_depthContours_description">Mostra isòbates i fondàries puntuals.</string>
<string name="rendering_attr_depthContours_name">Isòbates</string>
<string name="routing_attr_height_obstacles_name">Utilitza les cotes d\'elevació</string>
<string name="routing_attr_height_obstacles_description">Revisa l\'elevació del terreny (mitjançant dades SRTM, ASTER i EU-DEM).</string>
<string name="route_altitude">Alçat de la ruta</string>
<string name="altitude_descent">Descens</string>
<string name="altitude_ascent">Ascens</string>

View file

@ -2174,7 +2174,7 @@
<string name="shared_string_time">Čas</string>
<string name="total_distance">Celková vzdálenost</string>
<string name="routing_attr_height_obstacles_name">Použít údaje o nadmořské výšce</string>
<string name="routing_attr_height_obstacles_description">Zohlednit převýšení terénu (data od SRTM, ASTER a EU-DEM).</string>
<string name="routing_attr_driving_style_name">Styl jízdy</string>
<string name="select_gpx_folder">Vyberte složku pro soubor GPX</string>
<string name="file_can_not_be_moved">Soubor se nepodařilo přesunout.</string>

View file

@ -2172,7 +2172,7 @@
<string name="rendering_attr_depthContours_description">Vis dybdekonturer og -punkter.</string>
<string name="rendering_attr_depthContours_name">Havdybdekonturer</string>
<string name="routing_attr_height_obstacles_name">Brug højdedata</string>
<string name="routing_attr_height_obstacles_description">Terrænhøjde-faktor (via SRTM, ASTER og EU-DEM data).</string>
<string name="route_altitude">Rutehøjde</string>
<string name="altitude_descent">Fald</string>
<string name="altitude_ascent">Stigning</string>

View file

@ -2171,7 +2171,7 @@
<string name="navigate_point_olc">Offener Standortcode (OLC)</string>
<string name="quick_action_page_list_descr">Eine Schaltfläche, um durch die Liste unten zu blättern.</string>
<string name="routing_attr_height_obstacles_name">Höhendaten berücksichtigen</string>
<string name="routing_attr_height_obstacles_description">Faktor im Geländeprofil (über SRTM, ASTER und EU-DEM-Daten).</string>
<string name="rendering_attr_depthContours_name">Nautische Tiefenlinien</string>
<string name="rendering_attr_depthContours_description">Tiefenlinien und -punkte einblenden.</string>
<string name="route_altitude">Routenhöhenprofil</string>

View file

@ -1876,7 +1876,7 @@
<string name="total_distance">Συνολική απόσταση</string>
<string name="routing_attr_relief_smoothness_factor_name">Επιλέξτε διακύμανση ανύψωσης</string>
<string name="routing_attr_height_obstacles_name">Χρήση υψομετρικών δεδομένων</string>
<string name="routing_attr_height_obstacles_description">Συντελεστής σε ανύψωση εδάφους (μέσω SRTM, ASTER και δεδομένων EU-DEM).</string>
<string name="rendering_attr_depthContours_description">Εμφάνιση ισοβαθών καμπυλών και σημείων.</string>
<string name="rendering_attr_depthContours_name">Ναυτικές ισοβαθείς καμπύλες</string>
<string name="auto_split_recording_title">Αυτόματος διαχωρισμός καταγραφών μετά από κενό</string>

View file

@ -2166,7 +2166,7 @@
<string name="rendering_attr_depthContours_description">Montri punktojn kaj kurbojn de profundo.</string>
<string name="rendering_attr_depthContours_name">Maraj profundec-kurboj</string>
<string name="routing_attr_height_obstacles_name">Uzi datumojn pri altitudo</string>
<string name="routing_attr_height_obstacles_description">Konsideri nivelon de tereno (laŭ datumoj el SRTM, ASTER kaj EU-DEM).</string>
<string name="route_altitude">Kursa altitudo</string>
<string name="altitude_descent">Malsupreniro</string>
<string name="altitude_ascent">Supreniro</string>

View file

@ -2175,7 +2175,7 @@
<string name="shared_string_time">Tiempo</string>
<string name="total_distance">Distancia total</string>
<string name="routing_attr_height_obstacles_name">Usar datos de elevación</string>
<string name="routing_attr_height_obstacles_description">Incluye como factor, la elevación del terreno (según datos de SRTM, ASTER y EU-DEM).</string>
<string name="routing_attr_driving_style_name">Estilo de conducción</string>
<string name="select_gpx_folder">Marcar la carpeta del archivo GPX</string>
<string name="file_can_not_be_moved">No se pudo mover el archivo.</string>

View file

@ -2175,7 +2175,7 @@
<string name="shared_string_time">Tiempo</string>
<string name="total_distance">Distancia total</string>
<string name="routing_attr_height_obstacles_name">Usar datos de elevación</string>
<string name="routing_attr_height_obstacles_description">Incluye como factor, la elevación del terreno (según datos de SRTM, ASTER y EU-DEM).</string>
<string name="routing_attr_driving_style_name">Estilo de conducción</string>
<string name="select_gpx_folder">Marcar la carpeta del archivo GPX</string>
<string name="file_can_not_be_moved">No se pudo mover el archivo.</string>

View file

@ -2163,7 +2163,7 @@
<string name="shared_string_time">Tiempo</string>
<string name="total_distance">Distancia total</string>
<string name="routing_attr_height_obstacles_name">Usar datos de elevación</string>
<string name="routing_attr_height_obstacles_description">Incluye como factor, la elevación del terreno (según datos de SRTM, ASTER y EU-DEM).</string>
<string name="rendering_attr_depthContours_description">Mostrar curvas y puntos de profundidad.</string>
<string name="rendering_attr_depthContours_name">Curvas de profundidad náuticas</string>
<string name="auto_split_recording_title">División automática de grabaciones en intervalos</string>

View file

@ -2504,7 +2504,7 @@
<string name="rendering_attr_depthContours_description">Kuva sügavuskontuurid ja -punktid.</string>
<string name="rendering_attr_depthContours_name">Meresügavuse kontuurid</string>
<string name="routing_attr_height_obstacles_name">Kasuta kõrgusandmeid</string>
<string name="routing_attr_height_obstacles_description">Maastiku kõrguse tegur (SRTM, ASTER ja EU-DEM andmestikust).</string>
<string name="altitude_descent">Laskumine</string>
<string name="altitude_ascent">Tõus</string>
<string name="altitude_range">Kõrgusevahe</string>

View file

@ -2197,7 +2197,7 @@ Area honi dagokio: %1$s x %2$s</string>
<string name="shared_string_time">Denbora</string>
<string name="total_distance">Distantzia guztira</string>
<string name="routing_attr_height_obstacles_name">Erabili elebazio kotak</string>
<string name="routing_attr_height_obstacles_description">Kontuan izan terrenoaren elebazioa (SRTM, ASTER, eta EU-DEM datuen bidez).</string>
<string name="shared_string_slope">Malda</string>
<string name="lang_ber">Berberera</string>
<string name="right_side_navigation">Eskumatik gidatzea</string>

View file

@ -1811,7 +1811,7 @@
<string name="average_altitude">میانگین ارتفاع</string>
<string name="total_distance">مسافت کل</string>
<string name="routing_attr_height_obstacles_name">استفاده از دادهٔ ارتفاعی</string>
<string name="routing_attr_height_obstacles_description">فاکتور ارتفاع‌دهی عارضه‌ها (با استفاده از داده‌های SRTM، ASTER و EU-DEM).</string>
<string name="rendering_attr_depthContours_description">نمایش نقاط و منحنی‌های میزان عمقی.</string>
<string name="rendering_attr_depthContours_name">منحنی‌های میزان عمق دریا</string>
<string name="rendering_attr_contourDensity_description">تراکم منحنی میزان</string>

View file

@ -1898,7 +1898,7 @@ Jos pidät OsmAndista ja OSMsta ja haluat tukea niitä, on tämä täydellinen t
<string name="shared_string_time">Aika</string>
<string name="total_distance">Kokonaisetäisyys</string>
<string name="routing_attr_height_obstacles_name">Käytä korkeustietoja</string>
<string name="routing_attr_height_obstacles_description">Käytä maaston korkeustietoja jotka saadaan SRTM, ASTER ja EU-DEM lähteistä</string>
<string name="auto_split_recording_title">Jaa automaattisesti nauhoitukset tauon jälkeen</string>
<string name="rendering_attr_hideWaterPolygons_name">Piilota vesi</string>
<string name="shared_string_action_name">Toiminnon nimi</string>

View file

@ -2158,7 +2158,7 @@
<string name="rendering_attr_depthContours_description">Afficher les lignes et points de sonde.</string>
<string name="rendering_attr_depthContours_name">Lignes de sonde maritimes</string>
<string name="routing_attr_height_obstacles_name">Utiliser les données d\'altitude</string>
<string name="routing_attr_height_obstacles_description">Facteur pour les données d\'altitude fournies par SRTM, ASTER et EU-DEM.</string>
<string name="average_altitude">Altitude moyenne</string>
<string name="total_distance">Distance totale</string>
<string name="shared_string_time">Durée</string>

View file

@ -2572,7 +2572,7 @@ Lon %2$s</string>
<string name="do_not_send_anonymous_app_usage_desc">O OsmAnd recompila información sobre as lapelas que abres na aplicación. Non estamos a recompilar datos da localización, datos inseridos na aplicación ou datos relacionados coas áreas que ollas, procuras ou baixas.</string>
<string name="do_not_show_startup_messages_desc">Agocha os descontos da aplicación e as mensaxes especiais dos acontecementos locais.</string>
<string name="routing_attr_relief_smoothness_factor_name">Escoller variación da altitude</string>
<string name="routing_attr_height_obstacles_description">Inclúe coma factor, a altitude do terreo (segundo datos do SRTM, ASTER e EU-DEM).</string>
<string name="rendering_attr_depthContours_description">Amosar curvas e puntos do afundimento.</string>
<string name="rendering_attr_depthContours_name">Curvas do afundimento náuticos</string>
<string name="auto_split_recording_title">División automática das gravacións en intres</string>

View file

@ -2168,7 +2168,7 @@
<string name="shared_string_time">Idő</string>
<string name="total_distance">Teljes táv</string>
<string name="routing_attr_height_obstacles_name">Magasságadatok használata</string>
<string name="routing_attr_height_obstacles_description">Terepmagasság figyelembe vétele (SRTM, ASTER és EU-DEM domborzatmodellekből).</string>
<string name="rendering_attr_depthContours_description">Mélységvonalak és pontok megjelenítése.</string>
<string name="rendering_attr_depthContours_name">Tengeri mélységvonalak</string>
<string name="auto_split_recording_title">Felvételek automatikus szétvágása szünet után</string>

View file

@ -341,7 +341,7 @@
<string name="total_distance">Ընդհանուր հեռավորությունը</string>
<string name="routing_attr_relief_smoothness_factor_name">Ընտրել բարձունքների տատանումը</string>
<string name="routing_attr_height_obstacles_name">Օգտագործել բարձրության տվյալները</string>
<string name="routing_attr_height_obstacles_description">Օգտագործել բարձրության տվյալներ տրամադրված SRTM, ASTER և EU-DEM։</string>
<string name="rendering_attr_depthContours_description">Ցույց տալ խորության տվյալները։</string>
<string name="rendering_attr_depthContours_name">Ծովային խորքային ուրվագծեր</string>
<string name="rendering_attr_contourDensity_description">Եզրագծերի խտությունը</string>

View file

@ -333,7 +333,7 @@
<string name="total_distance">Jarak Total</string>
<string name="routing_attr_relief_smoothness_factor_name">Pilih fluktuasi ketinggian</string>
<string name="routing_attr_height_obstacles_name">Gunakan Data Ketinggian</string>
<string name="routing_attr_height_obstacles_description">Gunakan data elevasi medan yang disediakan oleh SRTM, ASTER, dan EU-DEM.</string>
<string name="rendering_attr_depthContours_description">Tampilkan kontur dan titik kedalaman.</string>
<string name="rendering_attr_depthContours_name">Kontur kedalaman bahari</string>
<string name="auto_split_recording_title">Rekaman split otomatis setelah jeda</string>

View file

@ -1994,7 +1994,7 @@
<string name="fonts_header">Letur fyrir kort</string>
<string name="right_side_navigation">Ekið á hægri akrein</string>
<string name="driving_region_automatic">Sjálfvirkt</string>
<string name="routing_attr_height_obstacles_description">Nota yfirborðshæðargögn (í gegnum SRTM, ASTER og EU-DEM).</string>
<string name="auto_split_recording_title">Skipta skráningu sjálfvirkt eftir bil</string>
<string name="incremental_search_city">Stigvaxandi leit í borg</string>
<string name="rendering_attr_showRoadMaps_description">Veldu þegar birta á kort einungis með vegum:</string>

View file

@ -2167,7 +2167,7 @@
<string name="shared_string_time">Tempo</string>
<string name="total_distance">Distanza totale</string>
<string name="routing_attr_height_obstacles_name">Utilizza dati altitudine</string>
<string name="routing_attr_height_obstacles_description">Fattore di elevazione del terreno (tramite i dati SRTM, ASTER e EU-DEM).</string>
<string name="shared_string_time_span">Intervallo di tempo</string>
<string name="shared_string_max">Massimo</string>
<string name="shared_string_start_time">Ora d\'inizio</string>

View file

@ -2712,7 +2712,7 @@
\n ניתן לקבל נווט אמין למדינה שלך - בין אם זו ישראל, צרפת, גרמניה, מקסיקו, אנגליה, ספרד, הולנד, ארה״ב, רוסיה, ברזיל או כל מדינה אחרת.</string>
<string name="nm">מייל ימי</string>
<string name="rendering_attr_hikingRoutesOSMC_description">עיבוד מסלולים לפי עקבות OSMC.</string>
<string name="routing_attr_height_obstacles_description">מקדם נתוני גובה פני קרקע (נתונים של SRTM, ASTER ו־EU-DEM).</string>
<string name="plugin_nautical_descr">תוסף זה מעשיר את המפה ואת הניווט של יישומון OsmAnd ומאפשר לייצר מפות ימיות לחתירה, הפלגה וסוגים נוספים של ספורט ימי.
\n
\nתוסף מפה מיוחד ל־OsmAnd יספק את כל סימוני הניווט הימיים והסימנים הימיים המוסכמים, לניווט במקווי מים פנימיים לרבות ניווט באזורים הקרובים לחוף. התיאור של כל סימון ניווט מספק את הפרטים הנדרשים כדי לזהות אותם ואת המשמעות שלהם (קטגוריה, צורה, צבע, רצף, הפניה וכו׳).

View file

@ -2084,7 +2084,7 @@ POIの更新は利用できません</string>
<string name="shared_string_time">時間</string>
<string name="total_distance">総走行距離</string>
<string name="routing_attr_height_obstacles_name">標高データを使用</string>
<string name="routing_attr_height_obstacles_description">SRTM、ASTER、EU-DEMによる地形標高データを使用します。</string>
<string name="rendering_attr_hideWaterPolygons_description">水域</string>
<string name="rendering_attr_hideWaterPolygons_name">水域ポリゴン</string>
<string name="wiki_around">近隣のWikipedia記事</string>

View file

@ -2231,7 +2231,7 @@ Tai yra puikus būdas paremti OsmAnd ir OSM, jei jie jums patinka.</string>
<string name="total_distance">Bendras atstumas</string>
<string name="routing_attr_relief_smoothness_factor_name">Pasirinkite aukščio kaitos diapazoną</string>
<string name="routing_attr_height_obstacles_name">Naudoti aukščio informaciją</string>
<string name="routing_attr_height_obstacles_description">Vietovės reljefo faktorius (SRTM, ASTER ir EU-DEM duomenimis).</string>
<string name="rendering_attr_depthContours_description">Rodyti gylio kontūrus ir taškus.</string>
<string name="rendering_attr_depthContours_name">Vandenyno gylio kontūrai</string>
<string name="auto_split_recording_title">Automatinis įrašo padalinimas po pertraukimo</string>

View file

@ -2166,7 +2166,7 @@ Apraksta laukumu: %1$s x %2$s</string>
<string name="shared_string_time">Laiks</string>
<string name="total_distance">Maršruta garums</string>
<string name="routing_attr_height_obstacles_name">Lietot elevācijas datus</string>
<string name="routing_attr_height_obstacles_description">Lietot apgabala elevācijas datus no SRTM, ASTER un EU-DEM.</string>
<string name="relief_smoothness_factor_descr">Ieteicamais reljefs: līdzens vai kalnains.</string>
<string name="shared_string_slope">Slīpums</string>
<string name="lang_ber">Berberu</string>

View file

@ -2015,7 +2015,7 @@
<string name="add_new_folder">Legg til ny mappe</string>
<string name="shared_string_gpx_track">Spor</string>
<string name="routing_attr_height_obstacles_name">Bruk høydedata</string>
<string name="routing_attr_height_obstacles_description">Ta hensyn til terrenghøyde (data fra SRTM, ASTER og EU-DEM).</string>
<string name="quick_action_bug_message">Melding</string>
<string name="shared_string_permissions">Tillatelser</string>
<string name="import_gpx_failed_descr">Kunne ikke importere filen. Kontroller at OsmAnd har tillatelse til å lese den.</string>

View file

@ -2177,7 +2177,7 @@
<string name="shared_string_time_moving">Tijd in beweging</string>
<string name="routing_attr_driving_style_name">Rijstijl</string>
<string name="routing_attr_height_obstacles_name">Hoogtegegevens gebruiken</string>
<string name="routing_attr_height_obstacles_description">Gebruik hoogtegegevens (van SRTM, ASTER en EU-DEM data) bij bepalen route.</string>
<string name="shared_string_gpx_track">Track</string>
<string name="right_side_navigation">Rechts rijdend</string>
<string name="driving_region_automatic">Automatisch</string>

View file

@ -2169,7 +2169,7 @@
<string name="rendering_attr_depthContours_description">Wyświetla kontury i punkty głębi.</string>
<string name="rendering_attr_depthContours_name">Morskie kontury głębokości</string>
<string name="routing_attr_height_obstacles_name">Używanie danych wysokościowych</string>
<string name="routing_attr_height_obstacles_description">Używa danych wysokościowych (dane z SRTM, ASTER i EU-DEM).</string>
<string name="route_altitude">Wysokość trasy</string>
<string name="altitude_descent">W dół</string>
<string name="altitude_ascent">W górę</string>

View file

@ -2207,7 +2207,7 @@
<string name="route_altitude">Altitude da rota</string>
<string name="routing_attr_relief_smoothness_factor_name">Selecionar a flutuação de altimetria</string>
<string name="routing_attr_height_obstacles_name">Usar dados altimétricos</string>
<string name="routing_attr_height_obstacles_description">Considerar altimetria do terreno (via dados SRTM, ASTER e EU-DEM).</string>
<string name="rendering_attr_depthContours_description">Mostrar curvas e pontos batimétricos.</string>
<string name="rendering_attr_depthContours_name">Batimetria náutica</string>
<string name="rendering_attr_contourDensity_description">Densidade das curvas de nível</string>

View file

@ -2011,7 +2011,7 @@
<string name="total_distance">Distância total</string>
<string name="routing_attr_relief_smoothness_factor_name">Selecionar flutuação de elevação</string>
<string name="routing_attr_height_obstacles_name">Utilizar dados de elevação</string>
<string name="routing_attr_height_obstacles_description">Utilizar elevação de terreno (dos dados do SRTM, ASTER e EU-DEM).</string>
<string name="rendering_attr_depthContours_description">Mostrar pontos e contornos de profundidade.</string>
<string name="rendering_attr_depthContours_name">Contornos de profundidade náuticos</string>
<string name="show_transparency_seekbar">Mostra a transparência da barra de navegação</string>

View file

@ -142,7 +142,7 @@
<string name="routing_attr_driving_style_name">Стиль езды</string>
<string name="routing_attr_relief_smoothness_factor_name">Колебания высоты ландшафта</string>
<string name="routing_attr_height_obstacles_name">Использовать данные о высотах</string>
<string name="routing_attr_height_obstacles_description">Фактор рельефа местности (по данным SRTM, ASTER и EU-DEM).</string>
<string name="quick_action_duplicates">Действие переименовано в %1$s, чтобы избежать дублирования.</string>
<string name="quick_action_duplicate">Обнаружен дубликат имени</string>
<string name="quick_action_showhide_favorites_descr">Переключатель, чтобы показать или скрыть избранные точки на карте.</string>

View file

@ -2167,7 +2167,7 @@
<string name="rendering_attr_depthContours_name">Curvas de profondidade nàuticas</string>
<string name="rendering_attr_depthContours_description">Ammustra sas lìnias de profondidade.</string>
<string name="routing_attr_height_obstacles_name">Imprea sos datos de s\'artària</string>
<string name="routing_attr_height_obstacles_description">Fatore pro s\'artària de su terrinu (dae datos SRTM, ASTER e EU-DEM).</string>
<string name="routing_attr_driving_style_name">Istile de ghia</string>
<string name="route_altitude">Artària de su caminu</string>
<string name="altitude_descent">Falada</string>

View file

@ -2165,7 +2165,7 @@
<string name="rendering_attr_depthContours_description">Zobraziť hĺbkové úrovne a body.</string>
<string name="rendering_attr_depthContours_name">Námorné hĺbkové vrstevnice</string>
<string name="routing_attr_height_obstacles_name">Použiť údaje nadmorskej výšky</string>
<string name="routing_attr_height_obstacles_description">Zohľadniť prevýšenie terénu (z údajov SRTM, ASTER a EU-DEM).</string>
<string name="route_altitude">Prevýšenie trasy</string>
<string name="altitude_descent">Klesanie</string>
<string name="altitude_ascent">Stúpanie</string>

View file

@ -2169,7 +2169,7 @@
<string name="shared_string_time">Čas</string>
<string name="total_distance">Skupna razdalja</string>
<string name="routing_attr_height_obstacles_name">Uporabi podatke višine</string>
<string name="routing_attr_height_obstacles_description">Faktor podatkov spreminjanja višine terena (po podatkih SRTM, ASTER in EU-DEM).</string>
<string name="routing_attr_driving_style_name">Način vožnje</string>
<string name="select_gpx_folder">Izbor mape datotek GPX</string>
<string name="file_can_not_be_moved">Datoteke ni mogoče premakniti.</string>

View file

@ -1525,7 +1525,7 @@
<string name="index_item_depth_points_northern_hemisphere">Поморске дубинске тачке северне полулопте</string>
<string name="download_depth_countours">Поморске изобате</string>
<string name="shared_string_color">Боја</string>
<string name="routing_attr_height_obstacles_description">Урачунај и податке висине земљишта (обезбеђених помоћу СРМ, АСТЕР и ЕУ-ДЕМ података).</string>
<string name="auto_split_recording_title">Самоподели снимке после размака</string>
<string name="auto_split_recording_descr">Почни нови одсечак после размака од 6 минута, нову путању после размака од 2 сата, или нови фајл после дужег размака ако је дан измењен.</string>
<string name="rendering_attr_showMtbRoutes_name">Прикажи путеве планинских бицикли</string>

View file

@ -2097,7 +2097,7 @@ Vänligen tillhandahåll fullständig kod</string>
<string name="quick_action_map_overlay_switch">"Kartöverlägget har ändrats till \"%s\"."</string>
<string name="quick_action_btn_tutorial_descr">Tryck länge och dra knappen för att ändra dess position på skärmen.</string>
<string name="routing_attr_height_obstacles_name">Använd höjddata</string>
<string name="routing_attr_height_obstacles_description">Använd terränghöjddata från SRTM, ASTER och EU-DEM.</string>
<string name="rendering_attr_depthContours_description">Visa djupkonturer och punkter.</string>
<string name="shared_string_slope">Sluttning</string>
<string name="altitude_range">Höjdområde</string>

View file

@ -2307,7 +2307,7 @@
<string name="average_altitude">Ortalama yükseklik</string>
<string name="routing_attr_relief_smoothness_factor_name">Yükseklikte dalgalanma seçin</string>
<string name="routing_attr_height_obstacles_name">Yükseklik verisi kullan</string>
<string name="routing_attr_height_obstacles_description">Arazi kotunda faktör (SRTM, ASTER ve EU-DEM verileri aracılığıyla).</string>
<string name="search_map_hint">Şehir veya bölge</string>
<string name="route_roundabout_short">%1$d çıkışa gir ve ilerle</string>
<string name="gpx_no_tracks_title">Henüz yol dosyanız yok</string>

View file

@ -2130,7 +2130,7 @@
<string name="shared_string_time">Час</string>
<string name="total_distance">Загальна відстань</string>
<string name="routing_attr_height_obstacles_name">Використовувати дані висоти</string>
<string name="routing_attr_height_obstacles_description">Фактор висоти рельєфу земної поверхні (дані від SRTM, ASTER та EU-DEM).</string>
<string name="rendering_attr_depthContours_description">Показати контури глибини і точки.</string>
<string name="rendering_attr_depthContours_name">Контури морських глибин</string>
<string name="auto_split_recording_title">Авто-розрив запису після перерви</string>

View file

@ -1382,7 +1382,7 @@
<string name="average_altitude">平均海拔</string>
<string name="routing_attr_relief_smoothness_factor_name">选择海拔波动</string>
<string name="routing_attr_height_obstacles_name">使用标高数据</string>
<string name="routing_attr_height_obstacles_description">地形高程因素(通过 SRTM、ASTER 和欧盟 DEM 数据)。</string>
<string name="rendering_attr_depthContours_description">显示等深线和标记。</string>
<string name="rendering_attr_depthContours_name">航海等深线</string>
<string name="auto_split_recording_title">自动拆分录音后的间隙</string>

View file

@ -2161,7 +2161,7 @@
<string name="rendering_attr_depthContours_description">顯示等深線和標記。</string>
<string name="rendering_attr_depthContours_name">航海等深線</string>
<string name="routing_attr_height_obstacles_name">使用海拔資料</string>
<string name="routing_attr_height_obstacles_description">將地勢海拔納入 (透過 SRTM、ASTER 和 EU-DEM 的資料)。</string>
<string name="route_altitude">路線的海拔</string>
<string name="altitude_descent">下坡</string>
<string name="altitude_ascent">上坡</string>

View file

@ -413,4 +413,7 @@
<dimen name="radioButtonSize">32dp</dimen>
<dimen name="checkBoxSize">24dp</dimen>
<dimen name="titleLineSpacingExtra">5sp</dimen>
<dimen name="descriptionLineSpacingExtra">3sp</dimen>
</resources>

View file

@ -12,8 +12,16 @@
-->
<string name="routing_attr_height_obstacles_description">Routing could avoid strong uphills.</string>
<string name="app_restart_required">Application restart required to apply some settings.</string>
<string name="on_pause">On pause</string>
<string name="track_recording_description">Are you sure you want to stop recording?\nAll unsaved data will be lost.</string>
<string name="track_recording_title">Track recording stopped</string>
<string name="track_recording_save_and_stop">Save and stop recording</string>
<string name="track_recording_stop_without_saving">Stop without saving</string>
<string name="delete_number_files_question">Delete %1$d files?</string>
<string name="shared_strings_all_regions">All regions</string>
<string name="restart">Restart</string>
<string name="elevation_data_descr">Routing could avoid strong uphills</string>
<string name="map_orientation_threshold_descr">Don\'t rotate map view if speed is less than a threshold</string>
<string name="snap_to_road_descr">Current location icon will be snapped to the current navigation route</string>
<string name="routing_attr_driving_style_description">Select driving purpose to get shorter, faster or safer route</string>
@ -39,6 +47,9 @@
<string name="hillshade_slope_contour_lines">Hillshade / Slope / Contour lines</string>
<string name="toast_select_edits_for_upload">Select edits for upload</string>
<string name="uploaded_count">Uploaded %1$d of %2$d</string>
<string name="segments_count">Segment %1$d</string>
<string name="select_segments_description">%1$s contains more than one segment, you need to select the needed part for the navigation.</string>
<string name="select_segments">Select segments</string>
<string name="uploading_count">Uploading %1$d of %2$d</string>
<string name="upload_photo_completed">Upload completed</string>
<string name="upload_photo">Uploading</string>
@ -1613,7 +1624,6 @@
<string name="total_distance">Total distance</string>
<string name="routing_attr_relief_smoothness_factor_name">Select elevation fluctuation</string>
<string name="routing_attr_height_obstacles_name">Use elevation data</string>
<string name="routing_attr_height_obstacles_description">Factor in terrain elevation (via SRTM, ASTER, and EU-DEM data).</string>
<string name="rendering_attr_depthContours_description">Show depth contours and points.</string>
<string name="rendering_attr_depthContours_name">Nautical depth contours</string>
<!-- string name="release_2_6">

View file

@ -66,6 +66,8 @@ import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
import java.io.File;
import java.lang.reflect.Field;
import java.text.MessageFormat;
@ -84,6 +86,7 @@ import static android.util.TypedValue.COMPLEX_UNIT_DIP;
import static android.util.TypedValue.COMPLEX_UNIT_SP;
public class AndroidUtils {
private static final Log LOG = PlatformUtil.getLog(AndroidUtils.class);
public static final String STRING_PLACEHOLDER = "%s";
public static final MessageFormat formatKb = new MessageFormat("{0, number,##.#}", Locale.US);
@ -804,16 +807,24 @@ public class AndroidUtils {
public static long getAvailableSpace(@Nullable File dir) {
if (dir != null && dir.canRead()) {
try {
StatFs fs = new StatFs(dir.getAbsolutePath());
return fs.getAvailableBlocksLong() * fs.getBlockSize();
} catch (IllegalArgumentException e) {
LOG.error(e);
}
}
return -1;
}
public static float getFreeSpaceGb(File dir) {
if (dir.canRead()) {
try {
StatFs fs = new StatFs(dir.getAbsolutePath());
return (float) (fs.getBlockSize()) * fs.getAvailableBlocks() / (1 << 30);
} catch (IllegalArgumentException e) {
LOG.error(e);
}
}
return -1;
}

View file

@ -11,6 +11,8 @@ import com.squareup.picasso.Picasso;
import net.osmand.plus.OsmandApplication;
import org.apache.commons.logging.Log;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
@ -23,6 +25,7 @@ import static android.os.Build.VERSION.SDK_INT;
import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2;
public class PicassoUtils {
private static final Log LOG = PlatformUtil.getLog(PicassoUtils.class);
private static final String PICASSO_CACHE = "picasso-cache";
private static final int MIN_DISK_CACHE_SIZE = 5 * 1024 * 1024; // 5MB
@ -109,7 +112,8 @@ public class PicassoUtils {
long available = blockCount * blockSize;
// Target 2% of the total space.
size = available / 50;
} catch (IllegalArgumentException ignored) {
} catch (IllegalArgumentException e) {
LOG.error(e);
}
// Bound inside min/max size for disk cache.

View file

@ -62,6 +62,8 @@ import net.osmand.plus.mapmarkers.MarkersPlanRouteContext;
import net.osmand.plus.measurementtool.MeasurementToolFragment;
import net.osmand.plus.measurementtool.StartPlanRouteBottomSheet;
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
import net.osmand.plus.monitoring.TripRecordingActiveBottomSheet;
import net.osmand.plus.monitoring.TripRecordingBottomSheet;
import net.osmand.plus.osmedit.dialogs.DismissRouteBottomSheetFragment;
import net.osmand.plus.profiles.ProfileDataObject;
import net.osmand.plus.profiles.ProfileDataUtils;
@ -98,6 +100,7 @@ import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_CONFIGURE_P
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_CONFIGURE_SCREEN_ID;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_DASHBOARD_ID;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_DIRECTIONS_ID;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_TRIP_RECORDING_ID;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_DIVIDER_ID;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_DOWNLOAD_MAPS_ID;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_HELP_ID;
@ -522,6 +525,7 @@ public class MapActivityActions implements DialogProvider {
GPXRouteParamsBuilder params = new GPXRouteParamsBuilder(result, settings);
params.setCalculateOsmAndRouteParts(settings.GPX_ROUTE_CALC_OSMAND_PARTS.get());
params.setCalculateOsmAndRoute(settings.GPX_ROUTE_CALC.get());
params.setSelectedSegment(settings.GPX_ROUTE_SEGMENT.get());
List<Location> ps = params.getPoints(settings.getContext());
mapActivity.getRoutingHelper().setGpxParams(params);
settings.FOLLOW_THE_GPX_ROUTE.set(result.path);
@ -839,6 +843,26 @@ public class MapActivityActions implements DialogProvider {
}
}).createItem());
final OsmandMonitoringPlugin monitoringPlugin = OsmandPlugin.getEnabledPlugin(OsmandMonitoringPlugin.class);
if (monitoringPlugin != null) {
optionsMenuHelper.addItem(new ItemBuilder().setTitleId(R.string.map_widget_monitoring, mapActivity)
.setId(DRAWER_TRIP_RECORDING_ID)
.setIcon(R.drawable.ic_action_track_recordable)
.setListener(new ItemClickListener() {
@Override
public boolean onContextMenuClick(ArrayAdapter<ContextMenuItem> adapter, int itemId, int pos, boolean isChecked, int[] viewCoordinates) {
app.logEvent("trip_recording_open");
MapActivity.clearPrevActivityIntent();
if (monitoringPlugin.hasDataToSave() || monitoringPlugin.wasTrackMonitored()) {
TripRecordingActiveBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), monitoringPlugin.getCurrentTrack());
} else {
TripRecordingBottomSheet.showInstance(mapActivity.getSupportFragmentManager());
}
return true;
}
}).createItem());
}
optionsMenuHelper.addItem(new ItemBuilder().setTitleId(R.string.get_directions, mapActivity)
.setId(DRAWER_DIRECTIONS_ID)

View file

@ -19,6 +19,7 @@ import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.OsmAndLocationProvider;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.Version;
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
@ -78,6 +79,9 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
private SelectedGpxFile currentTrack;
private int points;
private int trkPoints = 0;
private long lastTimeFileSaved;
private ApplicationMode lastRoutingApplicationMode;
public SavingTrackHelper(OsmandApplication ctx) {
super(ctx, DATABASE_NAME, null, DATABASE_VERSION);
@ -255,6 +259,7 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
GPXTrackAnalysis analysis = gpx.getAnalysis(fout.lastModified());
GpxDataItem item = new GpxDataItem(fout, analysis);
ctx.getGpxDbHelper().add(item);
lastTimeFileSaved = fout.lastModified();
}
}
}
@ -440,12 +445,15 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
} else {
heading = NO_HEADING;
}
if (ctx.getRoutingHelper().isFollowingMode()) {
lastRoutingApplicationMode = settings.getApplicationMode();
}
boolean record = false;
if (location != null && OsmAndLocationProvider.isNotSimulatedLocation(location)
&& OsmandPlugin.getEnabledPlugin(OsmandMonitoringPlugin.class) != null) {
if (settings.SAVE_TRACK_TO_GPX.get()
&& locationTime - lastTimeUpdated > settings.SAVE_TRACK_INTERVAL.get()
&& ctx.getRoutingHelper().isFollowingMode()) {
&& lastRoutingApplicationMode == settings.getApplicationMode()) {
record = true;
} else if (settings.SAVE_GLOBAL_TRACK_TO_GPX.get()
&& locationTime - lastTimeUpdated > settings.SAVE_GLOBAL_TRACK_INTERVAL.get()) {
@ -705,9 +713,10 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
}
public boolean getIsRecording() {
OsmandSettings settings = ctx.getSettings();
return OsmandPlugin.getEnabledPlugin(OsmandMonitoringPlugin.class) != null
&& ctx.getSettings().SAVE_GLOBAL_TRACK_TO_GPX.get()
|| (ctx.getSettings().SAVE_TRACK_TO_GPX.get() && ctx.getRoutingHelper().isFollowingMode());
&& settings.SAVE_GLOBAL_TRACK_TO_GPX.get() || settings.SAVE_TRACK_TO_GPX.get()
&& lastRoutingApplicationMode == settings.getApplicationMode();
}
public float getDistance() {
@ -730,6 +739,14 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
return lastTimeUpdated;
}
public long getLastTimeFileSaved() {
return lastTimeFileSaved;
}
public void setLastTimeFileSaved(long lastTimeFileSaved) {
this.lastTimeFileSaved = lastTimeFileSaved;
}
public GPXFile getCurrentGpx() {
return currentTrack.getGpxFile();
}

View file

@ -384,8 +384,12 @@ public class MultimediaNotesFragment extends BaseSettingsFragment implements Cop
File dir = app.getAppPath("").getParentFile();
long size = 0;
if (dir.canRead()) {
try {
StatFs fs = new StatFs(dir.getAbsolutePath());
size = ((long) fs.getBlockSize() * (long) fs.getBlockCount()) / (1 << 30);
} catch (IllegalArgumentException e) {
log.error(e);
}
}
if (size > 0) {
int value = 1;

View file

@ -134,6 +134,9 @@ public class FailSafeFuntions {
if(settings.GPX_ROUTE_CALC.get()) {
gpxRoute.setCalculateOsmAndRoute(true);
}
if (settings.GPX_ROUTE_SEGMENT.get() != -1) {
gpxRoute.setSelectedSegment(settings.GPX_ROUTE_SEGMENT.get());
}
} else {
gpxRoute = null;
}

View file

@ -380,7 +380,7 @@ public abstract class MenuBottomSheetDialogFragment extends BottomSheetDialogFra
AndroidUiHelper.updateVisibility(dismissButton, buttonTextId != DEFAULT_VALUE);
}
private void setupRightButton() {
protected void setupRightButton() {
rightButton = buttonsContainer.findViewById(R.id.right_bottom_button);
rightButton.getLayoutParams().height = getRightButtonHeight();
int buttonTextId = getRightBottomButtonTextId();

View file

@ -0,0 +1,301 @@
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

@ -31,6 +31,7 @@ import androidx.fragment.app.FragmentActivity;
import net.osmand.AndroidUtils;
import net.osmand.FileUtils;
import net.osmand.PlatformUtil;
import net.osmand.ValueHolder;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.settings.backend.OsmandSettings;
@ -39,6 +40,8 @@ import net.osmand.plus.R;
import net.osmand.plus.download.DownloadActivity;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@ -52,7 +55,7 @@ import java.util.Locale;
import gnu.trove.list.array.TIntArrayList;
public class DashChooseAppDirFragment {
private static final Log LOG = PlatformUtil.getLog(DashChooseAppDirFragment.class);
public static class ChooseAppDirFragment {
public static final int VERSION_DEFAULTLOCATION_CHANGED = 19;
@ -92,8 +95,12 @@ public class DashChooseAppDirFragment {
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 "";
}

View file

@ -17,7 +17,7 @@ public class AbstractDownloadActivity extends ActionBarProgressActivity {
downloadValidationManager.startDownload(this, indexItem);
}
public void makeSureUserCancelDownload(IndexItem item) {
public void makeSureUserCancelDownload(DownloadItem item) {
downloadValidationManager.makeSureUserCancelDownload(this, item);
}
}

View file

@ -56,7 +56,8 @@ public class CustomIndexItem extends IndexItem {
}
@Override
public File getTargetFile(OsmandApplication ctx) {
@NonNull
public File getTargetFile(@NonNull OsmandApplication ctx) {
String basename = getTranslatedBasename();
if (!Algorithms.isEmpty(subfolder)) {
basename = subfolder + "/" + basename;

View file

@ -1,7 +1,6 @@
package net.osmand.plus.download;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@ -23,6 +22,8 @@ import android.widget.ProgressBar;
import android.widget.Space;
import android.widget.TextView;
import com.ibm.icu.impl.IllegalIcuArgumentException;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@ -654,9 +655,13 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
String size = "";
int percent = 0;
if (dir.canRead()) {
try {
StatFs fs = new StatFs(dir.getAbsolutePath());
size = AndroidUtils.formatSize(activity, ((long) fs.getAvailableBlocks()) * fs.getBlockSize());
percent = 100 - (int) ((long) fs.getAvailableBlocks() * 100 / fs.getBlockCount());
} catch (IllegalIcuArgumentException e) {
LOG.error(e);
}
}
sizeProgress.setIndeterminate(false);
sizeProgress.setProgress(percent);

View file

@ -2,6 +2,8 @@ package net.osmand.plus.download;
import android.content.Context;
import androidx.annotation.NonNull;
import net.osmand.AndroidUtils;
import net.osmand.IndexConstants;
import net.osmand.map.OsmandRegions;
@ -18,6 +20,7 @@ import java.io.IOException;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
@ -114,6 +117,10 @@ public class DownloadActivityType {
return byTag.get(tagName);
}
public static Collection<DownloadActivityType> values() {
return byTag.values();
}
protected static String addVersionToExt(String ext, int version) {
return "_" + version + ext;
}
@ -318,7 +325,7 @@ public class DownloadActivityType {
}
}
public String getVisibleDescription(IndexItem indexItem, Context ctx) {
public String getVisibleDescription(DownloadItem downloadItem, Context ctx) {
if (this == SRTM_COUNTRY_FILE) {
return ctx.getString(R.string.download_srtm_maps);
} else if (this == WIKIPEDIA_FILE) {
@ -337,20 +344,20 @@ public class DownloadActivityType {
return "";
}
public String getVisibleName(IndexItem indexItem, Context ctx, OsmandRegions osmandRegions, boolean includingParent) {
public String getVisibleName(DownloadItem downloadItem, Context ctx, OsmandRegions osmandRegions, boolean includingParent) {
if (this == VOICE_FILE) {
String fileName = indexItem.fileName;
String fileName = downloadItem.getFileName();
if (fileName.endsWith(IndexConstants.VOICE_INDEX_EXT_ZIP)) {
return FileNameTranslationHelper.getVoiceName(ctx, getBasename(indexItem));
return FileNameTranslationHelper.getVoiceName(ctx, getBasename(downloadItem));
} else if (fileName.endsWith(IndexConstants.TTSVOICE_INDEX_EXT_JS)) {
return FileNameTranslationHelper.getVoiceName(ctx, getBasename(indexItem));
return FileNameTranslationHelper.getVoiceName(ctx, getBasename(downloadItem));
}
return getBasename(indexItem);
return getBasename(downloadItem);
}
if (this == FONT_FILE) {
return FileNameTranslationHelper.getFontName(ctx, getBasename(indexItem));
return FileNameTranslationHelper.getFontName(ctx, getBasename(downloadItem));
}
final String basename = getBasename(indexItem);
final String basename = getBasename(downloadItem);
if (basename.endsWith(FileNameTranslationHelper.WIKI_NAME)) {
return FileNameTranslationHelper.getWikiName(ctx, basename);
}
@ -441,9 +448,11 @@ public class DownloadActivityType {
return fileName;
}
@NonNull
public String getBasename(@NonNull DownloadItem downloadItem) {
String fileName = downloadItem.getFileName();
if (Algorithms.isEmpty(fileName)) return fileName;
public String getBasename(IndexItem indexItem) {
String fileName = indexItem.fileName;
if (fileName.endsWith(IndexConstants.EXTRA_ZIP_EXT)) {
return fileName.substring(0, fileName.length() - IndexConstants.EXTRA_ZIP_EXT.length());
}
@ -458,7 +467,7 @@ public class DownloadActivityType {
if (fileName.endsWith(IndexConstants.SQLITE_EXT)) {
return fileName.substring(0, fileName.length() - IndexConstants.SQLITE_EXT.length());
}
if (indexItem.getType() == WIKIVOYAGE_FILE &&
if (downloadItem.getType() == WIKIVOYAGE_FILE &&
fileName.endsWith(IndexConstants.BINARY_WIKIVOYAGE_MAP_INDEX_EXT)) {
return fileName.substring(0, fileName.length() - IndexConstants.BINARY_WIKIVOYAGE_MAP_INDEX_EXT.length());
}

View file

@ -239,6 +239,16 @@ public class DownloadIndexesThread {
}
}
public void cancelDownload(DownloadItem item) {
if (item instanceof MultipleIndexItem) {
MultipleIndexItem multipleIndexItem = (MultipleIndexItem) item;
cancelDownload(multipleIndexItem.getAllIndexes());
} else if (item instanceof IndexItem) {
IndexItem indexItem = (IndexItem) item;
cancelDownload(indexItem);
}
}
public void cancelDownload(IndexItem item) {
app.logMapDownloadEvent("cancel", item);
if (currentDownloadingItem == item) {
@ -294,8 +304,12 @@ public class DownloadIndexesThread {
File dir = app.getAppPath("").getParentFile();
double asz = -1;
if (dir.canRead()) {
try {
StatFs fs = new StatFs(dir.getAbsolutePath());
asz = (((long) fs.getAvailableBlocks()) * fs.getBlockSize()) / (1 << 20);
} catch (IllegalArgumentException e) {
LOG.error(e);
}
}
return asz;
}

View file

@ -0,0 +1,81 @@
package net.osmand.plus.download;
import android.content.Context;
import androidx.annotation.NonNull;
import net.osmand.map.OsmandRegions;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import java.io.File;
import java.util.List;
import java.util.Locale;
public abstract class DownloadItem {
protected DownloadActivityType type;
protected DownloadResourceGroup relatedGroup;
public DownloadItem(DownloadActivityType type) {
this.type = type;
}
public DownloadActivityType getType() {
return type;
}
public void setRelatedGroup(DownloadResourceGroup relatedGroup) {
this.relatedGroup = relatedGroup;
}
public DownloadResourceGroup getRelatedGroup() {
return relatedGroup;
}
@NonNull
public String getSizeDescription(Context ctx) {
return getFormattedMb(ctx, getSizeToDownloadInMb());
}
public String getVisibleName(Context ctx, OsmandRegions osmandRegions) {
return type.getVisibleName(this, ctx, osmandRegions, true);
}
public String getVisibleName(Context ctx, OsmandRegions osmandRegions, boolean includingParent) {
return type.getVisibleName(this, ctx, osmandRegions, includingParent);
}
public String getVisibleDescription(OsmandApplication ctx) {
return type.getVisibleDescription(this, ctx);
}
@NonNull
public String getBasename() {
return type.getBasename(this);
}
protected abstract double getSizeToDownloadInMb();
public abstract double getArchiveSizeMB();
public abstract boolean isDownloaded();
public abstract boolean isOutdated();
public abstract boolean hasActualDataToDownload();
public abstract boolean isDownloading(@NonNull DownloadIndexesThread thread);
public abstract String getFileName();
@NonNull
public abstract List<File> getDownloadedFiles(@NonNull OsmandApplication app);
@NonNull
public static String getFormattedMb(@NonNull Context ctx, double sizeInMb) {
String size = String.format(Locale.US, "%.2f", sizeInMb);
return ctx.getString(R.string.ltr_or_rtl_combine_via_space, size, "MB");
}
}

View file

@ -8,6 +8,7 @@ import net.osmand.map.OsmandRegions;
import net.osmand.map.WorldRegion;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.util.Algorithms;
import java.util.ArrayList;
import java.util.Collections;
@ -20,8 +21,8 @@ public class DownloadResourceGroup {
private final DownloadResourceGroupType type;
private final DownloadResourceGroup parentGroup;
// ASSERT: individualResources are not empty if and only if groups are empty
private final List<IndexItem> individualResources;
// ASSERT: individualDownloadItems are not empty if and only if groups are empty
private final List<DownloadItem> individualDownloadItems;
private final List<DownloadResourceGroup> groups;
protected final String id;
@ -107,10 +108,10 @@ public class DownloadResourceGroup {
public DownloadResourceGroup(DownloadResourceGroup parentGroup, DownloadResourceGroupType type, String id) {
boolean flat = type.containsIndexItem();
if (flat) {
this.individualResources = new ArrayList<IndexItem>();
this.individualDownloadItems = new ArrayList<DownloadItem>();
this.groups = null;
} else {
this.individualResources = null;
this.individualDownloadItems = null;
this.groups = new ArrayList<DownloadResourceGroup>();
}
this.id = id;
@ -173,7 +174,7 @@ public class DownloadResourceGroup {
DownloadResourceGroup regionMaps = getSubGroupById(DownloadResourceGroupType.REGION_MAPS.getDefaultId());
if(regionMaps != null && regionMaps.size() == 1 && parentGroup != null && parentGroup.getParentGroup() != null &&
isEmpty(getSubGroupById(DownloadResourceGroupType.SUBREGIONS.getDefaultId()))) {
IndexItem item = regionMaps.individualResources.get(0);
IndexItem item = regionMaps.getIndividualResources().get(0);
DownloadResourceGroup screenParent = parentGroup.getParentGroup();
if(item.getType() == DownloadActivityType.HILLSHADE_FILE) {
DownloadResourceGroup hillshades =
@ -183,7 +184,7 @@ public class DownloadResourceGroup {
screenParent.addGroup(hillshades);
}
hillshades.addItem(item);
regionMaps.individualResources.remove(0);
regionMaps.individualDownloadItems.remove(0);
} else if (item.getType() == DownloadActivityType.SRTM_COUNTRY_FILE) {
DownloadResourceGroup hillshades = screenParent
.getSubGroupById(DownloadResourceGroupType.SRTM_HEADER.getDefaultId());
@ -192,7 +193,7 @@ public class DownloadResourceGroup {
screenParent.addGroup(hillshades);
}
hillshades.addItem(item);
regionMaps.individualResources.remove(0);
regionMaps.individualDownloadItems.remove(0);
}
}
@ -221,35 +222,38 @@ public class DownloadResourceGroup {
}
}
groups.add(g);
if (g.individualResources != null) {
sortDownloadItems(g.individualDownloadItems);
}
protected void sortDownloadItems(List<DownloadItem> items) {
if (Algorithms.isEmpty(items)) return;
final net.osmand.Collator collator = OsmAndCollator.primaryCollator();
final OsmandApplication app = getRoot().app;
final OsmandRegions osmandRegions = app.getRegions();
Collections.sort(g.individualResources, new Comparator<IndexItem>() {
Collections.sort(items, new Comparator<DownloadItem>() {
@Override
public int compare(IndexItem lhs, IndexItem rhs) {
int lli = lhs.getType().getOrderIndex();
int rri = rhs.getType().getOrderIndex();
if(lli < rri) {
public int compare(DownloadItem firstItem, DownloadItem secondItem) {
int firstOrder = firstItem.getType().getOrderIndex();
int secondOrder = secondItem.getType().getOrderIndex();
if(firstOrder < secondOrder) {
return -1;
} else if(lli > rri) {
} else if(firstOrder > secondOrder) {
return 1;
}
return collator.compare(lhs.getVisibleName(app.getApplicationContext(), osmandRegions),
rhs.getVisibleName(app.getApplicationContext(), osmandRegions));
String firstName = firstItem.getVisibleName(app, osmandRegions);
String secondName = secondItem.getVisibleName(app, osmandRegions);
return collator.compare(firstName, secondName);
}
});
}
}
public void addItem(IndexItem i) {
public void addItem(DownloadItem i) {
i.setRelatedGroup(this);
individualResources.add(i);
individualDownloadItems.add(i);
}
public boolean isEmpty() {
return isEmpty(individualResources) && isEmpty(groups);
return isEmpty(individualDownloadItems) && isEmpty(groups);
}
private boolean isEmpty(List<?> l) {
@ -265,7 +269,7 @@ public class DownloadResourceGroup {
}
public int size() {
return groups != null ? groups.size() : individualResources.size();
return groups != null ? groups.size() : individualDownloadItems.size();
}
public DownloadResourceGroup getGroupByIndex(int ind) {
@ -275,9 +279,9 @@ public class DownloadResourceGroup {
return null;
}
public IndexItem getItemByIndex(int ind) {
if (individualResources != null && ind >= 0 && ind < individualResources.size()) {
return individualResources.get(ind);
public DownloadItem getItemByIndex(int ind) {
if (individualDownloadItems != null && ind >= 0 && ind < individualDownloadItems.size()) {
return individualDownloadItems.get(ind);
}
return null;
}
@ -306,9 +310,21 @@ public class DownloadResourceGroup {
}
public List<IndexItem> getIndividualResources() {
List<IndexItem> individualResources = new ArrayList<>();
if (individualDownloadItems != null) {
for (DownloadItem item : individualDownloadItems) {
if (item instanceof IndexItem) {
individualResources.add((IndexItem) item);
}
}
}
return individualResources;
}
public List<DownloadItem> getIndividualDownloadItems() {
return individualDownloadItems;
}
public WorldRegion getRegion() {
return region;
}

View file

@ -25,10 +25,14 @@ import java.io.InputStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static net.osmand.plus.download.DownloadResourceGroup.DownloadResourceGroupType.REGION_MAPS;
public class DownloadResources extends DownloadResourceGroup {
private static final String TAG = DownloadResources.class.getSimpleName();
@ -337,7 +341,7 @@ public class DownloadResources extends DownloadResourceGroup {
DownloadResourceGroup wikivoyageMapsScreen = new DownloadResourceGroup(wikivoyageMapsGroup, DownloadResourceGroupType.WIKIVOYAGE_MAPS);
DownloadResourceGroup wikivoyageMaps = new DownloadResourceGroup(wikivoyageMapsGroup, DownloadResourceGroupType.WIKIVOYAGE_HEADER);
Map<WorldRegion, List<IndexItem> > groupByRegion = new LinkedHashMap<WorldRegion, List<IndexItem>>();
Map<WorldRegion, List<IndexItem>> groupByRegion = new LinkedHashMap<>();
OsmandRegions regs = app.getRegions();
for (IndexItem ii : resources) {
if (ii.getType() == DownloadActivityType.VOICE_FILE) {
@ -416,12 +420,14 @@ public class DownloadResources extends DownloadResourceGroup {
mainGrp.region = reg;
parentGroup.addGroup(mainGrp);
DownloadResourceGroup flatFiles = new DownloadResourceGroup(mainGrp, REGION_MAPS);
List<IndexItem> list = groupByRegion.get(reg);
if (list != null) {
DownloadResourceGroup flatFiles = new DownloadResourceGroup(mainGrp, DownloadResourceGroupType.REGION_MAPS);
for (IndexItem ii : list) {
flatFiles.addItem(ii);
}
}
if (list != null || !reg.isContinent()) {
mainGrp.addGroup(flatFiles);
}
DownloadResourceGroup subRegions = new DownloadResourceGroup(mainGrp, DownloadResourceGroupType.SUBREGIONS);
@ -465,11 +471,91 @@ public class DownloadResources extends DownloadResourceGroup {
addGroup(otherGroup);
createHillshadeSRTMGroups();
collectMultipleIndexesItems();
trimEmptyGroups();
updateLoadedFiles();
return true;
}
private void collectMultipleIndexesItems() {
collectMultipleIndexesItems(region);
}
private void collectMultipleIndexesItems(@NonNull WorldRegion region) {
List<WorldRegion> subRegions = region.getSubregions();
if (Algorithms.isEmpty(subRegions)) return;
DownloadResourceGroup group = getRegionMapsGroup(region);
if (group != null) {
boolean listModified = false;
List<IndexItem> indexesList = group.getIndividualResources();
List<WorldRegion> regionsToCollect = removeDuplicateRegions(subRegions);
for (DownloadActivityType type : DownloadActivityType.values()) {
if (!doesListContainIndexWithType(indexesList, type)) {
List<IndexItem> indexesFromSubRegions = collectIndexesOfType(regionsToCollect, type);
if (indexesFromSubRegions != null) {
group.addItem(new MultipleIndexItem(region, indexesFromSubRegions, type));
listModified = true;
}
}
}
if (listModified) {
sortDownloadItems(group.getIndividualDownloadItems());
}
}
for (WorldRegion subRegion : subRegions) {
collectMultipleIndexesItems(subRegion);
}
}
private DownloadResourceGroup getRegionMapsGroup(WorldRegion region) {
DownloadResourceGroup group = getRegionGroup(region);
if (group != null) {
return group.getSubGroupById(REGION_MAPS.getDefaultId());
}
return null;
}
@Nullable
private List<IndexItem> collectIndexesOfType(@NonNull List<WorldRegion> regions,
@NonNull DownloadActivityType type) {
List<IndexItem> collectedIndexes = new ArrayList<>();
for (WorldRegion region : regions) {
List<IndexItem> regionIndexes = getIndexItems(region);
boolean found = false;
if (regionIndexes != null) {
for (IndexItem index : regionIndexes) {
if (index.getType() == type) {
found = true;
collectedIndexes.add(index);
break;
}
}
}
if (!found) return null;
}
return collectedIndexes;
}
private List<WorldRegion> removeDuplicateRegions(List<WorldRegion> regions) {
Set<WorldRegion> duplicates = new HashSet<>();
for (int i = 0; i < regions.size() - 1; i++) {
WorldRegion r1 = regions.get(i);
for (int j = i + 1; j < regions.size(); j++) {
WorldRegion r2 = regions.get(j);
if (r1.containsRegion(r2)) {
duplicates.add(r2);
} else if (r2.containsRegion(r1)) {
duplicates.add(r1);
}
}
}
for (WorldRegion region : duplicates) {
regions.remove(region);
}
return regions;
}
private void buildRegionsGroups(WorldRegion region, DownloadResourceGroup group) {
LinkedList<WorldRegion> queue = new LinkedList<WorldRegion>();
LinkedList<DownloadResourceGroup> parent = new LinkedList<DownloadResourceGroup>();
@ -487,7 +573,7 @@ public class DownloadResources extends DownloadResourceGroup {
CustomRegion customRegion = (CustomRegion) reg;
List<IndexItem> indexItems = customRegion.loadIndexItems();
if (!Algorithms.isEmpty(indexItems)) {
DownloadResourceGroup flatFiles = new DownloadResourceGroup(mainGrp, DownloadResourceGroupType.REGION_MAPS);
DownloadResourceGroup flatFiles = new DownloadResourceGroup(mainGrp, REGION_MAPS);
for (IndexItem ii : indexItems) {
flatFiles.addItem(ii);
}
@ -559,7 +645,11 @@ public class DownloadResources extends DownloadResourceGroup {
return res;
}
public static List<IndexItem> findIndexItemsAt(OsmandApplication app, List<String> names, DownloadActivityType type, boolean includeDownloaded, int limit) {
public static List<IndexItem> findIndexItemsAt(OsmandApplication app,
List<String> names,
DownloadActivityType type,
boolean includeDownloaded,
int limit) {
List<IndexItem> res = new ArrayList<>();
OsmandRegions regions = app.getRegions();
DownloadIndexesThread downloadThread = app.getDownloadThread();
@ -575,8 +665,12 @@ public class DownloadResources extends DownloadResourceGroup {
return res;
}
private static boolean isIndexItemDownloaded(DownloadIndexesThread downloadThread, DownloadActivityType type, WorldRegion downloadRegion, List<IndexItem> res) {
List<IndexItem> otherIndexItems = new ArrayList<>(downloadThread.getIndexes().getIndexItems(downloadRegion));
private static boolean isIndexItemDownloaded(DownloadIndexesThread downloadThread,
DownloadActivityType type,
WorldRegion downloadRegion,
List<IndexItem> res) {
List<IndexItem> otherIndexItems =
new ArrayList<>(downloadThread.getIndexes().getIndexItems(downloadRegion));
for (IndexItem indexItem : otherIndexItems) {
if (indexItem.getType() == type && indexItem.isDownloaded()) {
return true;
@ -586,8 +680,24 @@ public class DownloadResources extends DownloadResourceGroup {
&& isIndexItemDownloaded(downloadThread, type, downloadRegion.getSuperregion(), res);
}
private static boolean addIndexItem(DownloadIndexesThread downloadThread, DownloadActivityType type, WorldRegion downloadRegion, List<IndexItem> res) {
List<IndexItem> otherIndexItems = new ArrayList<>(downloadThread.getIndexes().getIndexItems(downloadRegion));
private boolean doesListContainIndexWithType(List<IndexItem> indexItems,
DownloadActivityType type) {
if (indexItems != null) {
for (IndexItem indexItem : indexItems) {
if (indexItem.getType() == type) {
return true;
}
}
}
return false;
}
private static boolean addIndexItem(DownloadIndexesThread downloadThread,
DownloadActivityType type,
WorldRegion downloadRegion,
List<IndexItem> res) {
List<IndexItem> otherIndexItems =
new ArrayList<>(downloadThread.getIndexes().getIndexItems(downloadRegion));
for (IndexItem indexItem : otherIndexItems) {
if (indexItem.getType() == type
&& !res.contains(indexItem)) {

View file

@ -192,7 +192,7 @@ public class DownloadValidationManager {
}
public void makeSureUserCancelDownload(FragmentActivity ctx, final IndexItem item) {
public void makeSureUserCancelDownload(FragmentActivity ctx, final DownloadItem item) {
AlertDialog.Builder bld = new AlertDialog.Builder(ctx);
bld.setTitle(ctx.getString(R.string.shared_string_cancel));
bld.setMessage(R.string.confirm_interrupt_download);

View file

@ -1,24 +1,24 @@
package net.osmand.plus.download;
import android.content.Context;
import androidx.annotation.NonNull;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.map.OsmandRegions;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.helpers.FileNameTranslationHelper;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.List;
public class IndexItem implements Comparable<IndexItem> {
public class IndexItem extends DownloadItem implements Comparable<IndexItem> {
private static final Log log = PlatformUtil.getLog(IndexItem.class);
String description;
@ -27,43 +27,43 @@ public class IndexItem implements Comparable<IndexItem> {
long timestamp;
long contentSize;
long containerSize;
DownloadActivityType type;
boolean extra;
// Update information
boolean outdated;
boolean downloaded;
long localTimestamp;
DownloadResourceGroup relatedGroup;
public IndexItem(String fileName, String description, long timestamp, String size, long contentSize,
long containerSize, @NonNull DownloadActivityType tp) {
public IndexItem(String fileName,
String description,
long timestamp,
String size,
long contentSize,
long containerSize,
@NonNull DownloadActivityType type) {
super(type);
this.fileName = fileName;
this.description = description;
this.timestamp = timestamp;
this.size = size;
this.contentSize = contentSize;
this.containerSize = containerSize;
this.type = tp;
}
public DownloadActivityType getType() {
return type;
}
public void setRelatedGroup(DownloadResourceGroup relatedGroup) {
this.relatedGroup = relatedGroup;
}
public DownloadResourceGroup getRelatedGroup() {
return relatedGroup;
}
@Override
public String getFileName() {
return fileName;
}
@NonNull
@Override
public List<File> getDownloadedFiles(@NonNull OsmandApplication app) {
File targetFile = getTargetFile(app);
if (targetFile.exists()) {
return Collections.singletonList(targetFile);
}
return Collections.emptyList();
}
public String getDescription() {
return description;
@ -89,11 +89,11 @@ public class IndexItem implements Comparable<IndexItem> {
return ((double)containerSize) / (1 << 20);
}
public String getSizeDescription(Context ctx) {
return ctx.getString(R.string.ltr_or_rtl_combine_via_space, size, "MB");
@Override
protected double getSizeToDownloadInMb() {
return Algorithms.parseDoubleSilently(size, 0.0);
}
public DownloadEntry createDownloadEntry(OsmandApplication ctx) {
String fileName = this.fileName;
File parent = type.getDownloadFolder(ctx, this);
@ -132,11 +132,8 @@ public class IndexItem implements Comparable<IndexItem> {
return type.getTargetFileName(this);
}
public String getBasename() {
return type.getBasename(this);
}
public File getTargetFile(OsmandApplication ctx) {
@NonNull
public File getTargetFile(@NonNull OsmandApplication ctx) {
String basename = getTranslatedBasename();
return new File(type.getDownloadFolder(ctx, this), basename + type.getUnzipExtension(ctx, this));
}
@ -170,6 +167,10 @@ public class IndexItem implements Comparable<IndexItem> {
return "";
}
public String getDate(@NonNull DateFormat dateFormat, boolean remote) {
return remote ? getRemoteDate(dateFormat) : getLocalDate(dateFormat);
}
public String getRemoteDate(DateFormat dateFormat) {
if(timestamp <= 0) {
return "";
@ -178,7 +179,7 @@ public class IndexItem implements Comparable<IndexItem> {
}
public String getLocalDate(DateFormat dateFormat) {
private String getLocalDate(@NonNull DateFormat dateFormat) {
if(localTimestamp <= 0) {
return "";
}
@ -199,6 +200,11 @@ public class IndexItem implements Comparable<IndexItem> {
this.downloaded = downloaded;
}
@Override
public boolean hasActualDataToDownload() {
return !isDownloaded() || isOutdated();
}
public void setLocalTimestamp(long localTimestamp) {
this.localTimestamp = localTimestamp;
}
@ -211,20 +217,11 @@ public class IndexItem implements Comparable<IndexItem> {
return downloaded;
}
public String getVisibleName(Context ctx, OsmandRegions osmandRegions) {
return type.getVisibleName(this, ctx, osmandRegions, true);
@Override
public boolean isDownloading(@NonNull DownloadIndexesThread thread) {
return thread.isDownloading(this);
}
public String getVisibleName(Context ctx, OsmandRegions osmandRegions, boolean includingParent) {
return type.getVisibleName(this, ctx, osmandRegions, includingParent);
}
public String getVisibleDescription(OsmandApplication clctx) {
return type.getVisibleDescription(this, clctx);
}
public String getDate(java.text.DateFormat format) {
return format.format(new Date(timestamp));
}

View file

@ -0,0 +1,122 @@
package net.osmand.plus.download;
import androidx.annotation.NonNull;
import net.osmand.map.WorldRegion;
import net.osmand.plus.OsmandApplication;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class MultipleIndexItem extends DownloadItem {
private final List<IndexItem> items;
public MultipleIndexItem(@NonNull WorldRegion region,
@NonNull List<IndexItem> items,
@NonNull DownloadActivityType type) {
super(type);
this.items = items;
}
public List<IndexItem> getAllIndexes() {
return items;
}
@Override
public boolean isOutdated() {
for (IndexItem item : items) {
if (item.isOutdated()) {
return true;
}
}
return false;
}
@Override
public boolean isDownloaded() {
for (IndexItem item : items) {
if (item.isDownloaded()) {
return true;
}
}
return false;
}
@Override
public boolean isDownloading(@NonNull DownloadIndexesThread thread) {
for (IndexItem item : items) {
if (thread.isDownloading(item)) {
return true;
}
}
return false;
}
@Override
public String getFileName() {
// The file name is used in many places.
// But in the case of a Multiple Indexes element it's not use in most cases.
// File is not created for Multiple Indexes element,
// and all file names are available in internal IndexItem elements.
// The only one place where a filename may be needed
// is to generate the base and display names.
// Since these names are generated based on the filename.
// But now we don't need a name for display,
// because on all screens where we now use multiple elements item,
// for display used a type name instead of a file name.
// Later, if you need a file name,
// you can try to create it based on the WorldRegion
// and file name of one of the internal IndexItem elements.
return "";
}
@NonNull
@Override
public List<File> getDownloadedFiles(@NonNull OsmandApplication app) {
List<File> result = new ArrayList<>();
for (IndexItem item : items) {
result.addAll(item.getDownloadedFiles(app));
}
return result;
}
public List<IndexItem> getIndexesToDownload() {
List<IndexItem> indexesToDownload = new ArrayList<>();
for (IndexItem item : items) {
if (item.hasActualDataToDownload()) {
indexesToDownload.add(item);
}
}
return indexesToDownload;
}
@Override
public boolean hasActualDataToDownload() {
return getIndexesToDownload().size() > 0;
}
@Override
public double getSizeToDownloadInMb() {
double totalSizeMb = 0.0d;
for (IndexItem item : items) {
if (item.hasActualDataToDownload()) {
totalSizeMb += item.getSizeToDownloadInMb();
}
}
return totalSizeMb;
}
@Override
public double getArchiveSizeMB() {
double result = 0.0d;
for (IndexItem item : items) {
result += item.getArchiveSizeMB();
}
return result;
}
}

View file

@ -0,0 +1,113 @@
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

@ -17,12 +17,15 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.ibm.icu.impl.IllegalIcuArgumentException;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentManager;
import net.osmand.AndroidUtils;
import net.osmand.FileUtils;
import net.osmand.IProgress;
import net.osmand.PlatformUtil;
import net.osmand.plus.OnDismissDialogFragmentListener;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.settings.backend.OsmandSettings;
@ -32,9 +35,12 @@ import net.osmand.plus.dashboard.DashChooseAppDirFragment;
import net.osmand.plus.download.DownloadActivity;
import net.osmand.plus.download.DownloadIndexesThread;
import org.apache.commons.logging.Log;
import java.io.File;
public class DataStoragePlaceDialogFragment extends BottomSheetDialogFragment {
private static final Log LOG = PlatformUtil.getLog(DataStoragePlaceDialogFragment.class);
public static final String TAG = "DataStoragePlaceDialogFragment";
private static final String STORAGE_READOLNY_KEY = "storage_readolny_key";
@ -189,12 +195,16 @@ public class DataStoragePlaceDialogFragment extends BottomSheetDialogFragment {
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;
}

View file

@ -10,9 +10,9 @@ import android.widget.TextView;
import net.osmand.plus.R;
import net.osmand.plus.activities.OsmandBaseExpandableListAdapter;
import net.osmand.plus.download.CustomIndexItem;
import net.osmand.plus.download.DownloadItem;
import net.osmand.plus.download.DownloadActivity;
import net.osmand.plus.download.DownloadResourceGroup;
import net.osmand.plus.download.IndexItem;
import java.util.ArrayList;
import java.util.List;
@ -52,9 +52,9 @@ public class DownloadResourceGroupAdapter extends OsmandBaseExpandableListAdapte
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
final Object child = getChild(groupPosition, childPosition);
if (child instanceof IndexItem) {
if (child instanceof DownloadItem) {
IndexItem item = (IndexItem) child;
DownloadItem item = (DownloadItem) child;
DownloadResourceGroup group = getGroupObj(groupPosition);
ItemViewHolder viewHolder;
if (convertView != null && convertView.getTag() instanceof ItemViewHolder) {

View file

@ -35,6 +35,7 @@ import net.osmand.plus.download.DownloadActivity;
import net.osmand.plus.download.DownloadActivity.BannerAndDownloadFreeVersion;
import net.osmand.plus.download.DownloadActivityType;
import net.osmand.plus.download.DownloadIndexesThread.DownloadEvents;
import net.osmand.plus.download.DownloadItem;
import net.osmand.plus.download.DownloadResourceGroup;
import net.osmand.plus.download.DownloadResources;
import net.osmand.plus.download.DownloadValidationManager;
@ -504,10 +505,10 @@ public class DownloadResourceGroupFragment extends DialogFragment implements Dow
DownloadItemFragment downloadItemFragment = DownloadItemFragment.createInstance(regionId, childPosition);
((DownloadActivity) getActivity()).showDialog(getActivity(), downloadItemFragment);
} else if (child instanceof IndexItem) {
IndexItem indexItem = (IndexItem) child;
} else if (child instanceof DownloadItem) {
DownloadItem downloadItem = (DownloadItem) child;
ItemViewHolder vh = (ItemViewHolder) v.getTag();
OnClickListener ls = vh.getRightButtonAction(indexItem, vh.getClickAction(indexItem));
OnClickListener ls = vh.getRightButtonAction(downloadItem, vh.getClickAction(downloadItem));
ls.onClick(v);
return true;
}

View file

@ -17,11 +17,14 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.PopupMenu;
import androidx.core.view.ViewCompat;
import net.osmand.map.OsmandRegions;
import net.osmand.map.WorldRegion;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.Version;
import net.osmand.plus.activities.LocalIndexHelper.LocalIndexType;
@ -31,11 +34,15 @@ import net.osmand.plus.activities.PluginsFragment;
import net.osmand.plus.chooseplan.ChoosePlanDialogFragment;
import net.osmand.plus.download.CityItem;
import net.osmand.plus.download.CustomIndexItem;
import net.osmand.plus.download.DownloadItem;
import net.osmand.plus.download.DownloadActivity;
import net.osmand.plus.download.DownloadActivityType;
import net.osmand.plus.download.DownloadResourceGroup;
import net.osmand.plus.download.DownloadResources;
import net.osmand.plus.download.IndexItem;
import net.osmand.plus.download.MultipleIndexesUiHelper;
import net.osmand.plus.download.MultipleIndexesUiHelper.SelectItemsToDownloadListener;
import net.osmand.plus.download.MultipleIndexItem;
import net.osmand.plus.download.ui.LocalIndexesFragment.LocalIndexOperationTask;
import net.osmand.plus.helpers.FileNameTranslationHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper;
@ -43,6 +50,7 @@ import net.osmand.util.Algorithms;
import java.io.File;
import java.text.DateFormat;
import java.util.List;
public class ItemViewHolder {
@ -137,24 +145,24 @@ public class ItemViewHolder {
depthContoursPurchased = InAppPurchaseHelper.isDepthContoursPurchased(context.getMyApplication());
}
public void bindIndexItem(final IndexItem indexItem) {
bindIndexItem(indexItem, null);
public void bindIndexItem(final DownloadItem downloadItem) {
bindIndexItem(downloadItem, null);
}
public void bindIndexItem(final IndexItem indexItem, final String cityName) {
public void bindIndexItem(final DownloadItem downloadItem, final String cityName) {
initAppStatusVariables();
boolean isDownloading = context.getDownloadThread().isDownloading(indexItem);
boolean isDownloading = downloadItem.isDownloading(context.getDownloadThread());
int progress = -1;
if (context.getDownloadThread().getCurrentDownloadingItem() == indexItem) {
if (context.getDownloadThread().getCurrentDownloadingItem() == downloadItem) {
progress = context.getDownloadThread().getCurrentDownloadingItemProgress();
}
boolean disabled = checkDisabledAndClickAction(indexItem);
boolean disabled = checkDisabledAndClickAction(downloadItem);
/// name and left item
String name;
if(showTypeInName) {
name = indexItem.getType().getString(context);
name = downloadItem.getType().getString(context);
} else {
name = indexItem.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;
nameTextView.setText(text);
@ -164,43 +172,78 @@ public class ItemViewHolder {
nameTextView.setTextColor(textColorSecondary);
}
int color = textColorSecondary;
if(indexItem.isDownloaded() && !isDownloading) {
int colorId = indexItem.isOutdated() ? R.color.color_distance : R.color.color_ok;
if(downloadItem.isDownloaded() && !isDownloading) {
int colorId = downloadItem.isOutdated() ? R.color.color_distance : R.color.color_ok;
color = context.getResources().getColor(colorId);
}
if (indexItem.isDownloaded()) {
if (downloadItem.isDownloaded()) {
leftImageView.setImageDrawable(getContentIcon(context,
indexItem.getType().getIconResource(), color));
downloadItem.getType().getIconResource(), color));
} else if (disabled) {
leftImageView.setImageDrawable(getContentIcon(context,
indexItem.getType().getIconResource(), textColorSecondary));
downloadItem.getType().getIconResource(), textColorSecondary));
} else {
leftImageView.setImageDrawable(getContentIcon(context,
indexItem.getType().getIconResource()));
downloadItem.getType().getIconResource()));
}
descrTextView.setTextColor(textColorSecondary);
if (!isDownloading) {
progressBar.setVisibility(View.GONE);
descrTextView.setVisibility(View.VISIBLE);
if (indexItem instanceof CustomIndexItem && (((CustomIndexItem) indexItem).getSubName(context) != null)) {
descrTextView.setText(((CustomIndexItem) indexItem).getSubName(context));
} else if (indexItem.getType() == DownloadActivityType.DEPTH_CONTOUR_FILE && !depthContoursPurchased) {
if (downloadItem instanceof CustomIndexItem && (((CustomIndexItem) downloadItem).getSubName(context) != null)) {
descrTextView.setText(((CustomIndexItem) downloadItem).getSubName(context));
} else if (downloadItem.getType() == DownloadActivityType.DEPTH_CONTOUR_FILE && !depthContoursPurchased) {
descrTextView.setText(context.getString(R.string.depth_contour_descr));
} else if ((indexItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE
|| indexItem.getType() == DownloadActivityType.HILLSHADE_FILE
|| indexItem.getType() == DownloadActivityType.SLOPE_FILE) && srtmDisabled) {
} else if ((downloadItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE
|| downloadItem.getType() == DownloadActivityType.HILLSHADE_FILE
|| downloadItem.getType() == DownloadActivityType.SLOPE_FILE) && srtmDisabled) {
if (showTypeInName) {
descrTextView.setText("");
} else {
descrTextView.setText(indexItem.getType().getString(context));
descrTextView.setText(downloadItem.getType().getString(context));
}
} else if (showTypeInDesc) {
descrTextView.setText(indexItem.getType().getString(context) +
"" + indexItem.getSizeDescription(context) +
"" + (showRemoteDate ? indexItem.getRemoteDate(dateFormat) : indexItem.getLocalDate(dateFormat)));
} else if (downloadItem instanceof MultipleIndexItem) {
MultipleIndexItem item = (MultipleIndexItem) downloadItem;
String allRegionsHeader = context.getString(R.string.shared_strings_all_regions);
String regionsHeader = context.getString(R.string.regions);
String allRegionsCount = String.valueOf(item.getAllIndexes().size());
String leftToDownloadCount = String.valueOf(item.getIndexesToDownload().size());
String header;
String count;
if (item.hasActualDataToDownload()) {
if (!item.isDownloaded()) {
header = allRegionsHeader;
count = leftToDownloadCount;
} else {
descrTextView.setText(indexItem.getSizeDescription(context) + "" +
(showRemoteDate ? indexItem.getRemoteDate(dateFormat) : indexItem.getLocalDate(dateFormat)));
header = regionsHeader;
count = String.format(
context.getString(R.string.ltr_or_rtl_combine_via_slash),
leftToDownloadCount,
allRegionsCount);
}
} else {
header = allRegionsHeader;
count = allRegionsCount;
}
String fullDescription =
context.getString(R.string.ltr_or_rtl_combine_via_colon, header, count);
if (item.hasActualDataToDownload()) {
fullDescription = context.getString(
R.string.ltr_or_rtl_combine_via_bold_point, fullDescription,
item.getSizeDescription(context));
}
descrTextView.setText(fullDescription);
} else {
IndexItem item = (IndexItem) downloadItem;
String pattern = context.getString(R.string.ltr_or_rtl_combine_via_bold_point);
String type = item.getType().getString(context);
String size = item.getSizeDescription(context);
String date = item.getDate(dateFormat, showRemoteDate);
String fullDescription = String.format(pattern, size, date);
if (showTypeInDesc) {
fullDescription = String.format(pattern, type, fullDescription);
}
descrTextView.setText(fullDescription);
}
} else {
@ -209,18 +252,19 @@ public class ItemViewHolder {
progressBar.setProgress(progress);
if (showProgressInDesc) {
double mb = indexItem.getArchiveSizeMB();
double mb = downloadItem.getArchiveSizeMB();
String v ;
if (progress != -1) {
v = context.getString(R.string.value_downloaded_of_max, mb * progress / 100, mb);
} else {
v = context.getString(R.string.file_size_in_mb, mb);
}
if(showTypeInDesc && indexItem.getType() == DownloadActivityType.ROADS_FILE) {
descrTextView.setText(indexItem.getType().getString(context) + "" + v);
} else {
descrTextView.setText(v);
String fullDescription = v;
if(showTypeInDesc && downloadItem.getType() == DownloadActivityType.ROADS_FILE) {
fullDescription = context.getString(R.string.ltr_or_rtl_combine_via_bold_point,
downloadItem.getType().getString(context), fullDescription);
}
descrTextView.setText(fullDescription);
descrTextView.setVisibility(View.VISIBLE);
} else {
descrTextView.setVisibility(View.GONE);
@ -241,44 +285,7 @@ public class ItemViewHolder {
}
}
protected void download(IndexItem indexItem, DownloadResourceGroup parentOptional) {
boolean handled = false;
if(parentOptional != null) {
WorldRegion region = DownloadResourceGroup.getRegion(parentOptional);
context.setDownloadItem(region, indexItem.getTargetFile(context.getMyApplication()).getAbsolutePath());
}
if (indexItem.getType() == DownloadActivityType.ROADS_FILE && parentOptional != null) {
for (IndexItem ii : parentOptional.getIndividualResources()) {
if (ii.getType() == DownloadActivityType.NORMAL_FILE) {
if (ii.isDownloaded()) {
handled = true;
confirmDownload(indexItem);
}
break;
}
}
}
if(!handled) {
context.startDownload(indexItem);
}
}
private void confirmDownload(final IndexItem indexItem) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.are_you_sure);
builder.setMessage(R.string.confirm_download_roadmaps);
builder.setNegativeButton(R.string.shared_string_cancel, null).setPositiveButton(
R.string.shared_string_download, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (indexItem != null) {
context.startDownload(indexItem);
}
}
});
builder.show();
}
private boolean checkDisabledAndClickAction(final IndexItem item) {
private boolean checkDisabledAndClickAction(final DownloadItem item) {
RightButtonAction clickAction = getClickAction(item);
boolean disabled = clickAction != RightButtonAction.DOWNLOAD;
OnClickListener action = getRightButtonAction(item, clickAction);
@ -290,15 +297,15 @@ public class ItemViewHolder {
} else {
rightButton.setVisibility(View.GONE);
rightImageButton.setVisibility(View.VISIBLE);
final boolean isDownloading = context.getDownloadThread().isDownloading(item);
final boolean isDownloading = item.isDownloading(context.getDownloadThread());
if (isDownloading) {
rightImageButton.setImageDrawable(getContentIcon(context, R.drawable.ic_action_remove_dark));
rightImageButton.setContentDescription(context.getString(R.string.shared_string_cancel));
} else if(item.isDownloaded() && !item.isOutdated()) {
} else if(!item.hasActualDataToDownload()) {
rightImageButton.setImageDrawable(getContentIcon(context, R.drawable.ic_overflow_menu_white));
rightImageButton.setContentDescription(context.getString(R.string.shared_string_more));
} else {
rightImageButton.setImageDrawable(getContentIcon(context, R.drawable.ic_action_import));
rightImageButton.setImageDrawable(getContentIcon(context, getDownloadActionIconId(item)));
rightImageButton.setContentDescription(context.getString(R.string.shared_string_download));
}
rightImageButton.setOnClickListener(action);
@ -307,32 +314,38 @@ public class ItemViewHolder {
return disabled;
}
private int getDownloadActionIconId(@NonNull DownloadItem item) {
return item instanceof MultipleIndexItem ?
R.drawable.ic_action_multi_download :
R.drawable.ic_action_import;
}
@SuppressLint("DefaultLocale")
public RightButtonAction getClickAction(final IndexItem indexItem) {
public RightButtonAction getClickAction(final DownloadItem item) {
RightButtonAction clickAction = RightButtonAction.DOWNLOAD;
if (indexItem.getBasename().toLowerCase().equals(DownloadResources.WORLD_SEAMARKS_KEY)
if (item.getBasename().toLowerCase().equals(DownloadResources.WORLD_SEAMARKS_KEY)
&& nauticalPluginDisabled) {
clickAction = RightButtonAction.ASK_FOR_SEAMARKS_PLUGIN;
} else if ((indexItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE
|| indexItem.getType() == DownloadActivityType.HILLSHADE_FILE
|| indexItem.getType() == DownloadActivityType.SLOPE_FILE) && srtmDisabled) {
} else if ((item.getType() == DownloadActivityType.SRTM_COUNTRY_FILE
|| item.getType() == DownloadActivityType.HILLSHADE_FILE
|| item.getType() == DownloadActivityType.SLOPE_FILE) && srtmDisabled) {
if (srtmNeedsInstallation) {
clickAction = RightButtonAction.ASK_FOR_SRTM_PLUGIN_PURCHASE;
} else {
clickAction = RightButtonAction.ASK_FOR_SRTM_PLUGIN_ENABLE;
}
} else if ((indexItem.getType() == DownloadActivityType.WIKIPEDIA_FILE
|| indexItem.getType() == DownloadActivityType.TRAVEL_FILE)
} else if ((item.getType() == DownloadActivityType.WIKIPEDIA_FILE
|| item.getType() == DownloadActivityType.TRAVEL_FILE)
&& !Version.isPaidVersion(context.getMyApplication())) {
clickAction = RightButtonAction.ASK_FOR_FULL_VERSION_PURCHASE;
} else if (indexItem.getType() == DownloadActivityType.DEPTH_CONTOUR_FILE && !depthContoursPurchased) {
} else if (item.getType() == DownloadActivityType.DEPTH_CONTOUR_FILE && !depthContoursPurchased) {
clickAction = RightButtonAction.ASK_FOR_DEPTH_CONTOURS_PURCHASE;
}
return clickAction;
}
public OnClickListener getRightButtonAction(final IndexItem item, final RightButtonAction clickAction) {
public OnClickListener getRightButtonAction(final DownloadItem item, final RightButtonAction clickAction) {
if (clickAction != RightButtonAction.DOWNLOAD) {
return new View.OnClickListener() {
@Override
@ -371,7 +384,7 @@ public class ItemViewHolder {
}
};
} else {
final boolean isDownloading = context.getDownloadThread().isDownloading(item);
final boolean isDownloading = item.isDownloading(context.getDownloadThread());
return new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -381,8 +394,8 @@ public class ItemViewHolder {
} else {
context.makeSureUserCancelDownload(item);
}
} else if(item.isDownloaded() && !item.isOutdated()){
contextMenu(v, item, item.getRelatedGroup());
} else if(!item.hasActualDataToDownload()){
showContextMenu(v, item, item.getRelatedGroup());
} else {
download(item, item.getRelatedGroup());
}
@ -391,52 +404,21 @@ public class ItemViewHolder {
}
}
protected void contextMenu(View v, final IndexItem indexItem, final DownloadResourceGroup parentOptional) {
final PopupMenu optionsMenu = new PopupMenu(context, v);
protected void showContextMenu(View v,
final DownloadItem downloadItem,
final DownloadResourceGroup parentOptional) {
OsmandApplication app = context.getMyApplication();
PopupMenu optionsMenu = new PopupMenu(context, v);
MenuItem item;
final File fl = indexItem.getTargetFile(context.getMyApplication());
if (fl.exists()) {
item = optionsMenu.getMenu().add(R.string.shared_string_remove).setIcon(
context.getMyApplication().getUIUtilities().getThemedIcon(R.drawable.ic_action_remove_dark));
final List<File> downloadedFiles = downloadItem.getDownloadedFiles(app);
if (!Algorithms.isEmpty(downloadedFiles)) {
item = optionsMenu.getMenu().add(R.string.shared_string_remove)
.setIcon(getContentIcon(context, R.drawable.ic_action_remove_dark));
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
LocalIndexType tp = LocalIndexType.MAP_DATA;
if (indexItem.getType() == DownloadActivityType.HILLSHADE_FILE) {
tp = LocalIndexType.TILES_DATA;
} else if (indexItem.getType() == DownloadActivityType.SLOPE_FILE) {
tp = LocalIndexType.TILES_DATA;
} else if (indexItem.getType() == DownloadActivityType.ROADS_FILE) {
tp = LocalIndexType.MAP_DATA;
} else if (indexItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE) {
tp = LocalIndexType.SRTM_DATA;
} else if (indexItem.getType() == DownloadActivityType.WIKIPEDIA_FILE) {
tp = LocalIndexType.MAP_DATA;
} else if (indexItem.getType() == DownloadActivityType.WIKIVOYAGE_FILE) {
tp = LocalIndexType.MAP_DATA;
} else if (indexItem.getType() == DownloadActivityType.TRAVEL_FILE) {
tp = LocalIndexType.MAP_DATA;
} else if (indexItem.getType() == DownloadActivityType.FONT_FILE) {
tp = LocalIndexType.FONT_DATA;
} else if (indexItem.getType() == DownloadActivityType.VOICE_FILE) {
tp = indexItem.getBasename().contains("tts") ? LocalIndexType.TTS_VOICE_DATA
: LocalIndexType.VOICE_DATA;
}
final LocalIndexInfo info = new LocalIndexInfo(tp, fl, false, context.getMyApplication());
AlertDialog.Builder confirm = new AlertDialog.Builder(context);
confirm.setPositiveButton(R.string.shared_string_yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
new LocalIndexOperationTask(context, null, LocalIndexOperationTask.DELETE_OPERATION)
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, info);
}
});
confirm.setNegativeButton(R.string.shared_string_no, null);
String fn = FileNameTranslationHelper.getFileName(context, context.getMyApplication().getRegions(),
indexItem.getVisibleName(context, context.getMyApplication().getRegions()));
confirm.setMessage(context.getString(R.string.delete_confirmation_msg, fn));
confirm.show();
confirmRemove(downloadItem, downloadedFiles);
return true;
}
});
@ -446,7 +428,7 @@ public class ItemViewHolder {
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
download(indexItem, parentOptional);
download(downloadItem, parentOptional);
return true;
}
});
@ -454,6 +436,135 @@ public class ItemViewHolder {
optionsMenu.show();
}
protected void download(DownloadItem item, DownloadResourceGroup parentOptional) {
boolean handled = false;
if (parentOptional != null && item instanceof IndexItem) {
IndexItem indexItem = (IndexItem) item;
WorldRegion region = DownloadResourceGroup.getRegion(parentOptional);
context.setDownloadItem(region, indexItem.getTargetFile(context.getMyApplication()).getAbsolutePath());
}
if (item.getType() == DownloadActivityType.ROADS_FILE && parentOptional != null) {
for (IndexItem ii : parentOptional.getIndividualResources()) {
if (ii.getType() == DownloadActivityType.NORMAL_FILE) {
if (ii.isDownloaded()) {
handled = true;
confirmDownload(item);
}
break;
}
}
}
if(!handled) {
startDownload(item);
}
}
private void confirmDownload(final DownloadItem item) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.are_you_sure);
builder.setMessage(R.string.confirm_download_roadmaps);
builder.setNegativeButton(R.string.shared_string_cancel, null).setPositiveButton(
R.string.shared_string_download, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (item != null) {
startDownload(item);
}
}
});
builder.show();
}
private void startDownload(DownloadItem item) {
if (item instanceof MultipleIndexItem) {
selectIndexesToDownload((MultipleIndexItem) item);
} else if (item instanceof IndexItem) {
IndexItem indexItem = (IndexItem) item;
context.startDownload(indexItem);
}
}
private void selectIndexesToDownload(MultipleIndexItem item) {
OsmandApplication app = context.getMyApplication();
MultipleIndexesUiHelper.showDialog(item, context, app, dateFormat, showRemoteDate,
new SelectItemsToDownloadListener() {
@Override
public void onItemsToDownloadSelected(List<IndexItem> indexes) {
IndexItem[] indexesArray = new IndexItem[indexes.size()];
context.startDownload(indexes.toArray(indexesArray));
}
}
);
}
private void confirmRemove(@NonNull final DownloadItem downloadItem,
@NonNull final List<File> downloadedFiles) {
OsmandApplication app = context.getMyApplication();
AlertDialog.Builder confirm = new AlertDialog.Builder(context);
String message;
if (downloadedFiles.size() > 1) {
message = context.getString(R.string.delete_number_files_question, downloadedFiles.size());
} else {
OsmandRegions regions = app.getRegions();
String visibleName = downloadItem.getVisibleName(context, regions);
String fileName = FileNameTranslationHelper.getFileName(context, regions, visibleName);
message = context.getString(R.string.delete_confirmation_msg, fileName);
}
confirm.setMessage(message);
confirm.setPositiveButton(R.string.shared_string_yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
LocalIndexType type = getLocalIndexType(downloadItem);
remove(type, downloadedFiles);
}
});
confirm.setNegativeButton(R.string.shared_string_no, null);
confirm.show();
}
private void remove(@NonNull LocalIndexType type,
@NonNull List<File> filesToDelete) {
OsmandApplication app = context.getMyApplication();
LocalIndexOperationTask removeTask = new LocalIndexOperationTask(
context,
null,
LocalIndexOperationTask.DELETE_OPERATION);
LocalIndexInfo[] params = new LocalIndexInfo[filesToDelete.size()];
for (int i = 0; i < filesToDelete.size(); i++) {
File file = filesToDelete.get(i);
params[i] = new LocalIndexInfo(type, file, false, app);
}
removeTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
}
@NonNull
private LocalIndexType getLocalIndexType(@NonNull DownloadItem downloadItem) {
LocalIndexType type = LocalIndexType.MAP_DATA;
if (downloadItem.getType() == DownloadActivityType.HILLSHADE_FILE) {
type = LocalIndexType.TILES_DATA;
} else if (downloadItem.getType() == DownloadActivityType.SLOPE_FILE) {
type = LocalIndexType.TILES_DATA;
} else if (downloadItem.getType() == DownloadActivityType.ROADS_FILE) {
type = LocalIndexType.MAP_DATA;
} else if (downloadItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE) {
type = LocalIndexType.SRTM_DATA;
} else if (downloadItem.getType() == DownloadActivityType.WIKIPEDIA_FILE) {
type = LocalIndexType.MAP_DATA;
} else if (downloadItem.getType() == DownloadActivityType.WIKIVOYAGE_FILE) {
type = LocalIndexType.MAP_DATA;
} else if (downloadItem.getType() == DownloadActivityType.TRAVEL_FILE) {
type = LocalIndexType.MAP_DATA;
} else if (downloadItem.getType() == DownloadActivityType.FONT_FILE) {
type = LocalIndexType.FONT_DATA;
} else if (downloadItem.getType() == DownloadActivityType.VOICE_FILE) {
type = downloadItem.getBasename().contains("tts") ? LocalIndexType.TTS_VOICE_DATA
: LocalIndexType.VOICE_DATA;
}
return type;
}
private Drawable getContentIcon(DownloadActivity context, int resourceId) {
return context.getMyApplication().getUIUtilities().getThemedIcon(resourceId);
}

View file

@ -153,7 +153,8 @@ public class UpdatesIndexFragment extends OsmAndListFragment implements Download
for (IndexItem indexItem : indexItems) {
downloadsSize += indexItem.getSize();
}
String updateAllText = getActivity().getString(R.string.update_all, downloadsSize >> 20);
String updateAllText = getActivity().getString(
R.string.update_all, String.valueOf(downloadsSize >> 20));
updateAllButton.setText(updateAllText);
updateAllButton.setOnClickListener(new View.OnClickListener() {
@Override

View file

@ -26,6 +26,7 @@ import androidx.fragment.app.FragmentActivity;
import net.osmand.AndroidNetworkUtils;
import net.osmand.AndroidUtils;
import net.osmand.Location;
import net.osmand.PlatformUtil;
import net.osmand.ValueHolder;
import net.osmand.binary.BinaryMapDataObject;
import net.osmand.data.LatLon;
@ -67,6 +68,8 @@ import java.util.TimerTask;
public class FirstUsageWizardFragment extends BaseOsmAndFragment implements OsmAndLocationListener,
AppInitializeListener, DownloadEvents {
private static final org.apache.commons.logging.Log LOG = PlatformUtil.getLog(FirstUsageWizardFragment.class);
public static final String TAG = "FirstUsageWizardFrag";
public static final int FIRST_USAGE_LOCATION_PERMISSION = 300;
public static final int FIRST_USAGE_REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION = 400;
@ -736,8 +739,12 @@ 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 "";
}

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