commit
fae2c412ba
72 changed files with 3613 additions and 689 deletions
|
@ -11,6 +11,7 @@ public interface OsmAndCustomizationConstants {
|
||||||
String DRAWER_MY_PLACES_ID = DRAWER_ITEM_ID_SCHEME + "my_places";
|
String DRAWER_MY_PLACES_ID = DRAWER_ITEM_ID_SCHEME + "my_places";
|
||||||
String DRAWER_SEARCH_ID = DRAWER_ITEM_ID_SCHEME + "search";
|
String DRAWER_SEARCH_ID = DRAWER_ITEM_ID_SCHEME + "search";
|
||||||
String DRAWER_DIRECTIONS_ID = DRAWER_ITEM_ID_SCHEME + "directions";
|
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_CONFIGURE_MAP_ID = DRAWER_ITEM_ID_SCHEME + "configure_map";
|
||||||
String DRAWER_DOWNLOAD_MAPS_ID = DRAWER_ITEM_ID_SCHEME + "download_maps";
|
String DRAWER_DOWNLOAD_MAPS_ID = DRAWER_ITEM_ID_SCHEME + "download_maps";
|
||||||
String DRAWER_OSMAND_LIVE_ID = DRAWER_ITEM_ID_SCHEME + "osmand_live";
|
String DRAWER_OSMAND_LIVE_ID = DRAWER_ITEM_ID_SCHEME + "osmand_live";
|
||||||
|
|
|
@ -436,6 +436,7 @@ public class OsmandRegions {
|
||||||
cx /= object.getPointsLength();
|
cx /= object.getPointsLength();
|
||||||
cy /= object.getPointsLength();
|
cy /= object.getPointsLength();
|
||||||
rd.regionCenter = new LatLon(MapUtils.get31LatitudeY((int) cy), MapUtils.get31LongitudeX((int) cx));
|
rd.regionCenter = new LatLon(MapUtils.get31LatitudeY((int) cy), MapUtils.get31LongitudeX((int) cx));
|
||||||
|
rd.boundingBox = findBoundingBox(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
rd.regionParentFullName = mapIndexFields.get(mapIndexFields.parentFullName, object);
|
rd.regionParentFullName = mapIndexFields.get(mapIndexFields.parentFullName, object);
|
||||||
|
@ -461,6 +462,43 @@ public class OsmandRegions {
|
||||||
return rd;
|
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) {
|
private String getSearchIndex(BinaryMapDataObject object) {
|
||||||
MapIndex mi = object.getMapIndex();
|
MapIndex mi = object.getMapIndex();
|
||||||
TIntObjectIterator<String> it = object.getObjectNames().iterator();
|
TIntObjectIterator<String> it = object.getObjectNames().iterator();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package net.osmand.map;
|
package net.osmand.map;
|
||||||
|
|
||||||
import net.osmand.data.LatLon;
|
import net.osmand.data.LatLon;
|
||||||
|
import net.osmand.data.QuadRect;
|
||||||
import net.osmand.util.Algorithms;
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
@ -40,6 +41,7 @@ public class WorldRegion implements Serializable {
|
||||||
protected String regionDownloadName;
|
protected String regionDownloadName;
|
||||||
protected boolean regionMapDownload;
|
protected boolean regionMapDownload;
|
||||||
protected LatLon regionCenter;
|
protected LatLon regionCenter;
|
||||||
|
protected QuadRect boundingBox;
|
||||||
|
|
||||||
public static class RegionParams {
|
public static class RegionParams {
|
||||||
protected String regionLeftHandDriving;
|
protected String regionLeftHandDriving;
|
||||||
|
@ -182,4 +184,11 @@ public class WorldRegion implements Serializable {
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean containsRegion(WorldRegion region) {
|
||||||
|
if (this.boundingBox != null && region.boundingBox != null) {
|
||||||
|
return this.boundingBox.contains(region.boundingBox);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -127,6 +127,17 @@ public class Algorithms {
|
||||||
return def;
|
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) {
|
public static String getFileNameWithoutExtension(File f) {
|
||||||
return getFileNameWithoutExtension(f.getName());
|
return getFileNameWithoutExtension(f.getName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,7 @@ android {
|
||||||
}
|
}
|
||||||
amazonFree {
|
amazonFree {
|
||||||
java.srcDirs = ["src-nogms", "src-google"]
|
java.srcDirs = ["src-nogms", "src-google"]
|
||||||
|
manifest.srcFile "AndroidManifest-gplayFree.xml"
|
||||||
}
|
}
|
||||||
amazonFull {
|
amazonFull {
|
||||||
java.srcDirs = ["src-nogms", "src-google"]
|
java.srcDirs = ["src-nogms", "src-google"]
|
||||||
|
|
6
OsmAnd/res/drawable-mdpi/btn_background_active_dark.xml
Normal file
6
OsmAnd/res/drawable-mdpi/btn_background_active_dark.xml
Normal 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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
6
OsmAnd/res/drawable/btn_background_active_light.xml
Normal file
6
OsmAnd/res/drawable/btn_background_active_light.xml
Normal 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>
|
15
OsmAnd/res/drawable/btn_unstroked_dark.xml
Normal file
15
OsmAnd/res/drawable/btn_unstroked_dark.xml
Normal 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>
|
15
OsmAnd/res/drawable/btn_unstroked_light.xml
Normal file
15
OsmAnd/res/drawable/btn_unstroked_light.xml
Normal 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>
|
70
OsmAnd/res/layout/bottom_sheet_button_with_icon.xml
Normal file
70
OsmAnd/res/layout/bottom_sheet_button_with_icon.xml
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<?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: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/description_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/description_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>
|
72
OsmAnd/res/layout/bottom_sheet_select_segment.xml
Normal file
72
OsmAnd/res/layout/bottom_sheet_select_segment.xml
Normal 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>
|
|
@ -21,11 +21,13 @@
|
||||||
android:layout_marginLeft="@dimen/card_padding"
|
android:layout_marginLeft="@dimen/card_padding"
|
||||||
android:padding="@dimen/context_menu_padding_margin_small"
|
android:padding="@dimen/context_menu_padding_margin_small"
|
||||||
android:paddingStart="@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
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:layout_width="@dimen/favorites_icon_size_small"
|
android:layout_width="@dimen/favorites_icon_size_small"
|
||||||
android:layout_height="@dimen/favorites_icon_size_small"
|
android:layout_height="@dimen/favorites_icon_size_small"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
android:tint="?attr/default_icon_color"
|
android:tint="?attr/default_icon_color"
|
||||||
osmand:srcCompat="@drawable/ic_action_close" />
|
osmand:srcCompat="@drawable/ic_action_close" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
@ -43,18 +45,20 @@
|
||||||
osmand:typeface="@string/font_roboto_medium" />
|
osmand:typeface="@string/font_roboto_medium" />
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
android:id="@+id/btn_save"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginRight="@dimen/content_padding_half"
|
android:layout_marginRight="@dimen/content_padding_half"
|
||||||
android:layout_marginEnd="@dimen/content_padding_half"
|
android:layout_marginEnd="@dimen/content_padding_half"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical">
|
||||||
android:background="@drawable/btn_border_active">
|
|
||||||
|
|
||||||
<net.osmand.plus.widgets.TextViewEx
|
<net.osmand.plus.widgets.TextViewEx
|
||||||
android:id="@+id/btn_save"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:layout_gravity="start"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:duplicateParentState="true"
|
||||||
|
android:background="@drawable/btn_border_active"
|
||||||
android:paddingStart="@dimen/content_padding"
|
android:paddingStart="@dimen/content_padding"
|
||||||
android:paddingLeft="@dimen/content_padding"
|
android:paddingLeft="@dimen/content_padding"
|
||||||
android:paddingTop="@dimen/content_padding_half"
|
android:paddingTop="@dimen/content_padding_half"
|
||||||
|
@ -77,18 +81,18 @@
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="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_marginStart="@dimen/content_padding"
|
android:layout_marginStart="@dimen/content_padding"
|
||||||
android:layout_marginLeft="@dimen/content_padding"
|
android:layout_marginLeft="@dimen/content_padding"
|
||||||
android:layout_marginTop="@dimen/content_padding_half"
|
android:layout_marginTop="@dimen/content_padding_half"
|
||||||
android:layout_marginRight="@dimen/content_padding"
|
android:layout_marginRight="@dimen/content_padding"
|
||||||
android:layout_marginEnd="@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:background="?attr/card_and_list_background_basic"
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:textSize="@dimen/default_list_text_size"
|
android:textSize="@dimen/default_list_text_size"
|
||||||
|
|
|
@ -1,31 +1,79 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
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:osmand="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/root"
|
android:id="@+id/root"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical">
|
||||||
android:background="?attr/list_background_color">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?attr/pstsTabBackground">
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.Toolbar
|
|
||||||
android:id="@+id/toolbar"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/action_bar_height"
|
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
|
<ScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
android:background="?attr/activity_background_basic">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/ll"
|
android:id="@+id/ll"
|
||||||
|
@ -61,33 +109,32 @@
|
||||||
tools:visibility="visible"/>
|
tools:visibility="visible"/>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
android:id="@+id/btn_edit"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/content_padding"
|
android:layout_marginLeft="@dimen/content_padding"
|
||||||
android:layout_marginStart="@dimen/content_padding"
|
android:layout_marginStart="@dimen/content_padding"
|
||||||
android:layout_marginTop="@dimen/context_menu_padding_margin_small"
|
android:layout_marginTop="@dimen/context_menu_padding_margin_small"
|
||||||
android:layout_marginBottom="@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
|
<net.osmand.plus.widgets.TextViewEx
|
||||||
android:id="@+id/btn_edit"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
android:duplicateParentState="true"
|
||||||
android:padding="@dimen/context_menu_padding_margin_small"
|
android:padding="@dimen/bottom_sheet_content_padding_small"
|
||||||
android:paddingStart="@dimen/context_menu_padding_margin_small"
|
android:paddingStart="@dimen/bottom_sheet_content_padding_small"
|
||||||
android:paddingEnd="@dimen/context_menu_padding_margin_small"
|
android:paddingEnd="@dimen/bottom_sheet_content_padding_small"
|
||||||
android:drawablePadding="@dimen/list_content_padding_large"
|
android:drawablePadding="@dimen/list_content_padding_large"
|
||||||
osmand:drawableLeftCompat="@drawable/ic_action_edit_dark"
|
|
||||||
osmand:drawableStartCompat="@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"
|
osmand:drawableTint="?attr/active_color_basic"
|
||||||
android:visibility="gone"
|
|
||||||
android:text="@string/shared_string_edit"
|
android:text="@string/shared_string_edit"
|
||||||
android:textColor="?attr/active_color_basic"
|
android:textColor="?attr/active_color_basic"
|
||||||
android:textSize="@dimen/default_list_text_size"
|
android:textSize="@dimen/default_list_text_size"
|
||||||
osmand:typeface="@string/font_roboto_medium"
|
osmand:typeface="@string/font_roboto_medium" />
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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:osmand="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -14,22 +13,22 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
android:background="?attr/dashboard_divider"
|
android:background="?attr/dashboard_divider"
|
||||||
android:visibility="gone"/>
|
android:visibility="gone" />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/list_divider"
|
android:id="@+id/list_divider"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
android:background="?attr/dashboard_divider"
|
android:layout_marginStart="@dimen/settings_divider_margin_start"
|
||||||
android:visibility="gone"
|
|
||||||
android:layout_marginLeft="@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
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:minHeight="@dimen/favorites_list_item_height"
|
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
|
android:minHeight="@dimen/favorites_list_item_height"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingStart="@dimen/favorites_my_places_icon_left_padding"
|
android:paddingStart="@dimen/favorites_my_places_icon_left_padding"
|
||||||
android:paddingLeft="@dimen/favorites_my_places_icon_left_padding"
|
android:paddingLeft="@dimen/favorites_my_places_icon_left_padding"
|
||||||
|
@ -56,19 +55,19 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:contentDescription="@string/favorite"
|
android:contentDescription="@string/favorite"
|
||||||
tools:src="@drawable/bg_point_circle"/>
|
tools:src="@drawable/bg_point_circle" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_weight="1"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_marginStart="@dimen/favorites_my_places_icon_right_padding"
|
android:layout_marginStart="@dimen/favorites_my_places_icon_right_padding"
|
||||||
android:layout_marginLeft="@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_marginEnd="@dimen/favorites_my_places_icon_right_padding"
|
||||||
android:layout_marginRight="@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:paddingTop="@dimen/context_menu_padding_margin_small"
|
||||||
android:paddingBottom="@dimen/context_menu_padding_margin_small">
|
android:paddingBottom="@dimen/context_menu_padding_margin_small">
|
||||||
|
|
||||||
|
@ -76,10 +75,10 @@
|
||||||
android:id="@+id/favourite_label"
|
android:id="@+id/favourite_label"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="@dimen/subHeaderPadding"
|
||||||
android:maxLines="2"
|
android:maxLines="2"
|
||||||
android:scrollbars="none"
|
android:scrollbars="none"
|
||||||
android:textColor="?android:textColorPrimary"
|
android:textColor="?android:textColorPrimary"
|
||||||
android:layout_marginBottom="@dimen/subHeaderPadding"
|
|
||||||
android:textSize="@dimen/default_list_text_size"
|
android:textSize="@dimen/default_list_text_size"
|
||||||
tools:text="@string/lorem_ipsum" />
|
tools:text="@string/lorem_ipsum" />
|
||||||
|
|
||||||
|
@ -93,6 +92,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginTop="1sp"
|
||||||
android:contentDescription="@string/show_view_angle"
|
android:contentDescription="@string/show_view_angle"
|
||||||
osmand:srcCompat="@drawable/ic_direction_arrow" />
|
osmand:srcCompat="@drawable/ic_direction_arrow" />
|
||||||
|
|
||||||
|
@ -104,8 +104,8 @@
|
||||||
android:layout_marginLeft="@dimen/gpx_small_icon_margin"
|
android:layout_marginLeft="@dimen/gpx_small_icon_margin"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
osmand:typeface="@string/font_roboto_medium"
|
|
||||||
android:textSize="@dimen/default_desc_text_size"
|
android:textSize="@dimen/default_desc_text_size"
|
||||||
|
osmand:typeface="@string/font_roboto_medium"
|
||||||
tools:text="100500 km" />
|
tools:text="100500 km" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
@ -141,8 +141,8 @@
|
||||||
android:layout_marginLeft="@dimen/dashFavIconMargin"
|
android:layout_marginLeft="@dimen/dashFavIconMargin"
|
||||||
android:background="?attr/dashboard_button"
|
android:background="?attr/dashboard_button"
|
||||||
android:contentDescription="@string/context_menu_item_directions_to"
|
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
|
<ImageButton
|
||||||
android:id="@+id/options"
|
android:id="@+id/options"
|
||||||
|
@ -151,8 +151,8 @@
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:background="?attr/dashboard_button"
|
android:background="?attr/dashboard_button"
|
||||||
android:contentDescription="@string/shared_string_more"
|
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>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
|
@ -68,19 +68,18 @@
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
android:id="@+id/btn_read_full"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="@dimen/context_menu_padding_margin_small"
|
android:layout_marginStart="@dimen/content_padding_half"
|
||||||
android:layout_marginLeft="@dimen/context_menu_padding_margin_small"
|
android:layout_marginLeft="@dimen/content_padding_half">
|
||||||
android:background="@drawable/rounded_background_3dp">
|
|
||||||
|
|
||||||
<net.osmand.plus.widgets.TextViewEx
|
<net.osmand.plus.widgets.TextViewEx
|
||||||
android:id="@+id/btn_read_full"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="start"
|
android:layout_gravity="start"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
android:duplicateParentState="true"
|
||||||
android:padding="@dimen/bottom_sheet_content_padding_small"
|
android:padding="@dimen/bottom_sheet_content_padding_small"
|
||||||
android:paddingStart="@dimen/bottom_sheet_content_padding_small"
|
android:paddingStart="@dimen/bottom_sheet_content_padding_small"
|
||||||
android:paddingEnd="@dimen/bottom_sheet_content_padding_small"
|
android:paddingEnd="@dimen/bottom_sheet_content_padding_small"
|
||||||
|
@ -96,19 +95,19 @@
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<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:id="@+id/btn_edit"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="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:gravity="center_vertical"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
android:duplicateParentState="true"
|
||||||
android:padding="@dimen/bottom_sheet_content_padding_small"
|
android:padding="@dimen/bottom_sheet_content_padding_small"
|
||||||
android:paddingStart="@dimen/bottom_sheet_content_padding_small"
|
android:paddingStart="@dimen/bottom_sheet_content_padding_small"
|
||||||
android:paddingEnd="@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_marginStart="@dimen/card_padding"
|
||||||
android:layout_marginLeft="@dimen/card_padding"
|
android:layout_marginLeft="@dimen/card_padding"
|
||||||
android:layout_marginTop="@dimen/content_padding"
|
android:layout_marginTop="@dimen/content_padding"
|
||||||
android:background="@drawable/rounded_background_3dp"
|
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
@ -142,7 +140,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
android:duplicateParentState="true"
|
||||||
android:padding="@dimen/bottom_sheet_content_padding_small"
|
android:padding="@dimen/bottom_sheet_content_padding_small"
|
||||||
android:paddingStart="@dimen/bottom_sheet_content_padding_small"
|
android:paddingStart="@dimen/bottom_sheet_content_padding_small"
|
||||||
android:paddingEnd="@dimen/bottom_sheet_content_padding_small"
|
android:paddingEnd="@dimen/bottom_sheet_content_padding_small"
|
||||||
|
|
|
@ -38,21 +38,23 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="@dimen/content_padding"
|
android:layout_marginStart="@dimen/content_padding"
|
||||||
android:layout_marginLeft="@dimen/content_padding"
|
android:layout_marginLeft="@dimen/content_padding"
|
||||||
android:gravity="center"
|
android:layout_marginTop="@dimen/dash_margin"
|
||||||
android:orientation="horizontal"
|
android:layout_marginBottom="@dimen/dash_margin"
|
||||||
android:paddingTop="@dimen/dash_margin"
|
android:orientation="horizontal">
|
||||||
android:paddingBottom="@dimen/dash_margin">
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/direction"
|
android:id="@+id/direction"
|
||||||
android:layout_width="@dimen/context_menu_transport_icon_size"
|
android:layout_width="@dimen/context_menu_transport_icon_size"
|
||||||
android:layout_height="@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" />
|
osmand:srcCompat="@drawable/ic_direction_arrow" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/distance"
|
android:id="@+id/distance"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_marginStart="@dimen/content_padding_small_half"
|
android:layout_marginStart="@dimen/content_padding_small_half"
|
||||||
android:layout_marginLeft="@dimen/content_padding_small_half"
|
android:layout_marginLeft="@dimen/content_padding_small_half"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
|
|
98
OsmAnd/res/layout/gpx_segment_list_item.xml
Normal file
98
OsmAnd/res/layout/gpx_segment_list_item.xml
Normal 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>
|
|
@ -51,6 +51,7 @@
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/name_and_read_section_container"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingTop="@dimen/gpx_text_top_margin"
|
android:paddingTop="@dimen/gpx_text_top_margin"
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
android:layout_height="@dimen/list_header_height"
|
android:layout_height="@dimen/list_header_height"
|
||||||
android:layout_marginStart="@dimen/content_padding"
|
android:layout_marginStart="@dimen/content_padding"
|
||||||
android:layout_marginLeft="@dimen/content_padding"
|
android:layout_marginLeft="@dimen/content_padding"
|
||||||
android:gravity="center_vertical"
|
android:gravity="start|center_vertical"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
@ -14,14 +14,13 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginEnd="@dimen/content_padding"
|
android:layout_marginEnd="@dimen/content_padding"
|
||||||
android:layout_marginRight="@dimen/content_padding"
|
android:layout_marginRight="@dimen/content_padding"
|
||||||
android:gravity="center_vertical"
|
android:gravity="start|center_vertical"
|
||||||
android:maxWidth="@dimen/grid_menu_item_width"
|
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center_vertical"
|
android:gravity="start|center_vertical"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:weightSum="2">
|
android:weightSum="2">
|
||||||
|
|
||||||
|
@ -31,6 +30,7 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="@null"
|
android:background="@null"
|
||||||
|
android:letterSpacing="@dimen/description_letter_spacing"
|
||||||
android:lines="1"
|
android:lines="1"
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:textSize="@dimen/default_desc_text_size"
|
android:textSize="@dimen/default_desc_text_size"
|
||||||
|
@ -61,8 +61,11 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@null"
|
android:background="@null"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
|
android:letterSpacing="@dimen/description_letter_spacing"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
android:lines="1"
|
android:lines="1"
|
||||||
android:maxWidth="@dimen/grid_menu_item_width"
|
android:maxWidth="@dimen/grid_menu_item_width"
|
||||||
|
android:minWidth="@dimen/map_route_buttons_width"
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
android:textSize="@dimen/default_desc_text_size"
|
android:textSize="@dimen/default_desc_text_size"
|
||||||
tools:text="@string/distance" />
|
tools:text="@string/distance" />
|
||||||
|
|
|
@ -73,6 +73,7 @@
|
||||||
android:paddingBottom="@dimen/content_padding_small">
|
android:paddingBottom="@dimen/content_padding_small">
|
||||||
|
|
||||||
<net.osmand.plus.widgets.TextViewEx
|
<net.osmand.plus.widgets.TextViewEx
|
||||||
|
android:id="@+id/check_box_title"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="@dimen/content_padding"
|
android:layout_marginEnd="@dimen/content_padding"
|
||||||
|
|
159
OsmAnd/res/layout/trip_recording_active_fragment.xml
Normal file
159
OsmAnd/res/layout/trip_recording_active_fragment.xml
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
<?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_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>
|
|
@ -413,4 +413,7 @@
|
||||||
|
|
||||||
<dimen name="radioButtonSize">32dp</dimen>
|
<dimen name="radioButtonSize">32dp</dimen>
|
||||||
<dimen name="checkBoxSize">24dp</dimen>
|
<dimen name="checkBoxSize">24dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="titleLineSpacingExtra">5sp</dimen>
|
||||||
|
<dimen name="descriptionLineSpacingExtra">3sp</dimen>
|
||||||
</resources>
|
</resources>
|
|
@ -12,6 +12,14 @@
|
||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
<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="restart">Restart</string>
|
||||||
<string name="elevation_data_descr">Routing could avoid strong uphills</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="map_orientation_threshold_descr">Don\'t rotate map view if speed is less than a threshold</string>
|
||||||
|
@ -39,6 +47,9 @@
|
||||||
<string name="hillshade_slope_contour_lines">Hillshade / Slope / Contour lines</string>
|
<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="toast_select_edits_for_upload">Select edits for upload</string>
|
||||||
<string name="uploaded_count">Uploaded %1$d of %2$d</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="uploading_count">Uploading %1$d of %2$d</string>
|
||||||
<string name="upload_photo_completed">Upload completed</string>
|
<string name="upload_photo_completed">Upload completed</string>
|
||||||
<string name="upload_photo">Uploading</string>
|
<string name="upload_photo">Uploading</string>
|
||||||
|
|
|
@ -62,6 +62,8 @@ import net.osmand.plus.mapmarkers.MarkersPlanRouteContext;
|
||||||
import net.osmand.plus.measurementtool.MeasurementToolFragment;
|
import net.osmand.plus.measurementtool.MeasurementToolFragment;
|
||||||
import net.osmand.plus.measurementtool.StartPlanRouteBottomSheet;
|
import net.osmand.plus.measurementtool.StartPlanRouteBottomSheet;
|
||||||
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
|
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.osmedit.dialogs.DismissRouteBottomSheetFragment;
|
||||||
import net.osmand.plus.profiles.ProfileDataObject;
|
import net.osmand.plus.profiles.ProfileDataObject;
|
||||||
import net.osmand.plus.profiles.ProfileDataUtils;
|
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_CONFIGURE_SCREEN_ID;
|
||||||
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_DASHBOARD_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_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_DIVIDER_ID;
|
||||||
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_DOWNLOAD_MAPS_ID;
|
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_DOWNLOAD_MAPS_ID;
|
||||||
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_HELP_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);
|
GPXRouteParamsBuilder params = new GPXRouteParamsBuilder(result, settings);
|
||||||
params.setCalculateOsmAndRouteParts(settings.GPX_ROUTE_CALC_OSMAND_PARTS.get());
|
params.setCalculateOsmAndRouteParts(settings.GPX_ROUTE_CALC_OSMAND_PARTS.get());
|
||||||
params.setCalculateOsmAndRoute(settings.GPX_ROUTE_CALC.get());
|
params.setCalculateOsmAndRoute(settings.GPX_ROUTE_CALC.get());
|
||||||
|
params.setSelectedSegment(settings.GPX_ROUTE_SEGMENT.get());
|
||||||
List<Location> ps = params.getPoints(settings.getContext());
|
List<Location> ps = params.getPoints(settings.getContext());
|
||||||
mapActivity.getRoutingHelper().setGpxParams(params);
|
mapActivity.getRoutingHelper().setGpxParams(params);
|
||||||
settings.FOLLOW_THE_GPX_ROUTE.set(result.path);
|
settings.FOLLOW_THE_GPX_ROUTE.set(result.path);
|
||||||
|
@ -839,6 +843,26 @@ public class MapActivityActions implements DialogProvider {
|
||||||
}
|
}
|
||||||
}).createItem());
|
}).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)
|
optionsMenuHelper.addItem(new ItemBuilder().setTitleId(R.string.get_directions, mapActivity)
|
||||||
.setId(DRAWER_DIRECTIONS_ID)
|
.setId(DRAWER_DIRECTIONS_ID)
|
||||||
|
|
|
@ -19,6 +19,7 @@ import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
|
||||||
import net.osmand.plus.OsmAndLocationProvider;
|
import net.osmand.plus.OsmAndLocationProvider;
|
||||||
import net.osmand.plus.OsmandApplication;
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.OsmandPlugin;
|
import net.osmand.plus.OsmandPlugin;
|
||||||
|
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||||
import net.osmand.plus.Version;
|
import net.osmand.plus.Version;
|
||||||
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
|
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
|
||||||
|
@ -78,6 +79,9 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
|
||||||
private SelectedGpxFile currentTrack;
|
private SelectedGpxFile currentTrack;
|
||||||
private int points;
|
private int points;
|
||||||
private int trkPoints = 0;
|
private int trkPoints = 0;
|
||||||
|
private long lastTimeFileSaved;
|
||||||
|
|
||||||
|
private ApplicationMode lastRoutingApplicationMode;
|
||||||
|
|
||||||
public SavingTrackHelper(OsmandApplication ctx) {
|
public SavingTrackHelper(OsmandApplication ctx) {
|
||||||
super(ctx, DATABASE_NAME, null, DATABASE_VERSION);
|
super(ctx, DATABASE_NAME, null, DATABASE_VERSION);
|
||||||
|
@ -255,6 +259,7 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
|
||||||
GPXTrackAnalysis analysis = gpx.getAnalysis(fout.lastModified());
|
GPXTrackAnalysis analysis = gpx.getAnalysis(fout.lastModified());
|
||||||
GpxDataItem item = new GpxDataItem(fout, analysis);
|
GpxDataItem item = new GpxDataItem(fout, analysis);
|
||||||
ctx.getGpxDbHelper().add(item);
|
ctx.getGpxDbHelper().add(item);
|
||||||
|
lastTimeFileSaved = fout.lastModified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -440,12 +445,15 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
|
||||||
} else {
|
} else {
|
||||||
heading = NO_HEADING;
|
heading = NO_HEADING;
|
||||||
}
|
}
|
||||||
|
if (ctx.getRoutingHelper().isFollowingMode()) {
|
||||||
|
lastRoutingApplicationMode = settings.getApplicationMode();
|
||||||
|
}
|
||||||
boolean record = false;
|
boolean record = false;
|
||||||
if (location != null && OsmAndLocationProvider.isNotSimulatedLocation(location)
|
if (location != null && OsmAndLocationProvider.isNotSimulatedLocation(location)
|
||||||
&& OsmandPlugin.getEnabledPlugin(OsmandMonitoringPlugin.class) != null) {
|
&& OsmandPlugin.getEnabledPlugin(OsmandMonitoringPlugin.class) != null) {
|
||||||
if (settings.SAVE_TRACK_TO_GPX.get()
|
if (settings.SAVE_TRACK_TO_GPX.get()
|
||||||
&& locationTime - lastTimeUpdated > settings.SAVE_TRACK_INTERVAL.get()
|
&& locationTime - lastTimeUpdated > settings.SAVE_TRACK_INTERVAL.get()
|
||||||
&& ctx.getRoutingHelper().isFollowingMode()) {
|
&& lastRoutingApplicationMode == settings.getApplicationMode()) {
|
||||||
record = true;
|
record = true;
|
||||||
} else if (settings.SAVE_GLOBAL_TRACK_TO_GPX.get()
|
} else if (settings.SAVE_GLOBAL_TRACK_TO_GPX.get()
|
||||||
&& locationTime - lastTimeUpdated > settings.SAVE_GLOBAL_TRACK_INTERVAL.get()) {
|
&& locationTime - lastTimeUpdated > settings.SAVE_GLOBAL_TRACK_INTERVAL.get()) {
|
||||||
|
@ -705,9 +713,10 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getIsRecording() {
|
public boolean getIsRecording() {
|
||||||
|
OsmandSettings settings = ctx.getSettings();
|
||||||
return OsmandPlugin.getEnabledPlugin(OsmandMonitoringPlugin.class) != null
|
return OsmandPlugin.getEnabledPlugin(OsmandMonitoringPlugin.class) != null
|
||||||
&& ctx.getSettings().SAVE_GLOBAL_TRACK_TO_GPX.get()
|
&& settings.SAVE_GLOBAL_TRACK_TO_GPX.get() || settings.SAVE_TRACK_TO_GPX.get()
|
||||||
|| (ctx.getSettings().SAVE_TRACK_TO_GPX.get() && ctx.getRoutingHelper().isFollowingMode());
|
&& lastRoutingApplicationMode == settings.getApplicationMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getDistance() {
|
public float getDistance() {
|
||||||
|
@ -730,6 +739,14 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
|
||||||
return lastTimeUpdated;
|
return lastTimeUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getLastTimeFileSaved() {
|
||||||
|
return lastTimeFileSaved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastTimeFileSaved(long lastTimeFileSaved) {
|
||||||
|
this.lastTimeFileSaved = lastTimeFileSaved;
|
||||||
|
}
|
||||||
|
|
||||||
public GPXFile getCurrentGpx() {
|
public GPXFile getCurrentGpx() {
|
||||||
return currentTrack.getGpxFile();
|
return currentTrack.getGpxFile();
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,6 +134,9 @@ public class FailSafeFuntions {
|
||||||
if(settings.GPX_ROUTE_CALC.get()) {
|
if(settings.GPX_ROUTE_CALC.get()) {
|
||||||
gpxRoute.setCalculateOsmAndRoute(true);
|
gpxRoute.setCalculateOsmAndRoute(true);
|
||||||
}
|
}
|
||||||
|
if (settings.GPX_ROUTE_SEGMENT.get() != -1) {
|
||||||
|
gpxRoute.setSelectedSegment(settings.GPX_ROUTE_SEGMENT.get());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
gpxRoute = null;
|
gpxRoute = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -380,7 +380,7 @@ public abstract class MenuBottomSheetDialogFragment extends BottomSheetDialogFra
|
||||||
AndroidUiHelper.updateVisibility(dismissButton, buttonTextId != DEFAULT_VALUE);
|
AndroidUiHelper.updateVisibility(dismissButton, buttonTextId != DEFAULT_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupRightButton() {
|
protected void setupRightButton() {
|
||||||
rightButton = buttonsContainer.findViewById(R.id.right_bottom_button);
|
rightButton = buttonsContainer.findViewById(R.id.right_bottom_button);
|
||||||
rightButton.getLayoutParams().height = getRightButtonHeight();
|
rightButton.getLayoutParams().height = getRightButtonHeight();
|
||||||
int buttonTextId = getRightBottomButtonTextId();
|
int buttonTextId = getRightBottomButtonTextId();
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ public class AbstractDownloadActivity extends ActionBarProgressActivity {
|
||||||
downloadValidationManager.startDownload(this, indexItem);
|
downloadValidationManager.startDownload(this, indexItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void makeSureUserCancelDownload(IndexItem item) {
|
public void makeSureUserCancelDownload(DownloadItem item) {
|
||||||
downloadValidationManager.makeSureUserCancelDownload(this, item);
|
downloadValidationManager.makeSureUserCancelDownload(this, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,8 @@ public class CustomIndexItem extends IndexItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public File getTargetFile(OsmandApplication ctx) {
|
@NonNull
|
||||||
|
public File getTargetFile(@NonNull OsmandApplication ctx) {
|
||||||
String basename = getTranslatedBasename();
|
String basename = getTranslatedBasename();
|
||||||
if (!Algorithms.isEmpty(subfolder)) {
|
if (!Algorithms.isEmpty(subfolder)) {
|
||||||
basename = subfolder + "/" + basename;
|
basename = subfolder + "/" + basename;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package net.osmand.plus.download;
|
package net.osmand.plus.download;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
|
@ -2,6 +2,8 @@ package net.osmand.plus.download;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import net.osmand.AndroidUtils;
|
import net.osmand.AndroidUtils;
|
||||||
import net.osmand.IndexConstants;
|
import net.osmand.IndexConstants;
|
||||||
import net.osmand.map.OsmandRegions;
|
import net.osmand.map.OsmandRegions;
|
||||||
|
@ -18,6 +20,7 @@ import java.io.IOException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
@ -114,6 +117,10 @@ public class DownloadActivityType {
|
||||||
return byTag.get(tagName);
|
return byTag.get(tagName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Collection<DownloadActivityType> values() {
|
||||||
|
return byTag.values();
|
||||||
|
}
|
||||||
|
|
||||||
protected static String addVersionToExt(String ext, int version) {
|
protected static String addVersionToExt(String ext, int version) {
|
||||||
return "_" + version + ext;
|
return "_" + version + ext;
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
if (this == SRTM_COUNTRY_FILE) {
|
||||||
return ctx.getString(R.string.download_srtm_maps);
|
return ctx.getString(R.string.download_srtm_maps);
|
||||||
} else if (this == WIKIPEDIA_FILE) {
|
} else if (this == WIKIPEDIA_FILE) {
|
||||||
|
@ -337,20 +344,20 @@ public class DownloadActivityType {
|
||||||
return "";
|
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) {
|
if (this == VOICE_FILE) {
|
||||||
String fileName = indexItem.fileName;
|
String fileName = downloadItem.getFileName();
|
||||||
if (fileName.endsWith(IndexConstants.VOICE_INDEX_EXT_ZIP)) {
|
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)) {
|
} 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) {
|
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)) {
|
if (basename.endsWith(FileNameTranslationHelper.WIKI_NAME)) {
|
||||||
return FileNameTranslationHelper.getWikiName(ctx, basename);
|
return FileNameTranslationHelper.getWikiName(ctx, basename);
|
||||||
}
|
}
|
||||||
|
@ -441,9 +448,11 @@ public class DownloadActivityType {
|
||||||
return fileName;
|
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)) {
|
if (fileName.endsWith(IndexConstants.EXTRA_ZIP_EXT)) {
|
||||||
return fileName.substring(0, fileName.length() - IndexConstants.EXTRA_ZIP_EXT.length());
|
return fileName.substring(0, fileName.length() - IndexConstants.EXTRA_ZIP_EXT.length());
|
||||||
}
|
}
|
||||||
|
@ -458,7 +467,7 @@ public class DownloadActivityType {
|
||||||
if (fileName.endsWith(IndexConstants.SQLITE_EXT)) {
|
if (fileName.endsWith(IndexConstants.SQLITE_EXT)) {
|
||||||
return fileName.substring(0, fileName.length() - IndexConstants.SQLITE_EXT.length());
|
return fileName.substring(0, fileName.length() - IndexConstants.SQLITE_EXT.length());
|
||||||
}
|
}
|
||||||
if (indexItem.getType() == WIKIVOYAGE_FILE &&
|
if (downloadItem.getType() == WIKIVOYAGE_FILE &&
|
||||||
fileName.endsWith(IndexConstants.BINARY_WIKIVOYAGE_MAP_INDEX_EXT)) {
|
fileName.endsWith(IndexConstants.BINARY_WIKIVOYAGE_MAP_INDEX_EXT)) {
|
||||||
return fileName.substring(0, fileName.length() - IndexConstants.BINARY_WIKIVOYAGE_MAP_INDEX_EXT.length());
|
return fileName.substring(0, fileName.length() - IndexConstants.BINARY_WIKIVOYAGE_MAP_INDEX_EXT.length());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
public void cancelDownload(IndexItem item) {
|
||||||
app.logMapDownloadEvent("cancel", item);
|
app.logMapDownloadEvent("cancel", item);
|
||||||
if (currentDownloadingItem == item) {
|
if (currentDownloadingItem == item) {
|
||||||
|
|
81
OsmAnd/src/net/osmand/plus/download/DownloadItem.java
Normal file
81
OsmAnd/src/net/osmand/plus/download/DownloadItem.java
Normal 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import net.osmand.map.OsmandRegions;
|
||||||
import net.osmand.map.WorldRegion;
|
import net.osmand.map.WorldRegion;
|
||||||
import net.osmand.plus.OsmandApplication;
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -20,8 +21,8 @@ public class DownloadResourceGroup {
|
||||||
|
|
||||||
private final DownloadResourceGroupType type;
|
private final DownloadResourceGroupType type;
|
||||||
private final DownloadResourceGroup parentGroup;
|
private final DownloadResourceGroup parentGroup;
|
||||||
// ASSERT: individualResources are not empty if and only if groups are empty
|
// ASSERT: individualDownloadItems are not empty if and only if groups are empty
|
||||||
private final List<IndexItem> individualResources;
|
private final List<DownloadItem> individualDownloadItems;
|
||||||
private final List<DownloadResourceGroup> groups;
|
private final List<DownloadResourceGroup> groups;
|
||||||
protected final String id;
|
protected final String id;
|
||||||
|
|
||||||
|
@ -107,10 +108,10 @@ public class DownloadResourceGroup {
|
||||||
public DownloadResourceGroup(DownloadResourceGroup parentGroup, DownloadResourceGroupType type, String id) {
|
public DownloadResourceGroup(DownloadResourceGroup parentGroup, DownloadResourceGroupType type, String id) {
|
||||||
boolean flat = type.containsIndexItem();
|
boolean flat = type.containsIndexItem();
|
||||||
if (flat) {
|
if (flat) {
|
||||||
this.individualResources = new ArrayList<IndexItem>();
|
this.individualDownloadItems = new ArrayList<DownloadItem>();
|
||||||
this.groups = null;
|
this.groups = null;
|
||||||
} else {
|
} else {
|
||||||
this.individualResources = null;
|
this.individualDownloadItems = null;
|
||||||
this.groups = new ArrayList<DownloadResourceGroup>();
|
this.groups = new ArrayList<DownloadResourceGroup>();
|
||||||
}
|
}
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
@ -173,7 +174,7 @@ public class DownloadResourceGroup {
|
||||||
DownloadResourceGroup regionMaps = getSubGroupById(DownloadResourceGroupType.REGION_MAPS.getDefaultId());
|
DownloadResourceGroup regionMaps = getSubGroupById(DownloadResourceGroupType.REGION_MAPS.getDefaultId());
|
||||||
if(regionMaps != null && regionMaps.size() == 1 && parentGroup != null && parentGroup.getParentGroup() != null &&
|
if(regionMaps != null && regionMaps.size() == 1 && parentGroup != null && parentGroup.getParentGroup() != null &&
|
||||||
isEmpty(getSubGroupById(DownloadResourceGroupType.SUBREGIONS.getDefaultId()))) {
|
isEmpty(getSubGroupById(DownloadResourceGroupType.SUBREGIONS.getDefaultId()))) {
|
||||||
IndexItem item = regionMaps.individualResources.get(0);
|
IndexItem item = regionMaps.getIndividualResources().get(0);
|
||||||
DownloadResourceGroup screenParent = parentGroup.getParentGroup();
|
DownloadResourceGroup screenParent = parentGroup.getParentGroup();
|
||||||
if(item.getType() == DownloadActivityType.HILLSHADE_FILE) {
|
if(item.getType() == DownloadActivityType.HILLSHADE_FILE) {
|
||||||
DownloadResourceGroup hillshades =
|
DownloadResourceGroup hillshades =
|
||||||
|
@ -183,7 +184,7 @@ public class DownloadResourceGroup {
|
||||||
screenParent.addGroup(hillshades);
|
screenParent.addGroup(hillshades);
|
||||||
}
|
}
|
||||||
hillshades.addItem(item);
|
hillshades.addItem(item);
|
||||||
regionMaps.individualResources.remove(0);
|
regionMaps.individualDownloadItems.remove(0);
|
||||||
} else if (item.getType() == DownloadActivityType.SRTM_COUNTRY_FILE) {
|
} else if (item.getType() == DownloadActivityType.SRTM_COUNTRY_FILE) {
|
||||||
DownloadResourceGroup hillshades = screenParent
|
DownloadResourceGroup hillshades = screenParent
|
||||||
.getSubGroupById(DownloadResourceGroupType.SRTM_HEADER.getDefaultId());
|
.getSubGroupById(DownloadResourceGroupType.SRTM_HEADER.getDefaultId());
|
||||||
|
@ -192,7 +193,7 @@ public class DownloadResourceGroup {
|
||||||
screenParent.addGroup(hillshades);
|
screenParent.addGroup(hillshades);
|
||||||
}
|
}
|
||||||
hillshades.addItem(item);
|
hillshades.addItem(item);
|
||||||
regionMaps.individualResources.remove(0);
|
regionMaps.individualDownloadItems.remove(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -221,35 +222,38 @@ public class DownloadResourceGroup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
groups.add(g);
|
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 net.osmand.Collator collator = OsmAndCollator.primaryCollator();
|
||||||
final OsmandApplication app = getRoot().app;
|
final OsmandApplication app = getRoot().app;
|
||||||
final OsmandRegions osmandRegions = app.getRegions();
|
final OsmandRegions osmandRegions = app.getRegions();
|
||||||
Collections.sort(g.individualResources, new Comparator<IndexItem>() {
|
Collections.sort(items, new Comparator<DownloadItem>() {
|
||||||
@Override
|
@Override
|
||||||
public int compare(IndexItem lhs, IndexItem rhs) {
|
public int compare(DownloadItem firstItem, DownloadItem secondItem) {
|
||||||
int lli = lhs.getType().getOrderIndex();
|
int firstOrder = firstItem.getType().getOrderIndex();
|
||||||
int rri = rhs.getType().getOrderIndex();
|
int secondOrder = secondItem.getType().getOrderIndex();
|
||||||
if(lli < rri) {
|
if(firstOrder < secondOrder) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if(lli > rri) {
|
} else if(firstOrder > secondOrder) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
String firstName = firstItem.getVisibleName(app, osmandRegions);
|
||||||
return collator.compare(lhs.getVisibleName(app.getApplicationContext(), osmandRegions),
|
String secondName = secondItem.getVisibleName(app, osmandRegions);
|
||||||
rhs.getVisibleName(app.getApplicationContext(), osmandRegions));
|
return collator.compare(firstName, secondName);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void addItem(IndexItem i) {
|
public void addItem(DownloadItem i) {
|
||||||
i.setRelatedGroup(this);
|
i.setRelatedGroup(this);
|
||||||
individualResources.add(i);
|
individualDownloadItems.add(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return isEmpty(individualResources) && isEmpty(groups);
|
return isEmpty(individualDownloadItems) && isEmpty(groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isEmpty(List<?> l) {
|
private boolean isEmpty(List<?> l) {
|
||||||
|
@ -265,7 +269,7 @@ public class DownloadResourceGroup {
|
||||||
}
|
}
|
||||||
|
|
||||||
public int size() {
|
public int size() {
|
||||||
return groups != null ? groups.size() : individualResources.size();
|
return groups != null ? groups.size() : individualDownloadItems.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownloadResourceGroup getGroupByIndex(int ind) {
|
public DownloadResourceGroup getGroupByIndex(int ind) {
|
||||||
|
@ -275,9 +279,9 @@ public class DownloadResourceGroup {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IndexItem getItemByIndex(int ind) {
|
public DownloadItem getItemByIndex(int ind) {
|
||||||
if (individualResources != null && ind >= 0 && ind < individualResources.size()) {
|
if (individualDownloadItems != null && ind >= 0 && ind < individualDownloadItems.size()) {
|
||||||
return individualResources.get(ind);
|
return individualDownloadItems.get(ind);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -306,9 +310,21 @@ public class DownloadResourceGroup {
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<IndexItem> getIndividualResources() {
|
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;
|
return individualResources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<DownloadItem> getIndividualDownloadItems() {
|
||||||
|
return individualDownloadItems;
|
||||||
|
}
|
||||||
|
|
||||||
public WorldRegion getRegion() {
|
public WorldRegion getRegion() {
|
||||||
return region;
|
return region;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,10 +25,14 @@ import java.io.InputStream;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static net.osmand.plus.download.DownloadResourceGroup.DownloadResourceGroupType.REGION_MAPS;
|
||||||
|
|
||||||
public class DownloadResources extends DownloadResourceGroup {
|
public class DownloadResources extends DownloadResourceGroup {
|
||||||
private static final String TAG = DownloadResources.class.getSimpleName();
|
private static final String TAG = DownloadResources.class.getSimpleName();
|
||||||
|
@ -40,7 +44,7 @@ public class DownloadResources extends DownloadResourceGroup {
|
||||||
private Map<String, String> indexFileNames = new LinkedHashMap<>();
|
private Map<String, String> indexFileNames = new LinkedHashMap<>();
|
||||||
private Map<String, String> indexActivatedFileNames = new LinkedHashMap<>();
|
private Map<String, String> indexActivatedFileNames = new LinkedHashMap<>();
|
||||||
private List<IndexItem> rawResources;
|
private List<IndexItem> rawResources;
|
||||||
private Map<WorldRegion, List<IndexItem> > groupByRegion;
|
private Map<WorldRegion, List<IndexItem>> groupByRegion;
|
||||||
private List<IndexItem> itemsToUpdate = new ArrayList<>();
|
private List<IndexItem> itemsToUpdate = new ArrayList<>();
|
||||||
public static final String WORLD_SEAMARKS_KEY = "world_seamarks";
|
public static final String WORLD_SEAMARKS_KEY = "world_seamarks";
|
||||||
public static final String WORLD_SEAMARKS_NAME = "World_seamarks";
|
public static final String WORLD_SEAMARKS_NAME = "World_seamarks";
|
||||||
|
@ -337,13 +341,13 @@ public class DownloadResources extends DownloadResourceGroup {
|
||||||
DownloadResourceGroup wikivoyageMapsScreen = new DownloadResourceGroup(wikivoyageMapsGroup, DownloadResourceGroupType.WIKIVOYAGE_MAPS);
|
DownloadResourceGroup wikivoyageMapsScreen = new DownloadResourceGroup(wikivoyageMapsGroup, DownloadResourceGroupType.WIKIVOYAGE_MAPS);
|
||||||
DownloadResourceGroup wikivoyageMaps = new DownloadResourceGroup(wikivoyageMapsGroup, DownloadResourceGroupType.WIKIVOYAGE_HEADER);
|
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();
|
OsmandRegions regs = app.getRegions();
|
||||||
for (IndexItem ii : resources) {
|
for (IndexItem ii : resources) {
|
||||||
if (ii.getType() == DownloadActivityType.VOICE_FILE) {
|
if (ii.getType() == DownloadActivityType.VOICE_FILE) {
|
||||||
if (ii.getFileName().endsWith(IndexConstants.TTSVOICE_INDEX_EXT_JS)){
|
if (ii.getFileName().endsWith(IndexConstants.TTSVOICE_INDEX_EXT_JS)) {
|
||||||
voiceTTS.addItem(ii);
|
voiceTTS.addItem(ii);
|
||||||
} else if (ii.getFileName().endsWith(IndexConstants.VOICE_INDEX_EXT_ZIP)){
|
} else if (ii.getFileName().endsWith(IndexConstants.VOICE_INDEX_EXT_ZIP)) {
|
||||||
voiceRec.addItem(ii);
|
voiceRec.addItem(ii);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
@ -402,11 +406,11 @@ public class DownloadResources extends DownloadResourceGroup {
|
||||||
LinkedList<DownloadResourceGroup> parent = new LinkedList<DownloadResourceGroup>();
|
LinkedList<DownloadResourceGroup> parent = new LinkedList<DownloadResourceGroup>();
|
||||||
DownloadResourceGroup worldSubregions = new DownloadResourceGroup(this, DownloadResourceGroupType.SUBREGIONS);
|
DownloadResourceGroup worldSubregions = new DownloadResourceGroup(this, DownloadResourceGroupType.SUBREGIONS);
|
||||||
addGroup(worldSubregions);
|
addGroup(worldSubregions);
|
||||||
for(WorldRegion rg : region.getSubregions()) {
|
for (WorldRegion rg : region.getSubregions()) {
|
||||||
queue.add(rg);
|
queue.add(rg);
|
||||||
parent.add(worldSubregions);
|
parent.add(worldSubregions);
|
||||||
}
|
}
|
||||||
while(!queue.isEmpty()) {
|
while (!queue.isEmpty()) {
|
||||||
WorldRegion reg = queue.pollFirst();
|
WorldRegion reg = queue.pollFirst();
|
||||||
DownloadResourceGroup parentGroup = parent.pollFirst();
|
DownloadResourceGroup parentGroup = parent.pollFirst();
|
||||||
List<WorldRegion> subregions = reg.getSubregions();
|
List<WorldRegion> subregions = reg.getSubregions();
|
||||||
|
@ -415,9 +419,9 @@ public class DownloadResources extends DownloadResourceGroup {
|
||||||
parentGroup.addGroup(mainGrp);
|
parentGroup.addGroup(mainGrp);
|
||||||
|
|
||||||
List<IndexItem> list = groupByRegion.get(reg);
|
List<IndexItem> list = groupByRegion.get(reg);
|
||||||
if(list != null) {
|
if (list != null) {
|
||||||
DownloadResourceGroup flatFiles = new DownloadResourceGroup(mainGrp, DownloadResourceGroupType.REGION_MAPS);
|
DownloadResourceGroup flatFiles = new DownloadResourceGroup(mainGrp, REGION_MAPS);
|
||||||
for(IndexItem ii : list) {
|
for (IndexItem ii : list) {
|
||||||
flatFiles.addItem(ii);
|
flatFiles.addItem(ii);
|
||||||
}
|
}
|
||||||
mainGrp.addGroup(flatFiles);
|
mainGrp.addGroup(flatFiles);
|
||||||
|
@ -425,7 +429,7 @@ public class DownloadResources extends DownloadResourceGroup {
|
||||||
DownloadResourceGroup subRegions = new DownloadResourceGroup(mainGrp, DownloadResourceGroupType.SUBREGIONS);
|
DownloadResourceGroup subRegions = new DownloadResourceGroup(mainGrp, DownloadResourceGroupType.SUBREGIONS);
|
||||||
mainGrp.addGroup(subRegions);
|
mainGrp.addGroup(subRegions);
|
||||||
// add to processing queue
|
// add to processing queue
|
||||||
for(WorldRegion rg : subregions) {
|
for (WorldRegion rg : subregions) {
|
||||||
queue.add(rg);
|
queue.add(rg);
|
||||||
parent.add(subRegions);
|
parent.add(subRegions);
|
||||||
}
|
}
|
||||||
|
@ -465,9 +469,85 @@ public class DownloadResources extends DownloadResourceGroup {
|
||||||
createHillshadeSRTMGroups();
|
createHillshadeSRTMGroups();
|
||||||
trimEmptyGroups();
|
trimEmptyGroups();
|
||||||
updateLoadedFiles();
|
updateLoadedFiles();
|
||||||
|
collectMultipleIndexesItems(region);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
private void buildRegionsGroups(WorldRegion region, DownloadResourceGroup group) {
|
||||||
LinkedList<WorldRegion> queue = new LinkedList<WorldRegion>();
|
LinkedList<WorldRegion> queue = new LinkedList<WorldRegion>();
|
||||||
LinkedList<DownloadResourceGroup> parent = new LinkedList<DownloadResourceGroup>();
|
LinkedList<DownloadResourceGroup> parent = new LinkedList<DownloadResourceGroup>();
|
||||||
|
@ -485,7 +565,7 @@ public class DownloadResources extends DownloadResourceGroup {
|
||||||
CustomRegion customRegion = (CustomRegion) reg;
|
CustomRegion customRegion = (CustomRegion) reg;
|
||||||
List<IndexItem> indexItems = customRegion.loadIndexItems();
|
List<IndexItem> indexItems = customRegion.loadIndexItems();
|
||||||
if (!Algorithms.isEmpty(indexItems)) {
|
if (!Algorithms.isEmpty(indexItems)) {
|
||||||
DownloadResourceGroup flatFiles = new DownloadResourceGroup(mainGrp, DownloadResourceGroupType.REGION_MAPS);
|
DownloadResourceGroup flatFiles = new DownloadResourceGroup(mainGrp, REGION_MAPS);
|
||||||
for (IndexItem ii : indexItems) {
|
for (IndexItem ii : indexItems) {
|
||||||
flatFiles.addItem(ii);
|
flatFiles.addItem(ii);
|
||||||
}
|
}
|
||||||
|
@ -557,7 +637,11 @@ public class DownloadResources extends DownloadResourceGroup {
|
||||||
return res;
|
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<>();
|
List<IndexItem> res = new ArrayList<>();
|
||||||
OsmandRegions regions = app.getRegions();
|
OsmandRegions regions = app.getRegions();
|
||||||
DownloadIndexesThread downloadThread = app.getDownloadThread();
|
DownloadIndexesThread downloadThread = app.getDownloadThread();
|
||||||
|
@ -573,8 +657,12 @@ public class DownloadResources extends DownloadResourceGroup {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isIndexItemDownloaded(DownloadIndexesThread downloadThread, DownloadActivityType type, WorldRegion downloadRegion, List<IndexItem> res) {
|
private static boolean isIndexItemDownloaded(DownloadIndexesThread downloadThread,
|
||||||
List<IndexItem> otherIndexItems = new ArrayList<>(downloadThread.getIndexes().getIndexItems(downloadRegion));
|
DownloadActivityType type,
|
||||||
|
WorldRegion downloadRegion,
|
||||||
|
List<IndexItem> res) {
|
||||||
|
List<IndexItem> otherIndexItems =
|
||||||
|
new ArrayList<>(downloadThread.getIndexes().getIndexItems(downloadRegion));
|
||||||
for (IndexItem indexItem : otherIndexItems) {
|
for (IndexItem indexItem : otherIndexItems) {
|
||||||
if (indexItem.getType() == type && indexItem.isDownloaded()) {
|
if (indexItem.getType() == type && indexItem.isDownloaded()) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -584,8 +672,24 @@ public class DownloadResources extends DownloadResourceGroup {
|
||||||
&& isIndexItemDownloaded(downloadThread, type, downloadRegion.getSuperregion(), res);
|
&& isIndexItemDownloaded(downloadThread, type, downloadRegion.getSuperregion(), res);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean addIndexItem(DownloadIndexesThread downloadThread, DownloadActivityType type, WorldRegion downloadRegion, List<IndexItem> res) {
|
private boolean doesListContainIndexWithType(List<IndexItem> indexItems,
|
||||||
List<IndexItem> otherIndexItems = new ArrayList<>(downloadThread.getIndexes().getIndexItems(downloadRegion));
|
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) {
|
for (IndexItem indexItem : otherIndexItems) {
|
||||||
if (indexItem.getType() == type
|
if (indexItem.getType() == type
|
||||||
&& !res.contains(indexItem)) {
|
&& !res.contains(indexItem)) {
|
||||||
|
|
|
@ -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);
|
AlertDialog.Builder bld = new AlertDialog.Builder(ctx);
|
||||||
bld.setTitle(ctx.getString(R.string.shared_string_cancel));
|
bld.setTitle(ctx.getString(R.string.shared_string_cancel));
|
||||||
bld.setMessage(R.string.confirm_interrupt_download);
|
bld.setMessage(R.string.confirm_interrupt_download);
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
package net.osmand.plus.download;
|
package net.osmand.plus.download;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import net.osmand.IndexConstants;
|
import net.osmand.IndexConstants;
|
||||||
import net.osmand.PlatformUtil;
|
import net.osmand.PlatformUtil;
|
||||||
import net.osmand.map.OsmandRegions;
|
|
||||||
import net.osmand.plus.OsmandApplication;
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.helpers.FileNameTranslationHelper;
|
import net.osmand.plus.helpers.FileNameTranslationHelper;
|
||||||
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
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);
|
private static final Log log = PlatformUtil.getLog(IndexItem.class);
|
||||||
|
|
||||||
String description;
|
String description;
|
||||||
|
@ -27,43 +27,43 @@ public class IndexItem implements Comparable<IndexItem> {
|
||||||
long timestamp;
|
long timestamp;
|
||||||
long contentSize;
|
long contentSize;
|
||||||
long containerSize;
|
long containerSize;
|
||||||
DownloadActivityType type;
|
|
||||||
boolean extra;
|
boolean extra;
|
||||||
|
|
||||||
// Update information
|
// Update information
|
||||||
boolean outdated;
|
boolean outdated;
|
||||||
boolean downloaded;
|
boolean downloaded;
|
||||||
long localTimestamp;
|
long localTimestamp;
|
||||||
DownloadResourceGroup relatedGroup;
|
|
||||||
|
|
||||||
|
public IndexItem(String fileName,
|
||||||
public IndexItem(String fileName, String description, long timestamp, String size, long contentSize,
|
String description,
|
||||||
long containerSize, @NonNull DownloadActivityType tp) {
|
long timestamp,
|
||||||
|
String size,
|
||||||
|
long contentSize,
|
||||||
|
long containerSize,
|
||||||
|
@NonNull DownloadActivityType type) {
|
||||||
|
super(type);
|
||||||
this.fileName = fileName;
|
this.fileName = fileName;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.size = size;
|
this.size = size;
|
||||||
this.contentSize = contentSize;
|
this.contentSize = contentSize;
|
||||||
this.containerSize = containerSize;
|
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() {
|
public String getFileName() {
|
||||||
return fileName;
|
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() {
|
public String getDescription() {
|
||||||
return description;
|
return description;
|
||||||
|
@ -89,11 +89,11 @@ public class IndexItem implements Comparable<IndexItem> {
|
||||||
return ((double)containerSize) / (1 << 20);
|
return ((double)containerSize) / (1 << 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSizeDescription(Context ctx) {
|
@Override
|
||||||
return ctx.getString(R.string.ltr_or_rtl_combine_via_space, size, "MB");
|
protected double getSizeToDownloadInMb() {
|
||||||
|
return Algorithms.parseDoubleSilently(size, 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public DownloadEntry createDownloadEntry(OsmandApplication ctx) {
|
public DownloadEntry createDownloadEntry(OsmandApplication ctx) {
|
||||||
String fileName = this.fileName;
|
String fileName = this.fileName;
|
||||||
File parent = type.getDownloadFolder(ctx, this);
|
File parent = type.getDownloadFolder(ctx, this);
|
||||||
|
@ -132,11 +132,8 @@ public class IndexItem implements Comparable<IndexItem> {
|
||||||
return type.getTargetFileName(this);
|
return type.getTargetFileName(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBasename() {
|
@NonNull
|
||||||
return type.getBasename(this);
|
public File getTargetFile(@NonNull OsmandApplication ctx) {
|
||||||
}
|
|
||||||
|
|
||||||
public File getTargetFile(OsmandApplication ctx) {
|
|
||||||
String basename = getTranslatedBasename();
|
String basename = getTranslatedBasename();
|
||||||
return new File(type.getDownloadFolder(ctx, this), basename + type.getUnzipExtension(ctx, this));
|
return new File(type.getDownloadFolder(ctx, this), basename + type.getUnzipExtension(ctx, this));
|
||||||
}
|
}
|
||||||
|
@ -170,6 +167,10 @@ public class IndexItem implements Comparable<IndexItem> {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDate(@NonNull DateFormat dateFormat, boolean remote) {
|
||||||
|
return remote ? getRemoteDate(dateFormat) : getLocalDate(dateFormat);
|
||||||
|
}
|
||||||
|
|
||||||
public String getRemoteDate(DateFormat dateFormat) {
|
public String getRemoteDate(DateFormat dateFormat) {
|
||||||
if(timestamp <= 0) {
|
if(timestamp <= 0) {
|
||||||
return "";
|
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) {
|
if(localTimestamp <= 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -199,6 +200,11 @@ public class IndexItem implements Comparable<IndexItem> {
|
||||||
this.downloaded = downloaded;
|
this.downloaded = downloaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasActualDataToDownload() {
|
||||||
|
return !isDownloaded() || isOutdated();
|
||||||
|
}
|
||||||
|
|
||||||
public void setLocalTimestamp(long localTimestamp) {
|
public void setLocalTimestamp(long localTimestamp) {
|
||||||
this.localTimestamp = localTimestamp;
|
this.localTimestamp = localTimestamp;
|
||||||
}
|
}
|
||||||
|
@ -211,20 +217,11 @@ public class IndexItem implements Comparable<IndexItem> {
|
||||||
return downloaded;
|
return downloaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getVisibleName(Context ctx, OsmandRegions osmandRegions) {
|
@Override
|
||||||
return type.getVisibleName(this, ctx, osmandRegions, true);
|
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) {
|
public String getDate(java.text.DateFormat format) {
|
||||||
return format.format(new Date(timestamp));
|
return format.format(new Date(timestamp));
|
||||||
}
|
}
|
||||||
|
|
122
OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java
Normal file
122
OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
113
OsmAnd/src/net/osmand/plus/download/MultipleIndexesUiHelper.java
Normal file
113
OsmAnd/src/net/osmand/plus/download/MultipleIndexesUiHelper.java
Normal 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));
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -10,9 +10,9 @@ import android.widget.TextView;
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.activities.OsmandBaseExpandableListAdapter;
|
import net.osmand.plus.activities.OsmandBaseExpandableListAdapter;
|
||||||
import net.osmand.plus.download.CustomIndexItem;
|
import net.osmand.plus.download.CustomIndexItem;
|
||||||
|
import net.osmand.plus.download.DownloadItem;
|
||||||
import net.osmand.plus.download.DownloadActivity;
|
import net.osmand.plus.download.DownloadActivity;
|
||||||
import net.osmand.plus.download.DownloadResourceGroup;
|
import net.osmand.plus.download.DownloadResourceGroup;
|
||||||
import net.osmand.plus.download.IndexItem;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -52,9 +52,9 @@ public class DownloadResourceGroupAdapter extends OsmandBaseExpandableListAdapte
|
||||||
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild,
|
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild,
|
||||||
View convertView, ViewGroup parent) {
|
View convertView, ViewGroup parent) {
|
||||||
final Object child = getChild(groupPosition, childPosition);
|
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);
|
DownloadResourceGroup group = getGroupObj(groupPosition);
|
||||||
ItemViewHolder viewHolder;
|
ItemViewHolder viewHolder;
|
||||||
if (convertView != null && convertView.getTag() instanceof ItemViewHolder) {
|
if (convertView != null && convertView.getTag() instanceof ItemViewHolder) {
|
||||||
|
|
|
@ -35,6 +35,7 @@ import net.osmand.plus.download.DownloadActivity;
|
||||||
import net.osmand.plus.download.DownloadActivity.BannerAndDownloadFreeVersion;
|
import net.osmand.plus.download.DownloadActivity.BannerAndDownloadFreeVersion;
|
||||||
import net.osmand.plus.download.DownloadActivityType;
|
import net.osmand.plus.download.DownloadActivityType;
|
||||||
import net.osmand.plus.download.DownloadIndexesThread.DownloadEvents;
|
import net.osmand.plus.download.DownloadIndexesThread.DownloadEvents;
|
||||||
|
import net.osmand.plus.download.DownloadItem;
|
||||||
import net.osmand.plus.download.DownloadResourceGroup;
|
import net.osmand.plus.download.DownloadResourceGroup;
|
||||||
import net.osmand.plus.download.DownloadResources;
|
import net.osmand.plus.download.DownloadResources;
|
||||||
import net.osmand.plus.download.DownloadValidationManager;
|
import net.osmand.plus.download.DownloadValidationManager;
|
||||||
|
@ -504,10 +505,10 @@ public class DownloadResourceGroupFragment extends DialogFragment implements Dow
|
||||||
|
|
||||||
DownloadItemFragment downloadItemFragment = DownloadItemFragment.createInstance(regionId, childPosition);
|
DownloadItemFragment downloadItemFragment = DownloadItemFragment.createInstance(regionId, childPosition);
|
||||||
((DownloadActivity) getActivity()).showDialog(getActivity(), downloadItemFragment);
|
((DownloadActivity) getActivity()).showDialog(getActivity(), downloadItemFragment);
|
||||||
} else if (child instanceof IndexItem) {
|
} else if (child instanceof DownloadItem) {
|
||||||
IndexItem indexItem = (IndexItem) child;
|
DownloadItem downloadItem = (DownloadItem) child;
|
||||||
ItemViewHolder vh = (ItemViewHolder) v.getTag();
|
ItemViewHolder vh = (ItemViewHolder) v.getTag();
|
||||||
OnClickListener ls = vh.getRightButtonAction(indexItem, vh.getClickAction(indexItem));
|
OnClickListener ls = vh.getRightButtonAction(downloadItem, vh.getClickAction(downloadItem));
|
||||||
ls.onClick(v);
|
ls.onClick(v);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,14 @@ import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.widget.PopupMenu;
|
import androidx.appcompat.widget.PopupMenu;
|
||||||
import androidx.core.view.ViewCompat;
|
import androidx.core.view.ViewCompat;
|
||||||
|
|
||||||
|
import net.osmand.map.OsmandRegions;
|
||||||
import net.osmand.map.WorldRegion;
|
import net.osmand.map.WorldRegion;
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.Version;
|
import net.osmand.plus.Version;
|
||||||
import net.osmand.plus.activities.LocalIndexHelper.LocalIndexType;
|
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.chooseplan.ChoosePlanDialogFragment;
|
||||||
import net.osmand.plus.download.CityItem;
|
import net.osmand.plus.download.CityItem;
|
||||||
import net.osmand.plus.download.CustomIndexItem;
|
import net.osmand.plus.download.CustomIndexItem;
|
||||||
|
import net.osmand.plus.download.DownloadItem;
|
||||||
import net.osmand.plus.download.DownloadActivity;
|
import net.osmand.plus.download.DownloadActivity;
|
||||||
import net.osmand.plus.download.DownloadActivityType;
|
import net.osmand.plus.download.DownloadActivityType;
|
||||||
import net.osmand.plus.download.DownloadResourceGroup;
|
import net.osmand.plus.download.DownloadResourceGroup;
|
||||||
import net.osmand.plus.download.DownloadResources;
|
import net.osmand.plus.download.DownloadResources;
|
||||||
import net.osmand.plus.download.IndexItem;
|
import net.osmand.plus.download.IndexItem;
|
||||||
|
import net.osmand.plus.download.MultipleIndexesUiHelper;
|
||||||
|
import net.osmand.plus.download.MultipleIndexesUiHelper.SelectItemsToDownloadListener;
|
||||||
|
import net.osmand.plus.download.MultipleIndexItem;
|
||||||
import net.osmand.plus.download.ui.LocalIndexesFragment.LocalIndexOperationTask;
|
import net.osmand.plus.download.ui.LocalIndexesFragment.LocalIndexOperationTask;
|
||||||
import net.osmand.plus.helpers.FileNameTranslationHelper;
|
import net.osmand.plus.helpers.FileNameTranslationHelper;
|
||||||
import net.osmand.plus.inapp.InAppPurchaseHelper;
|
import net.osmand.plus.inapp.InAppPurchaseHelper;
|
||||||
|
@ -43,6 +50,7 @@ import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class ItemViewHolder {
|
public class ItemViewHolder {
|
||||||
|
|
||||||
|
@ -137,24 +145,24 @@ public class ItemViewHolder {
|
||||||
depthContoursPurchased = InAppPurchaseHelper.isDepthContoursPurchased(context.getMyApplication());
|
depthContoursPurchased = InAppPurchaseHelper.isDepthContoursPurchased(context.getMyApplication());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bindIndexItem(final IndexItem indexItem) {
|
public void bindIndexItem(final DownloadItem downloadItem) {
|
||||||
bindIndexItem(indexItem, null);
|
bindIndexItem(downloadItem, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bindIndexItem(final IndexItem indexItem, final String cityName) {
|
public void bindIndexItem(final DownloadItem downloadItem, final String cityName) {
|
||||||
initAppStatusVariables();
|
initAppStatusVariables();
|
||||||
boolean isDownloading = context.getDownloadThread().isDownloading(indexItem);
|
boolean isDownloading = downloadItem.isDownloading(context.getDownloadThread());
|
||||||
int progress = -1;
|
int progress = -1;
|
||||||
if (context.getDownloadThread().getCurrentDownloadingItem() == indexItem) {
|
if (context.getDownloadThread().getCurrentDownloadingItem() == downloadItem) {
|
||||||
progress = context.getDownloadThread().getCurrentDownloadingItemProgress();
|
progress = context.getDownloadThread().getCurrentDownloadingItemProgress();
|
||||||
}
|
}
|
||||||
boolean disabled = checkDisabledAndClickAction(indexItem);
|
boolean disabled = checkDisabledAndClickAction(downloadItem);
|
||||||
/// name and left item
|
/// name and left item
|
||||||
String name;
|
String name;
|
||||||
if(showTypeInName) {
|
if(showTypeInName) {
|
||||||
name = indexItem.getType().getString(context);
|
name = downloadItem.getType().getString(context);
|
||||||
} else {
|
} 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;
|
String text = (!Algorithms.isEmpty(cityName) && !cityName.equals(name) ? cityName + "\n" : "") + name;
|
||||||
nameTextView.setText(text);
|
nameTextView.setText(text);
|
||||||
|
@ -164,43 +172,78 @@ public class ItemViewHolder {
|
||||||
nameTextView.setTextColor(textColorSecondary);
|
nameTextView.setTextColor(textColorSecondary);
|
||||||
}
|
}
|
||||||
int color = textColorSecondary;
|
int color = textColorSecondary;
|
||||||
if(indexItem.isDownloaded() && !isDownloading) {
|
if(downloadItem.isDownloaded() && !isDownloading) {
|
||||||
int colorId = indexItem.isOutdated() ? R.color.color_distance : R.color.color_ok;
|
int colorId = downloadItem.isOutdated() ? R.color.color_distance : R.color.color_ok;
|
||||||
color = context.getResources().getColor(colorId);
|
color = context.getResources().getColor(colorId);
|
||||||
}
|
}
|
||||||
if (indexItem.isDownloaded()) {
|
if (downloadItem.isDownloaded()) {
|
||||||
leftImageView.setImageDrawable(getContentIcon(context,
|
leftImageView.setImageDrawable(getContentIcon(context,
|
||||||
indexItem.getType().getIconResource(), color));
|
downloadItem.getType().getIconResource(), color));
|
||||||
} else if (disabled) {
|
} else if (disabled) {
|
||||||
leftImageView.setImageDrawable(getContentIcon(context,
|
leftImageView.setImageDrawable(getContentIcon(context,
|
||||||
indexItem.getType().getIconResource(), textColorSecondary));
|
downloadItem.getType().getIconResource(), textColorSecondary));
|
||||||
} else {
|
} else {
|
||||||
leftImageView.setImageDrawable(getContentIcon(context,
|
leftImageView.setImageDrawable(getContentIcon(context,
|
||||||
indexItem.getType().getIconResource()));
|
downloadItem.getType().getIconResource()));
|
||||||
}
|
}
|
||||||
descrTextView.setTextColor(textColorSecondary);
|
descrTextView.setTextColor(textColorSecondary);
|
||||||
if (!isDownloading) {
|
if (!isDownloading) {
|
||||||
progressBar.setVisibility(View.GONE);
|
progressBar.setVisibility(View.GONE);
|
||||||
descrTextView.setVisibility(View.VISIBLE);
|
descrTextView.setVisibility(View.VISIBLE);
|
||||||
if (indexItem instanceof CustomIndexItem && (((CustomIndexItem) indexItem).getSubName(context) != null)) {
|
if (downloadItem instanceof CustomIndexItem && (((CustomIndexItem) downloadItem).getSubName(context) != null)) {
|
||||||
descrTextView.setText(((CustomIndexItem) indexItem).getSubName(context));
|
descrTextView.setText(((CustomIndexItem) downloadItem).getSubName(context));
|
||||||
} else if (indexItem.getType() == DownloadActivityType.DEPTH_CONTOUR_FILE && !depthContoursPurchased) {
|
} else if (downloadItem.getType() == DownloadActivityType.DEPTH_CONTOUR_FILE && !depthContoursPurchased) {
|
||||||
descrTextView.setText(context.getString(R.string.depth_contour_descr));
|
descrTextView.setText(context.getString(R.string.depth_contour_descr));
|
||||||
} else if ((indexItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE
|
} else if ((downloadItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE
|
||||||
|| indexItem.getType() == DownloadActivityType.HILLSHADE_FILE
|
|| downloadItem.getType() == DownloadActivityType.HILLSHADE_FILE
|
||||||
|| indexItem.getType() == DownloadActivityType.SLOPE_FILE) && srtmDisabled) {
|
|| downloadItem.getType() == DownloadActivityType.SLOPE_FILE) && srtmDisabled) {
|
||||||
if (showTypeInName) {
|
if (showTypeInName) {
|
||||||
descrTextView.setText("");
|
descrTextView.setText("");
|
||||||
} else {
|
} else {
|
||||||
descrTextView.setText(indexItem.getType().getString(context));
|
descrTextView.setText(downloadItem.getType().getString(context));
|
||||||
}
|
}
|
||||||
} else if (showTypeInDesc) {
|
} else if (downloadItem instanceof MultipleIndexItem) {
|
||||||
descrTextView.setText(indexItem.getType().getString(context) +
|
MultipleIndexItem item = (MultipleIndexItem) downloadItem;
|
||||||
" • " + indexItem.getSizeDescription(context) +
|
String allRegionsHeader = context.getString(R.string.shared_strings_all_regions);
|
||||||
" • " + (showRemoteDate ? indexItem.getRemoteDate(dateFormat) : indexItem.getLocalDate(dateFormat)));
|
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 {
|
} else {
|
||||||
descrTextView.setText(indexItem.getSizeDescription(context) + " • " +
|
header = regionsHeader;
|
||||||
(showRemoteDate ? indexItem.getRemoteDate(dateFormat) : indexItem.getLocalDate(dateFormat)));
|
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 {
|
} else {
|
||||||
|
@ -209,18 +252,19 @@ public class ItemViewHolder {
|
||||||
progressBar.setProgress(progress);
|
progressBar.setProgress(progress);
|
||||||
|
|
||||||
if (showProgressInDesc) {
|
if (showProgressInDesc) {
|
||||||
double mb = indexItem.getArchiveSizeMB();
|
double mb = downloadItem.getArchiveSizeMB();
|
||||||
String v ;
|
String v ;
|
||||||
if (progress != -1) {
|
if (progress != -1) {
|
||||||
v = context.getString(R.string.value_downloaded_of_max, mb * progress / 100, mb);
|
v = context.getString(R.string.value_downloaded_of_max, mb * progress / 100, mb);
|
||||||
} else {
|
} else {
|
||||||
v = context.getString(R.string.file_size_in_mb, mb);
|
v = context.getString(R.string.file_size_in_mb, mb);
|
||||||
}
|
}
|
||||||
if(showTypeInDesc && indexItem.getType() == DownloadActivityType.ROADS_FILE) {
|
String fullDescription = v;
|
||||||
descrTextView.setText(indexItem.getType().getString(context) + " • " + v);
|
if(showTypeInDesc && downloadItem.getType() == DownloadActivityType.ROADS_FILE) {
|
||||||
} else {
|
fullDescription = context.getString(R.string.ltr_or_rtl_combine_via_bold_point,
|
||||||
descrTextView.setText(v);
|
downloadItem.getType().getString(context), fullDescription);
|
||||||
}
|
}
|
||||||
|
descrTextView.setText(fullDescription);
|
||||||
descrTextView.setVisibility(View.VISIBLE);
|
descrTextView.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
descrTextView.setVisibility(View.GONE);
|
descrTextView.setVisibility(View.GONE);
|
||||||
|
@ -241,44 +285,7 @@ public class ItemViewHolder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void download(IndexItem indexItem, DownloadResourceGroup parentOptional) {
|
private boolean checkDisabledAndClickAction(final DownloadItem item) {
|
||||||
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) {
|
|
||||||
RightButtonAction clickAction = getClickAction(item);
|
RightButtonAction clickAction = getClickAction(item);
|
||||||
boolean disabled = clickAction != RightButtonAction.DOWNLOAD;
|
boolean disabled = clickAction != RightButtonAction.DOWNLOAD;
|
||||||
OnClickListener action = getRightButtonAction(item, clickAction);
|
OnClickListener action = getRightButtonAction(item, clickAction);
|
||||||
|
@ -290,15 +297,15 @@ public class ItemViewHolder {
|
||||||
} else {
|
} else {
|
||||||
rightButton.setVisibility(View.GONE);
|
rightButton.setVisibility(View.GONE);
|
||||||
rightImageButton.setVisibility(View.VISIBLE);
|
rightImageButton.setVisibility(View.VISIBLE);
|
||||||
final boolean isDownloading = context.getDownloadThread().isDownloading(item);
|
final boolean isDownloading = item.isDownloading(context.getDownloadThread());
|
||||||
if (isDownloading) {
|
if (isDownloading) {
|
||||||
rightImageButton.setImageDrawable(getContentIcon(context, R.drawable.ic_action_remove_dark));
|
rightImageButton.setImageDrawable(getContentIcon(context, R.drawable.ic_action_remove_dark));
|
||||||
rightImageButton.setContentDescription(context.getString(R.string.shared_string_cancel));
|
rightImageButton.setContentDescription(context.getString(R.string.shared_string_cancel));
|
||||||
} else if(item.isDownloaded() && !item.isOutdated()) {
|
} else if(!item.hasActualDataToDownload()) {
|
||||||
rightImageButton.setImageDrawable(getContentIcon(context, R.drawable.ic_overflow_menu_white));
|
rightImageButton.setImageDrawable(getContentIcon(context, R.drawable.ic_overflow_menu_white));
|
||||||
rightImageButton.setContentDescription(context.getString(R.string.shared_string_more));
|
rightImageButton.setContentDescription(context.getString(R.string.shared_string_more));
|
||||||
} else {
|
} else {
|
||||||
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.setContentDescription(context.getString(R.string.shared_string_download));
|
||||||
}
|
}
|
||||||
rightImageButton.setOnClickListener(action);
|
rightImageButton.setOnClickListener(action);
|
||||||
|
@ -307,31 +314,37 @@ public class ItemViewHolder {
|
||||||
return disabled;
|
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")
|
@SuppressLint("DefaultLocale")
|
||||||
public RightButtonAction getClickAction(final IndexItem indexItem) {
|
public RightButtonAction getClickAction(final DownloadItem item) {
|
||||||
RightButtonAction clickAction = RightButtonAction.DOWNLOAD;
|
RightButtonAction clickAction = RightButtonAction.DOWNLOAD;
|
||||||
if (indexItem.getBasename().toLowerCase().equals(DownloadResources.WORLD_SEAMARKS_KEY)
|
if (item.getBasename().toLowerCase().equals(DownloadResources.WORLD_SEAMARKS_KEY)
|
||||||
&& nauticalPluginDisabled) {
|
&& nauticalPluginDisabled) {
|
||||||
clickAction = RightButtonAction.ASK_FOR_SEAMARKS_PLUGIN;
|
clickAction = RightButtonAction.ASK_FOR_SEAMARKS_PLUGIN;
|
||||||
} else if ((indexItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE
|
} else if ((item.getType() == DownloadActivityType.SRTM_COUNTRY_FILE
|
||||||
|| indexItem.getType() == DownloadActivityType.HILLSHADE_FILE
|
|| item.getType() == DownloadActivityType.HILLSHADE_FILE
|
||||||
|| indexItem.getType() == DownloadActivityType.SLOPE_FILE) && srtmDisabled) {
|
|| item.getType() == DownloadActivityType.SLOPE_FILE) && srtmDisabled) {
|
||||||
if (srtmNeedsInstallation) {
|
if (srtmNeedsInstallation) {
|
||||||
clickAction = RightButtonAction.ASK_FOR_SRTM_PLUGIN_PURCHASE;
|
clickAction = RightButtonAction.ASK_FOR_SRTM_PLUGIN_PURCHASE;
|
||||||
} else {
|
} else {
|
||||||
clickAction = RightButtonAction.ASK_FOR_SRTM_PLUGIN_ENABLE;
|
clickAction = RightButtonAction.ASK_FOR_SRTM_PLUGIN_ENABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (indexItem.getType() == DownloadActivityType.WIKIPEDIA_FILE
|
} else if (item.getType() == DownloadActivityType.WIKIPEDIA_FILE
|
||||||
&& !Version.isPaidVersion(context.getMyApplication())) {
|
&& !Version.isPaidVersion(context.getMyApplication())) {
|
||||||
clickAction = RightButtonAction.ASK_FOR_FULL_VERSION_PURCHASE;
|
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;
|
clickAction = RightButtonAction.ASK_FOR_DEPTH_CONTOURS_PURCHASE;
|
||||||
}
|
}
|
||||||
return clickAction;
|
return clickAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OnClickListener getRightButtonAction(final IndexItem item, final RightButtonAction clickAction) {
|
public OnClickListener getRightButtonAction(final DownloadItem item, final RightButtonAction clickAction) {
|
||||||
if (clickAction != RightButtonAction.DOWNLOAD) {
|
if (clickAction != RightButtonAction.DOWNLOAD) {
|
||||||
return new View.OnClickListener() {
|
return new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -370,7 +383,7 @@ public class ItemViewHolder {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
final boolean isDownloading = context.getDownloadThread().isDownloading(item);
|
final boolean isDownloading = item.isDownloading(context.getDownloadThread());
|
||||||
return new View.OnClickListener() {
|
return new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
|
@ -380,8 +393,8 @@ public class ItemViewHolder {
|
||||||
} else {
|
} else {
|
||||||
context.makeSureUserCancelDownload(item);
|
context.makeSureUserCancelDownload(item);
|
||||||
}
|
}
|
||||||
} else if(item.isDownloaded() && !item.isOutdated()){
|
} else if(!item.hasActualDataToDownload()){
|
||||||
contextMenu(v, item, item.getRelatedGroup());
|
showContextMenu(v, item, item.getRelatedGroup());
|
||||||
} else {
|
} else {
|
||||||
download(item, item.getRelatedGroup());
|
download(item, item.getRelatedGroup());
|
||||||
}
|
}
|
||||||
|
@ -390,52 +403,21 @@ public class ItemViewHolder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void contextMenu(View v, final IndexItem indexItem, final DownloadResourceGroup parentOptional) {
|
protected void showContextMenu(View v,
|
||||||
final PopupMenu optionsMenu = new PopupMenu(context, v);
|
final DownloadItem downloadItem,
|
||||||
|
final DownloadResourceGroup parentOptional) {
|
||||||
|
OsmandApplication app = context.getMyApplication();
|
||||||
|
PopupMenu optionsMenu = new PopupMenu(context, v);
|
||||||
MenuItem item;
|
MenuItem item;
|
||||||
|
|
||||||
final File fl = indexItem.getTargetFile(context.getMyApplication());
|
final List<File> downloadedFiles = downloadItem.getDownloadedFiles(app);
|
||||||
if (fl.exists()) {
|
if (!Algorithms.isEmpty(downloadedFiles)) {
|
||||||
item = optionsMenu.getMenu().add(R.string.shared_string_remove).setIcon(
|
item = optionsMenu.getMenu().add(R.string.shared_string_remove)
|
||||||
context.getMyApplication().getUIUtilities().getThemedIcon(R.drawable.ic_action_remove_dark));
|
.setIcon(getContentIcon(context, R.drawable.ic_action_remove_dark));
|
||||||
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onMenuItemClick(MenuItem item) {
|
public boolean onMenuItemClick(MenuItem item) {
|
||||||
LocalIndexType tp = LocalIndexType.MAP_DATA;
|
confirmRemove(downloadItem, downloadedFiles);
|
||||||
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();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -445,7 +427,7 @@ public class ItemViewHolder {
|
||||||
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onMenuItemClick(MenuItem item) {
|
public boolean onMenuItemClick(MenuItem item) {
|
||||||
download(indexItem, parentOptional);
|
download(downloadItem, parentOptional);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -453,6 +435,135 @@ public class ItemViewHolder {
|
||||||
optionsMenu.show();
|
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) {
|
private Drawable getContentIcon(DownloadActivity context, int resourceId) {
|
||||||
return context.getMyApplication().getUIUtilities().getThemedIcon(resourceId);
|
return context.getMyApplication().getUIUtilities().getThemedIcon(resourceId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,7 +153,8 @@ public class UpdatesIndexFragment extends OsmAndListFragment implements Download
|
||||||
for (IndexItem indexItem : indexItems) {
|
for (IndexItem indexItem : indexItems) {
|
||||||
downloadsSize += indexItem.getSize();
|
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.setText(updateAllText);
|
||||||
updateAllButton.setOnClickListener(new View.OnClickListener() {
|
updateAllButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
package net.osmand.plus.helpers;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import net.osmand.GPXUtilities.TrkSegment;
|
||||||
|
import net.osmand.GPXUtilities.WptPt;
|
||||||
|
import net.osmand.plus.OsmAndFormatter;
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.plus.UiUtilities;
|
||||||
|
import net.osmand.plus.helpers.TrackSelectSegmentAdapter.TrackViewHolder;
|
||||||
|
import net.osmand.util.MapUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TrackSelectSegmentAdapter extends RecyclerView.Adapter<TrackViewHolder> {
|
||||||
|
|
||||||
|
private final OsmandApplication app;
|
||||||
|
private final LayoutInflater themedInflater;
|
||||||
|
private final UiUtilities iconsCache;
|
||||||
|
private final List<TrkSegment> segments;
|
||||||
|
private OnItemClickListener onItemClickListener;
|
||||||
|
|
||||||
|
public TrackSelectSegmentAdapter(Context ctx, List<TrkSegment> segments) {
|
||||||
|
app = (OsmandApplication) ctx.getApplicationContext();
|
||||||
|
themedInflater = UiUtilities.getInflater(ctx, app.getDaynightHelper().isNightModeForMapControls());
|
||||||
|
iconsCache = app.getUIUtilities();
|
||||||
|
this.segments = segments;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public TrackViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
View view = themedInflater.inflate(R.layout.gpx_segment_list_item, parent, false);
|
||||||
|
ImageView distanceIcon = view.findViewById(R.id.distance_icon);
|
||||||
|
distanceIcon.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_split_interval));
|
||||||
|
ImageView timeIcon = view.findViewById(R.id.time_icon);
|
||||||
|
timeIcon.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_time_moving_16));
|
||||||
|
return new TrackViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull final TrackViewHolder holder, int position) {
|
||||||
|
holder.icon.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_split_interval));
|
||||||
|
|
||||||
|
TrkSegment segment = segments.get(position);
|
||||||
|
|
||||||
|
String segmentTitle = app.getResources().getString(R.string.segments_count, position + 1);
|
||||||
|
holder.name.setText(segmentTitle);
|
||||||
|
|
||||||
|
double distance = getDistance(segment);
|
||||||
|
long time = getSegmentTime(segment);
|
||||||
|
if (time != 1) {
|
||||||
|
holder.time.setText(OsmAndFormatter.getFormattedDurationShort((int) (time / 1000)));
|
||||||
|
} else {
|
||||||
|
holder.time.setText("");
|
||||||
|
}
|
||||||
|
holder.distance.setText(OsmAndFormatter.getFormattedDistance((float) distance, app));
|
||||||
|
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (onItemClickListener != null) {
|
||||||
|
onItemClickListener.onItemClick(holder.getAdapterPosition());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return segments.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long getSegmentTime(TrkSegment segment) {
|
||||||
|
long startTime = Long.MAX_VALUE;
|
||||||
|
long endTime = Long.MIN_VALUE;
|
||||||
|
for (int i = 0; i < segment.points.size(); i++) {
|
||||||
|
WptPt point = segment.points.get(i);
|
||||||
|
long time = point.time;
|
||||||
|
if (time != 0) {
|
||||||
|
startTime = Math.min(startTime, time);
|
||||||
|
endTime = Math.max(endTime, time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return endTime - startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getDistance(TrkSegment segment) {
|
||||||
|
double distance = 0;
|
||||||
|
WptPt prevPoint = null;
|
||||||
|
for (int i = 0; i < segment.points.size(); i++) {
|
||||||
|
WptPt point = segment.points.get(i);
|
||||||
|
if (prevPoint != null) {
|
||||||
|
distance += MapUtils.getDistance(prevPoint.getLatitude(), prevPoint.getLongitude(), point.getLatitude(), point.getLongitude());
|
||||||
|
}
|
||||||
|
prevPoint = point;
|
||||||
|
}
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAdapterListener(OnItemClickListener onItemClickListener) {
|
||||||
|
this.onItemClickListener = onItemClickListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnItemClickListener {
|
||||||
|
|
||||||
|
void onItemClick(int position);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class TrackViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
|
ImageView icon;
|
||||||
|
TextView name;
|
||||||
|
TextView distance;
|
||||||
|
TextView time;
|
||||||
|
|
||||||
|
TrackViewHolder(View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
icon = itemView.findViewById(R.id.icon);
|
||||||
|
name = itemView.findViewById(R.id.name);
|
||||||
|
distance = itemView.findViewById(R.id.distance);
|
||||||
|
time = itemView.findViewById(R.id.time_interval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
package net.osmand.plus.monitoring;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.plus.UiUtilities;
|
||||||
|
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
|
||||||
|
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
|
||||||
|
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription;
|
||||||
|
import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerSpaceItem;
|
||||||
|
import net.osmand.plus.monitoring.TripRecordingActiveBottomSheet.ItemType;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
|
public class ClearRecordedDataBottomSheetFragment extends MenuBottomSheetDialogFragment {
|
||||||
|
|
||||||
|
public static final String TAG = ClearRecordedDataBottomSheetFragment.class.getSimpleName();
|
||||||
|
|
||||||
|
private OsmandApplication app;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createMenuItems(Bundle savedInstanceState) {
|
||||||
|
app = requiredMyApplication();
|
||||||
|
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
|
||||||
|
int verticalBig = getResources().getDimensionPixelSize(R.dimen.dialog_content_margin);
|
||||||
|
int verticalSmall = getResources().getDimensionPixelSize(R.dimen.content_padding_small);
|
||||||
|
|
||||||
|
items.add(new BottomSheetItemWithDescription.Builder()
|
||||||
|
.setDescription(app.getString(R.string.clear_recorded_data_warning))
|
||||||
|
.setDescriptionColorId(!nightMode ? R.color.text_color_primary_light : R.color.text_color_primary_dark)
|
||||||
|
.setDescriptionMaxLines(2)
|
||||||
|
.setTitle(app.getString(R.string.clear_recorded_data))
|
||||||
|
.setLayoutId(R.layout.bottom_sheet_item_title_with_description)
|
||||||
|
.create());
|
||||||
|
|
||||||
|
items.add(new DividerSpaceItem(app, verticalBig));
|
||||||
|
|
||||||
|
items.add(new BaseBottomSheetItem.Builder()
|
||||||
|
.setCustomView(TripRecordingActiveBottomSheet.createButton(inflater, ItemType.CLEAR_DATA, nightMode))
|
||||||
|
.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
app.getSavingTrackHelper().clearRecordedData(true);
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.create());
|
||||||
|
|
||||||
|
items.add(new DividerSpaceItem(app, verticalBig));
|
||||||
|
|
||||||
|
items.add(new BaseBottomSheetItem.Builder()
|
||||||
|
.setCustomView(TripRecordingActiveBottomSheet.createButton(inflater, ItemType.CANCEL, nightMode))
|
||||||
|
.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.create());
|
||||||
|
|
||||||
|
items.add(new DividerSpaceItem(app, verticalSmall));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
Fragment target = getTargetFragment();
|
||||||
|
if (target instanceof TripRecordingActiveBottomSheet) {
|
||||||
|
((TripRecordingActiveBottomSheet) target).hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
Fragment target = getTargetFragment();
|
||||||
|
if (target instanceof TripRecordingActiveBottomSheet) {
|
||||||
|
((TripRecordingActiveBottomSheet) target).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean hideButtonsContainer() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showInstance(@NonNull FragmentManager fragmentManager, @NonNull Fragment target) {
|
||||||
|
if (!fragmentManager.isStateSaved()) {
|
||||||
|
ClearRecordedDataBottomSheetFragment fragment = new ClearRecordedDataBottomSheetFragment();
|
||||||
|
fragment.setTargetFragment(target, 0);
|
||||||
|
fragment.show(fragmentManager, TAG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,7 @@
|
||||||
package net.osmand.plus.monitoring;
|
package net.osmand.plus.monitoring;
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.DialogInterface.OnClickListener;
|
import android.content.DialogInterface.OnClickListener;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
@ -19,18 +17,18 @@ import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.widget.AppCompatCheckBox;
|
import androidx.appcompat.widget.AppCompatCheckBox;
|
||||||
import androidx.core.app.ActivityCompat;
|
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
import com.google.android.material.slider.Slider;
|
import com.google.android.material.slider.Slider;
|
||||||
|
|
||||||
import net.osmand.AndroidUtils;
|
import net.osmand.AndroidUtils;
|
||||||
import net.osmand.Location;
|
import net.osmand.Location;
|
||||||
import net.osmand.ValueHolder;
|
import net.osmand.ValueHolder;
|
||||||
|
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
|
||||||
import net.osmand.plus.NavigationService;
|
import net.osmand.plus.NavigationService;
|
||||||
import net.osmand.plus.OsmAndFormatter;
|
import net.osmand.plus.OsmAndFormatter;
|
||||||
import net.osmand.plus.OsmAndLocationProvider;
|
|
||||||
import net.osmand.plus.OsmAndTaskManager.OsmAndTaskRunnable;
|
import net.osmand.plus.OsmAndTaskManager.OsmAndTaskRunnable;
|
||||||
import net.osmand.plus.OsmandApplication;
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.OsmandPlugin;
|
import net.osmand.plus.OsmandPlugin;
|
||||||
|
@ -52,8 +50,6 @@ import net.osmand.util.Algorithms;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import gnu.trove.list.array.TIntArrayList;
|
|
||||||
|
|
||||||
import static net.osmand.plus.UiUtilities.CompoundButtonType.PROFILE_DEPENDENT;
|
import static net.osmand.plus.UiUtilities.CompoundButtonType.PROFILE_DEPENDENT;
|
||||||
|
|
||||||
public class OsmandMonitoringPlugin extends OsmandPlugin {
|
public class OsmandMonitoringPlugin extends OsmandPlugin {
|
||||||
|
@ -162,9 +158,9 @@ public class OsmandMonitoringPlugin extends OsmandPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final int[] SECONDS = new int[] {0, 1, 2, 3, 5, 10, 15, 20, 30, 60, 90};
|
public static final int[] SECONDS = new int[]{0, 1, 2, 3, 5, 10, 15, 20, 30, 60, 90};
|
||||||
public static final int[] MINUTES = new int[] {2, 3, 5};
|
public static final int[] MINUTES = new int[]{2, 3, 5};
|
||||||
public static final int[] MAX_INTERVAL_TO_SEND_MINUTES = new int[] {1, 2, 5, 10, 15, 20, 30, 60, 90, 2 * 60, 3 * 60, 4 * 60, 6 * 60, 12 * 60, 24 * 60};
|
public static final int[] MAX_INTERVAL_TO_SEND_MINUTES = new int[]{1, 2, 5, 10, 15, 20, 30, 60, 90, 2 * 60, 3 * 60, 4 * 60, 6 * 60, 12 * 60, 24 * 60};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SettingsScreenType getSettingsScreenType() {
|
public SettingsScreenType getSettingsScreenType() {
|
||||||
|
@ -182,9 +178,10 @@ public class OsmandMonitoringPlugin extends OsmandPlugin {
|
||||||
private TextInfoWidget createMonitoringControl(final MapActivity map) {
|
private TextInfoWidget createMonitoringControl(final MapActivity map) {
|
||||||
monitoringControl = new TextInfoWidget(map) {
|
monitoringControl = new TextInfoWidget(map) {
|
||||||
long lastUpdateTime;
|
long lastUpdateTime;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean updateInfo(DrawSettings drawSettings) {
|
public boolean updateInfo(DrawSettings drawSettings) {
|
||||||
if(isSaving){
|
if (isSaving) {
|
||||||
setText(map.getString(R.string.shared_string_save), "");
|
setText(map.getString(R.string.shared_string_save), "");
|
||||||
setIcons(R.drawable.widget_monitoring_rec_big_day, R.drawable.widget_monitoring_rec_big_night);
|
setIcons(R.drawable.widget_monitoring_rec_big_day, R.drawable.widget_monitoring_rec_big_night);
|
||||||
return true;
|
return true;
|
||||||
|
@ -212,7 +209,7 @@ public class OsmandMonitoringPlugin extends OsmandPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean liveMonitoringEnabled = liveMonitoringHelper.isLiveMonitoringEnabled();
|
final boolean liveMonitoringEnabled = liveMonitoringHelper.isLiveMonitoringEnabled();
|
||||||
if(globalRecord) {
|
if (globalRecord) {
|
||||||
//indicates global recording (+background recording)
|
//indicates global recording (+background recording)
|
||||||
if (liveMonitoringEnabled) {
|
if (liveMonitoringEnabled) {
|
||||||
dn = R.drawable.widget_live_monitoring_rec_big_night;
|
dn = R.drawable.widget_live_monitoring_rec_big_night;
|
||||||
|
@ -317,8 +314,27 @@ public class OsmandMonitoringPlugin extends OsmandPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SelectedGpxFile getCurrentTrack() {
|
||||||
|
return app.getSavingTrackHelper().getCurrentTrack();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean wasTrackMonitored() {
|
||||||
|
return settings.SAVE_GLOBAL_TRACK_TO_GPX.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasDataToSave() {
|
||||||
|
return app.getSavingTrackHelper().hasDataToSave();
|
||||||
|
}
|
||||||
|
|
||||||
public void controlDialog(final Activity activity, final boolean showTrackSelection) {
|
public void controlDialog(final Activity activity, final boolean showTrackSelection) {
|
||||||
final boolean wasTrackMonitored = settings.SAVE_GLOBAL_TRACK_TO_GPX.get();
|
FragmentManager fragmentManager = ((FragmentActivity) activity).getSupportFragmentManager();
|
||||||
|
if (hasDataToSave() || wasTrackMonitored()) {
|
||||||
|
TripRecordingActiveBottomSheet.showInstance(fragmentManager, getCurrentTrack());
|
||||||
|
} else {
|
||||||
|
TripRecordingBottomSheet.showInstance(fragmentManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*final boolean wasTrackMonitored = settings.SAVE_GLOBAL_TRACK_TO_GPX.get();
|
||||||
final boolean nightMode;
|
final boolean nightMode;
|
||||||
if (activity instanceof MapActivity) {
|
if (activity instanceof MapActivity) {
|
||||||
nightMode = app.getDaynightHelper().isNightModeForMapControls();
|
nightMode = app.getDaynightHelper().isNightModeForMapControls();
|
||||||
|
@ -415,8 +431,8 @@ public class OsmandMonitoringPlugin extends OsmandPlugin {
|
||||||
run.run();
|
run.run();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
bld.show();
|
// bld.show();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveCurrentTrack() {
|
public void saveCurrentTrack() {
|
||||||
|
@ -478,7 +494,7 @@ public class OsmandMonitoringPlugin extends OsmandPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopRecording(){
|
public void stopRecording() {
|
||||||
settings.SAVE_GLOBAL_TRACK_TO_GPX.set(false);
|
settings.SAVE_GLOBAL_TRACK_TO_GPX.set(false);
|
||||||
if (app.getNavigationService() != null) {
|
if (app.getNavigationService() != null) {
|
||||||
app.getNavigationService().stopIfNeeded(app, NavigationService.USED_BY_GPX);
|
app.getNavigationService().stopIfNeeded(app, NavigationService.USED_BY_GPX);
|
||||||
|
@ -567,11 +583,11 @@ public class OsmandMonitoringPlugin extends OsmandPlugin {
|
||||||
public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) {
|
public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) {
|
||||||
String s;
|
String s;
|
||||||
int progress = (int) value;
|
int progress = (int) value;
|
||||||
if(progress == 0) {
|
if (progress == 0) {
|
||||||
s = uiCtx.getString(R.string.int_continuosly);
|
s = uiCtx.getString(R.string.int_continuosly);
|
||||||
v.value = 0;
|
v.value = 0;
|
||||||
} else {
|
} else {
|
||||||
if(progress < secondsLength) {
|
if (progress < secondsLength) {
|
||||||
s = seconds[progress] + " " + uiCtx.getString(R.string.int_seconds);
|
s = seconds[progress] + " " + uiCtx.getString(R.string.int_seconds);
|
||||||
v.value = seconds[progress] * 1000;
|
v.value = seconds[progress] * 1000;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
package net.osmand.plus.monitoring;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
import net.osmand.plus.OsmandPlugin;
|
||||||
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.plus.UiUtilities;
|
||||||
|
import net.osmand.plus.activities.MapActivity;
|
||||||
|
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
|
||||||
|
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
|
||||||
|
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription;
|
||||||
|
import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerSpaceItem;
|
||||||
|
import net.osmand.plus.monitoring.TripRecordingActiveBottomSheet.ItemType;
|
||||||
|
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
|
public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragment {
|
||||||
|
|
||||||
|
public static final String TAG = StopTrackRecordingBottomFragment.class.getSimpleName();
|
||||||
|
|
||||||
|
private OsmandApplication app;
|
||||||
|
private MapActivity mapActivity;
|
||||||
|
private OsmandSettings settings;
|
||||||
|
private OsmandMonitoringPlugin plugin;
|
||||||
|
private ItemType tag = ItemType.CANCEL;
|
||||||
|
|
||||||
|
public void setMapActivity(MapActivity mapActivity) {
|
||||||
|
this.mapActivity = mapActivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createMenuItems(Bundle savedInstanceState) {
|
||||||
|
app = requiredMyApplication();
|
||||||
|
settings = app.getSettings();
|
||||||
|
plugin = OsmandPlugin.getPlugin(OsmandMonitoringPlugin.class);
|
||||||
|
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
|
||||||
|
int verticalBig = getResources().getDimensionPixelSize(R.dimen.dialog_content_margin);
|
||||||
|
int verticalSmall = getResources().getDimensionPixelSize(R.dimen.content_padding_small);
|
||||||
|
|
||||||
|
items.add(new BottomSheetItemWithDescription.Builder()
|
||||||
|
.setDescription(app.getString(R.string.track_recording_description))
|
||||||
|
.setDescriptionColorId(!nightMode ? R.color.text_color_primary_light : R.color.text_color_primary_dark)
|
||||||
|
.setDescriptionMaxLines(4)
|
||||||
|
.setTitle(app.getString(R.string.track_recording_title))
|
||||||
|
.setLayoutId(R.layout.bottom_sheet_item_title_with_description)
|
||||||
|
.create());
|
||||||
|
|
||||||
|
items.add(new DividerSpaceItem(app, verticalBig));
|
||||||
|
|
||||||
|
items.add(new BaseBottomSheetItem.Builder()
|
||||||
|
.setCustomView(TripRecordingActiveBottomSheet.createButton(inflater, ItemType.STOP_AND_DISCARD, nightMode))
|
||||||
|
.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
tag = ItemType.STOP_AND_DISCARD;
|
||||||
|
if (plugin != null && settings.SAVE_GLOBAL_TRACK_TO_GPX.get()) {
|
||||||
|
plugin.stopRecording();
|
||||||
|
app.getNotificationHelper().refreshNotifications();
|
||||||
|
}
|
||||||
|
app.getSavingTrackHelper().clearRecordedData(true);
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.create());
|
||||||
|
|
||||||
|
items.add(new DividerSpaceItem(app, verticalBig));
|
||||||
|
|
||||||
|
items.add(new BaseBottomSheetItem.Builder()
|
||||||
|
.setCustomView(TripRecordingActiveBottomSheet.createButton(inflater, ItemType.SAVE_AND_STOP, nightMode))
|
||||||
|
.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
tag = ItemType.SAVE_AND_STOP;
|
||||||
|
if (plugin != null && settings.SAVE_GLOBAL_TRACK_TO_GPX.get()) {
|
||||||
|
plugin.saveCurrentTrack(null, mapActivity);
|
||||||
|
app.getNotificationHelper().refreshNotifications();
|
||||||
|
}
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.create());
|
||||||
|
|
||||||
|
items.add(new DividerSpaceItem(app, verticalSmall));
|
||||||
|
|
||||||
|
items.add(new BaseBottomSheetItem.Builder()
|
||||||
|
.setCustomView(TripRecordingActiveBottomSheet.createButton(inflater, ItemType.CANCEL, nightMode))
|
||||||
|
.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
tag = ItemType.CANCEL;
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.create());
|
||||||
|
|
||||||
|
items.add(new DividerSpaceItem(app, verticalSmall));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
Fragment target = getTargetFragment();
|
||||||
|
if (target instanceof TripRecordingActiveBottomSheet) {
|
||||||
|
((TripRecordingActiveBottomSheet) target).hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
if (tag == ItemType.CANCEL) {
|
||||||
|
Fragment target = getTargetFragment();
|
||||||
|
if (target instanceof TripRecordingActiveBottomSheet) {
|
||||||
|
((TripRecordingActiveBottomSheet) target).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean hideButtonsContainer() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showInstance(MapActivity mapActivity, @NonNull FragmentManager fragmentManager, @NonNull Fragment target) {
|
||||||
|
if (!fragmentManager.isStateSaved()) {
|
||||||
|
StopTrackRecordingBottomFragment fragment = new StopTrackRecordingBottomFragment();
|
||||||
|
fragment.setMapActivity(mapActivity);
|
||||||
|
fragment.setTargetFragment(target, 0);
|
||||||
|
fragment.show(fragmentManager, TAG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,645 @@
|
||||||
|
package net.osmand.plus.monitoring;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.ColorStateList;
|
||||||
|
import android.graphics.Typeface;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.util.TypedValue;
|
||||||
|
import android.text.format.DateUtils;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.ColorRes;
|
||||||
|
import androidx.annotation.DrawableRes;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
|
import androidx.appcompat.content.res.AppCompatResources;
|
||||||
|
import androidx.appcompat.widget.AppCompatImageView;
|
||||||
|
import androidx.appcompat.widget.SwitchCompat;
|
||||||
|
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.core.graphics.drawable.DrawableCompat;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
|
import net.osmand.AndroidUtils;
|
||||||
|
import net.osmand.GPXUtilities.GPXFile;
|
||||||
|
import net.osmand.PlatformUtil;
|
||||||
|
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.plus.UiUtilities;
|
||||||
|
import net.osmand.plus.UiUtilities.DialogButtonType;
|
||||||
|
import net.osmand.plus.activities.MapActivity;
|
||||||
|
import net.osmand.plus.activities.SavingTrackHelper;
|
||||||
|
import net.osmand.plus.activities.SavingTrackHelper.SaveGpxResult;
|
||||||
|
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
|
||||||
|
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
|
||||||
|
import net.osmand.plus.helpers.AndroidUiHelper;
|
||||||
|
import net.osmand.plus.helpers.FontCache;
|
||||||
|
import net.osmand.plus.myplaces.SaveCurrentTrackTask;
|
||||||
|
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||||
|
import net.osmand.plus.track.GpxBlockStatisticsBuilder;
|
||||||
|
import net.osmand.plus.track.SaveGpxAsyncTask.SaveGpxListener;
|
||||||
|
import net.osmand.plus.track.TrackAppearanceFragment;
|
||||||
|
import net.osmand.plus.widgets.TextViewEx;
|
||||||
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
|
import static net.osmand.plus.UiUtilities.CompoundButtonType.PROFILE_DEPENDENT;
|
||||||
|
|
||||||
|
public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragment {
|
||||||
|
|
||||||
|
public static final String TAG = TripRecordingActiveBottomSheet.class.getSimpleName();
|
||||||
|
private static final Log log = PlatformUtil.getLog(TripRecordingActiveBottomSheet.class);
|
||||||
|
private static final String UPDATE_CURRENT_GPX_FILE = "update_current_gpx_file";
|
||||||
|
private static final int GENERAL_UPDATE_GPS_INTERVAL = 1000;
|
||||||
|
private static final int GENERAL_UPDATE_SAVE_INTERVAL = 1000;
|
||||||
|
|
||||||
|
private OsmandApplication app;
|
||||||
|
private OsmandSettings settings;
|
||||||
|
private SavingTrackHelper helper;
|
||||||
|
private SelectedGpxFile selectedGpxFile;
|
||||||
|
|
||||||
|
private View statusContainer;
|
||||||
|
private View buttonSave;
|
||||||
|
private GpxBlockStatisticsBuilder blockStatisticsBuilder;
|
||||||
|
|
||||||
|
private final Handler handler = new Handler();
|
||||||
|
private Runnable updatingGPS;
|
||||||
|
private Runnable updatingTimeTrackSaved;
|
||||||
|
|
||||||
|
private GPXFile getGPXFile() {
|
||||||
|
return selectedGpxFile.getGpxFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSelectedGpxFile(SelectedGpxFile selectedGpxFile) {
|
||||||
|
this.selectedGpxFile = selectedGpxFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasDataToSave() {
|
||||||
|
return app.getSavingTrackHelper().hasDataToSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean searchingGPS() {
|
||||||
|
return app.getLocationProvider().getLastKnownLocation() == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean wasTrackMonitored() {
|
||||||
|
return settings.SAVE_GLOBAL_TRACK_TO_GPX.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showInstance(@NonNull FragmentManager fragmentManager, SelectedGpxFile selectedGpxFile) {
|
||||||
|
if (!fragmentManager.isStateSaved()) {
|
||||||
|
TripRecordingActiveBottomSheet fragment = new TripRecordingActiveBottomSheet();
|
||||||
|
fragment.setSelectedGpxFile(selectedGpxFile);
|
||||||
|
fragment.show(fragmentManager, TAG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createMenuItems(Bundle savedInstanceState) {
|
||||||
|
app = requiredMyApplication();
|
||||||
|
settings = app.getSettings();
|
||||||
|
helper = app.getSavingTrackHelper();
|
||||||
|
LayoutInflater inflater = UiUtilities.getInflater(getContext(), nightMode);
|
||||||
|
final FragmentManager fragmentManager = getFragmentManager();
|
||||||
|
|
||||||
|
View itemView = inflater.inflate(R.layout.trip_recording_active_fragment, null, false);
|
||||||
|
items.add(new BaseBottomSheetItem.Builder()
|
||||||
|
.setCustomView(itemView)
|
||||||
|
.create());
|
||||||
|
|
||||||
|
View buttonClear = itemView.findViewById(R.id.button_clear);
|
||||||
|
View buttonSegment = itemView.findViewById(R.id.button_segment);
|
||||||
|
buttonSave = itemView.findViewById(R.id.button_save);
|
||||||
|
final View buttonPause = itemView.findViewById(R.id.button_pause);
|
||||||
|
View buttonStop = itemView.findViewById(R.id.button_stop);
|
||||||
|
|
||||||
|
createItem(buttonClear, ItemType.CLEAR_DATA, hasDataToSave(), null);
|
||||||
|
createItem(buttonSegment, ItemType.START_SEGMENT, wasTrackMonitored(), null);
|
||||||
|
createItem(buttonPause, wasTrackMonitored() ? ItemType.PAUSE : ItemType.RESUME, true, null);
|
||||||
|
createItem(buttonStop, ItemType.STOP, true, null);
|
||||||
|
|
||||||
|
statusContainer = itemView.findViewById(R.id.status_container);
|
||||||
|
updateStatus();
|
||||||
|
|
||||||
|
RecyclerView statBlocks = itemView.findViewById(R.id.block_statistics);
|
||||||
|
if (savedInstanceState != null) {
|
||||||
|
if (savedInstanceState.containsKey(UPDATE_CURRENT_GPX_FILE)
|
||||||
|
&& savedInstanceState.getBoolean(UPDATE_CURRENT_GPX_FILE)) {
|
||||||
|
selectedGpxFile = app.getSavingTrackHelper().getCurrentTrack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blockStatisticsBuilder = new GpxBlockStatisticsBuilder(app, selectedGpxFile);
|
||||||
|
blockStatisticsBuilder.setBlocksView(statBlocks);
|
||||||
|
blockStatisticsBuilder.setBlocksClickable(false);
|
||||||
|
blockStatisticsBuilder.initStatBlocks(null, ContextCompat.getColor(app, getActiveTextColorId(nightMode)), nightMode);
|
||||||
|
|
||||||
|
LinearLayout showTrackContainer = itemView.findViewById(R.id.show_track_on_map);
|
||||||
|
showTrackContainer.setMinimumHeight(app.getResources().getDimensionPixelSize(R.dimen.bottom_sheet_list_item_height));
|
||||||
|
|
||||||
|
final LinearLayout buttonShow = showTrackContainer.findViewById(R.id.basic_item_body);
|
||||||
|
TextView showTrackTitle = buttonShow.findViewById(R.id.title);
|
||||||
|
Integer showTitle = ItemType.SHOW_TRACK.getTitleId();
|
||||||
|
if (showTitle != null) {
|
||||||
|
showTrackTitle.setText(showTitle);
|
||||||
|
}
|
||||||
|
showTrackTitle.setTextColor(ContextCompat.getColor(app, getActiveIconColorId(nightMode)));
|
||||||
|
showTrackTitle.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimensionPixelSize(R.dimen.default_desc_text_size));
|
||||||
|
Typeface typeface = FontCache.getFont(app, app.getResources().getString(R.string.font_roboto_medium));
|
||||||
|
showTrackTitle.setTypeface(typeface);
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
float letterSpacing = AndroidUtils.getFloatValueFromRes(app, R.dimen.description_letter_spacing);
|
||||||
|
showTrackTitle.setLetterSpacing(letterSpacing);
|
||||||
|
}
|
||||||
|
final SwitchCompat showTrackOnMapButton = buttonShow.findViewById(R.id.switch_button);
|
||||||
|
showTrackOnMapButton.setChecked(app.getSelectedGpxHelper().getSelectedCurrentRecordingTrack() != null);
|
||||||
|
UiUtilities.setupCompoundButton(showTrackOnMapButton, nightMode, PROFILE_DEPENDENT);
|
||||||
|
|
||||||
|
final LinearLayout buttonAppearance = showTrackContainer.findViewById(R.id.additional_button);
|
||||||
|
View divider = buttonAppearance.getChildAt(0);
|
||||||
|
AndroidUiHelper.setVisibility(View.GONE, divider);
|
||||||
|
int marginS = app.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_small);
|
||||||
|
UiUtilities.setMargins(buttonAppearance, marginS, 0, 0, 0);
|
||||||
|
String width = settings.CURRENT_TRACK_WIDTH.get();
|
||||||
|
boolean showArrows = settings.CURRENT_TRACK_SHOW_ARROWS.get();
|
||||||
|
int color = settings.CURRENT_TRACK_COLOR.get();
|
||||||
|
Drawable appearanceDrawable = TrackAppearanceFragment.getTrackIcon(app, width, showArrows, color);
|
||||||
|
AppCompatImageView appearanceIcon = buttonAppearance.findViewById(R.id.icon_after_divider);
|
||||||
|
int marginTrackIconH = app.getResources().getDimensionPixelSize(R.dimen.content_padding_small);
|
||||||
|
UiUtilities.setMargins(appearanceIcon, marginTrackIconH, 0, marginTrackIconH, 0);
|
||||||
|
appearanceIcon.setImageDrawable(appearanceDrawable);
|
||||||
|
buttonAppearance.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (showTrackOnMapButton.isChecked()) {
|
||||||
|
MapActivity mapActivity = getMapActivity();
|
||||||
|
if (mapActivity != null) {
|
||||||
|
hide();
|
||||||
|
SelectedGpxFile selectedGpxFile = app.getSavingTrackHelper().getCurrentTrack();
|
||||||
|
TrackAppearanceFragment.showInstance(mapActivity, selectedGpxFile, TripRecordingActiveBottomSheet.this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
createItem(buttonAppearance, ItemType.APPEARANCE, showTrackOnMapButton.isChecked(), null);
|
||||||
|
setShowOnMapBackground(buttonShow, app, showTrackOnMapButton.isChecked(), nightMode);
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
buttonShow.setBackgroundTintList(null);
|
||||||
|
}
|
||||||
|
buttonShow.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
boolean checked = !showTrackOnMapButton.isChecked();
|
||||||
|
showTrackOnMapButton.setChecked(checked);
|
||||||
|
app.getSelectedGpxHelper().selectGpxFile(app.getSavingTrackHelper().getCurrentGpx(), checked, false);
|
||||||
|
createItem(buttonAppearance, ItemType.APPEARANCE, checked, null);
|
||||||
|
setShowOnMapBackground(buttonShow, app, checked, nightMode);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
buttonClear.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (fragmentManager != null && hasDataToSave()) {
|
||||||
|
ClearRecordedDataBottomSheetFragment.showInstance(fragmentManager, TripRecordingActiveBottomSheet.this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
buttonSegment.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (wasTrackMonitored()) {
|
||||||
|
blockStatisticsBuilder.stopUpdatingStatBlocks();
|
||||||
|
helper.startNewSegment();
|
||||||
|
blockStatisticsBuilder.runUpdatingStatBlocksIfNeeded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
buttonSave.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (hasDataToSave()) {
|
||||||
|
final GPXFile gpxFile = getGPXFile();
|
||||||
|
new SaveCurrentTrackTask(app, gpxFile, createSaveListener(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
blockStatisticsBuilder.stopUpdatingStatBlocks();
|
||||||
|
blockStatisticsBuilder.runUpdatingStatBlocksIfNeeded();
|
||||||
|
stopUpdatingTimeTrackSaved();
|
||||||
|
runUpdatingTimeTrackSaved();
|
||||||
|
}
|
||||||
|
})).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
buttonPause.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
boolean wasTrackMonitored = !wasTrackMonitored();
|
||||||
|
if (!wasTrackMonitored) {
|
||||||
|
blockStatisticsBuilder.stopUpdatingStatBlocks();
|
||||||
|
} else {
|
||||||
|
blockStatisticsBuilder.runUpdatingStatBlocksIfNeeded();
|
||||||
|
}
|
||||||
|
settings.SAVE_GLOBAL_TRACK_TO_GPX.set(wasTrackMonitored);
|
||||||
|
updateStatus();
|
||||||
|
createItem(buttonPause, wasTrackMonitored ? ItemType.PAUSE : ItemType.RESUME, true, null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
buttonStop.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (fragmentManager != null) {
|
||||||
|
StopTrackRecordingBottomFragment.showInstance(getMapActivity(), fragmentManager, TripRecordingActiveBottomSheet.this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
outState.putBoolean(UPDATE_CURRENT_GPX_FILE, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateStatus() {
|
||||||
|
TextView statusTitle = statusContainer.findViewById(R.id.text_status);
|
||||||
|
AppCompatImageView statusIcon = statusContainer.findViewById(R.id.icon_status);
|
||||||
|
ItemType status = searchingGPS() ? ItemType.SEARCHING_GPS : !wasTrackMonitored() ? ItemType.ON_PAUSE : ItemType.RECORDING;
|
||||||
|
Integer titleId = status.getTitleId();
|
||||||
|
if (titleId != null) {
|
||||||
|
statusTitle.setText(titleId);
|
||||||
|
}
|
||||||
|
int colorText = status.equals(ItemType.SEARCHING_GPS) ? getSecondaryTextColorId(nightMode) : getOsmandIconColorId(nightMode);
|
||||||
|
statusTitle.setTextColor(ContextCompat.getColor(app, colorText));
|
||||||
|
Integer iconId = status.getIconId();
|
||||||
|
if (iconId != null) {
|
||||||
|
int colorDrawable = ContextCompat.getColor(app,
|
||||||
|
status.equals(ItemType.SEARCHING_GPS) ? getSecondaryIconColorId(nightMode) : getOsmandIconColorId(nightMode));
|
||||||
|
Drawable statusDrawable = UiUtilities.tintDrawable(AppCompatResources.getDrawable(app, iconId), colorDrawable);
|
||||||
|
statusIcon.setImageDrawable(statusDrawable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createItem(View view, ItemType type, boolean enabled, @Nullable String description) {
|
||||||
|
view.setTag(type);
|
||||||
|
LinearLayout button = view.findViewById(R.id.button_container);
|
||||||
|
|
||||||
|
AppCompatImageView icon = view.findViewById(R.id.icon);
|
||||||
|
if (icon != null) {
|
||||||
|
setTintedIcon(icon, enabled, nightMode, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextView title = view.findViewById(R.id.button_text);
|
||||||
|
Integer titleId = type.getTitleId();
|
||||||
|
if (title != null && titleId != null) {
|
||||||
|
title.setText(titleId);
|
||||||
|
setTextColor(title, enabled, nightMode, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextViewEx desc = view.findViewById(R.id.desc);
|
||||||
|
if (desc != null) {
|
||||||
|
boolean isShowDesc = !Algorithms.isBlank(description);
|
||||||
|
int marginDesc = isShowDesc ? 0 : app.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_medium);
|
||||||
|
AndroidUiHelper.updateVisibility(desc, isShowDesc);
|
||||||
|
if (title != null) {
|
||||||
|
UiUtilities.setMargins(title, 0, marginDesc, 0, marginDesc);
|
||||||
|
}
|
||||||
|
desc.setText(description);
|
||||||
|
setTextColor(desc, false, nightMode, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
setItemBackground(button != null ? button : (LinearLayout) view, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static View createButton(LayoutInflater inflater, ItemType type, boolean nightMode) {
|
||||||
|
View button = inflater.inflate(R.layout.bottom_sheet_button_with_icon, null);
|
||||||
|
button.setTag(type);
|
||||||
|
Context context = button.getContext();
|
||||||
|
LinearLayout container = button.findViewById(R.id.button_container);
|
||||||
|
container.setClickable(false);
|
||||||
|
container.setFocusable(false);
|
||||||
|
|
||||||
|
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
|
||||||
|
int horizontal = context.getResources().getDimensionPixelSize(R.dimen.content_padding);
|
||||||
|
params.setMargins(horizontal, 0, horizontal, 0);
|
||||||
|
button.setLayoutParams(params);
|
||||||
|
|
||||||
|
if (type.getTitleId() != null) {
|
||||||
|
UiUtilities.setupDialogButton(nightMode, button, type.getEffect(), type.getTitleId());
|
||||||
|
}
|
||||||
|
|
||||||
|
TextViewEx title = button.findViewById(R.id.button_text);
|
||||||
|
int margin = context.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_medium);
|
||||||
|
UiUtilities.setMargins(title, 0, margin, 0, margin);
|
||||||
|
|
||||||
|
int colorRes;
|
||||||
|
if (type.getEffect() == UiUtilities.DialogButtonType.SECONDARY_HARMFUL) {
|
||||||
|
colorRes = R.color.color_osm_edit_delete;
|
||||||
|
} else {
|
||||||
|
colorRes = nightMode ? R.color.dlg_btn_secondary_text_dark : R.color.dlg_btn_secondary_text_light;
|
||||||
|
}
|
||||||
|
AppCompatImageView icon = button.findViewById(R.id.icon);
|
||||||
|
if (type.getIconId() != null) {
|
||||||
|
Drawable drawable = AppCompatResources.getDrawable(context, type.getIconId());
|
||||||
|
UiUtilities.tintDrawable(drawable, ContextCompat.getColor(context, colorRes));
|
||||||
|
icon.setImageDrawable(drawable);
|
||||||
|
}
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getTimeTrackSaved() {
|
||||||
|
long timeTrackSaved = helper.getLastTimeFileSaved();
|
||||||
|
if (timeTrackSaved != 0) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
CharSequence time = DateUtils.getRelativeTimeSpanString(timeTrackSaved, now, DateUtils.MINUTE_IN_MILLIS);
|
||||||
|
return String.valueOf(time);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
blockStatisticsBuilder.runUpdatingStatBlocksIfNeeded();
|
||||||
|
runUpdatingGPS();
|
||||||
|
runUpdatingTimeTrackSaved();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
blockStatisticsBuilder.stopUpdatingStatBlocks();
|
||||||
|
stopUpdatingGPS();
|
||||||
|
stopUpdatingTimeTrackSaved();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopUpdatingGPS() {
|
||||||
|
handler.removeCallbacks(updatingGPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runUpdatingGPS() {
|
||||||
|
updatingGPS = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
int interval = app.getSettings().SAVE_GLOBAL_TRACK_INTERVAL.get();
|
||||||
|
updateStatus();
|
||||||
|
handler.postDelayed(this, Math.max(GENERAL_UPDATE_GPS_INTERVAL, interval));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
handler.post(updatingGPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopUpdatingTimeTrackSaved() {
|
||||||
|
handler.removeCallbacks(updatingTimeTrackSaved);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runUpdatingTimeTrackSaved() {
|
||||||
|
updatingTimeTrackSaved = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
String time = getTimeTrackSaved();
|
||||||
|
createItem(buttonSave, ItemType.SAVE, hasDataToSave(), !Algorithms.isEmpty(time) ? time : null);
|
||||||
|
handler.postDelayed(this, GENERAL_UPDATE_SAVE_INTERVAL);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
handler.post(updatingTimeTrackSaved);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SaveGpxListener createSaveListener(@Nullable final Runnable callback) {
|
||||||
|
return new SaveGpxListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void gpxSavingStarted() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void gpxSavingFinished(Exception errorMessage) {
|
||||||
|
String gpxFileName = Algorithms.getFileWithoutDirs(getGPXFile().path);
|
||||||
|
final MapActivity mapActivity = getMapActivity();
|
||||||
|
final Context context = getContext();
|
||||||
|
final SaveGpxResult result = helper.saveDataToGpx(app.getAppCustomization().getTracksDir());
|
||||||
|
if (mapActivity != null && context != null) {
|
||||||
|
final WeakReference<MapActivity> mapActivityRef = new WeakReference<>(mapActivity);
|
||||||
|
final FragmentManager fragmentManager = mapActivityRef.get().getSupportFragmentManager();
|
||||||
|
@SuppressLint({"StringFormatInvalid", "LocalSuppress"})
|
||||||
|
Snackbar snackbar = Snackbar.make(getView(),
|
||||||
|
app.getResources().getString(R.string.shared_string_file_is_saved, gpxFileName),
|
||||||
|
Snackbar.LENGTH_LONG)
|
||||||
|
.setAction(R.string.shared_string_rename, new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
fragmentManager.beginTransaction().remove(TripRecordingActiveBottomSheet.this).commitAllowingStateLoss();
|
||||||
|
SaveGPXBottomSheetFragment.showInstance(fragmentManager, result.getFilenames());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
View view = snackbar.getView();
|
||||||
|
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) view.getLayoutParams();
|
||||||
|
params.gravity = Gravity.TOP;
|
||||||
|
AndroidUtils.setMargins(params, 0, AndroidUtils.getStatusBarHeight(context), 0, 0);
|
||||||
|
view.setLayoutParams(params);
|
||||||
|
UiUtilities.setupSnackbar(snackbar, nightMode);
|
||||||
|
snackbar.show();
|
||||||
|
if (callback != null) {
|
||||||
|
callback.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public MapActivity getMapActivity() {
|
||||||
|
Activity activity = getActivity();
|
||||||
|
if (activity instanceof MapActivity) {
|
||||||
|
return (MapActivity) activity;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void show() {
|
||||||
|
Dialog dialog = getDialog();
|
||||||
|
if (dialog != null) {
|
||||||
|
dialog.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hide() {
|
||||||
|
Dialog dialog = getDialog();
|
||||||
|
if (dialog != null) {
|
||||||
|
dialog.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ItemType {
|
||||||
|
SHOW_TRACK(R.string.shared_string_show_on_map, null, null),
|
||||||
|
APPEARANCE(null, null, null),
|
||||||
|
SEARCHING_GPS(R.string.searching_gps, R.drawable.ic_action_gps_info, null),
|
||||||
|
RECORDING(R.string.recording_default_name, R.drawable.ic_action_track_recordable, null),
|
||||||
|
ON_PAUSE(R.string.on_pause, R.drawable.ic_pause, null),
|
||||||
|
CLEAR_DATA(R.string.clear_recorded_data, R.drawable.ic_action_delete_dark, UiUtilities.DialogButtonType.SECONDARY_HARMFUL),
|
||||||
|
START_SEGMENT(R.string.gpx_start_new_segment, R.drawable.ic_action_new_segment, null),
|
||||||
|
SAVE(R.string.shared_string_save, R.drawable.ic_action_save_to_file, null),
|
||||||
|
PAUSE(R.string.shared_string_pause, R.drawable.ic_pause, null),
|
||||||
|
RESUME(R.string.shared_string_resume, R.drawable.ic_play_dark, null),
|
||||||
|
STOP(R.string.shared_string_control_stop, R.drawable.ic_action_rec_stop, null),
|
||||||
|
STOP_AND_DISCARD(R.string.track_recording_stop_without_saving, R.drawable.ic_action_rec_stop, DialogButtonType.SECONDARY_HARMFUL),
|
||||||
|
SAVE_AND_STOP(R.string.track_recording_save_and_stop, R.drawable.ic_action_save_to_file, DialogButtonType.SECONDARY),
|
||||||
|
CANCEL(R.string.shared_string_cancel, R.drawable.ic_action_close, DialogButtonType.SECONDARY);
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
private final Integer titleId;
|
||||||
|
@DrawableRes
|
||||||
|
private final Integer iconId;
|
||||||
|
private final DialogButtonType effect;
|
||||||
|
|
||||||
|
ItemType(@Nullable @StringRes Integer titleId, @Nullable @DrawableRes Integer iconId, @Nullable DialogButtonType effect) {
|
||||||
|
this.titleId = titleId;
|
||||||
|
this.iconId = iconId;
|
||||||
|
this.effect = effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Integer getTitleId() {
|
||||||
|
return titleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Integer getIconId() {
|
||||||
|
return iconId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public DialogButtonType getEffect() {
|
||||||
|
return effect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setItemBackground(LinearLayout view, boolean enabled) {
|
||||||
|
Drawable background = AppCompatResources.getDrawable(app, R.drawable.btn_background_inactive_light);
|
||||||
|
if (background != null && enabled) {
|
||||||
|
ColorStateList iconColorStateList = AndroidUtils.createPressedColorStateList(
|
||||||
|
app, getInactiveButtonColorId(nightMode), getActiveButtonColorId(nightMode)
|
||||||
|
);
|
||||||
|
DrawableCompat.setTintList(background, iconColorStateList);
|
||||||
|
} else {
|
||||||
|
UiUtilities.tintDrawable(background, ContextCompat.getColor(app, getInactiveButtonColorId(nightMode)));
|
||||||
|
}
|
||||||
|
view.setBackgroundDrawable(background);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setShowOnMapBackground(LinearLayout view, Context context, boolean checked, boolean nightMode) {
|
||||||
|
Drawable background = AppCompatResources.getDrawable(context,
|
||||||
|
nightMode ? checked ? R.drawable.btn_background_inactive_dark : R.drawable.btn_background_stroked_inactive_dark
|
||||||
|
: checked ? R.drawable.btn_background_inactive_light : R.drawable.btn_background_stroked_inactive_light);
|
||||||
|
view.setBackgroundDrawable(background);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTextColor(TextView tv, boolean enabled, boolean nightMode, ItemType type) {
|
||||||
|
if (tv != null) {
|
||||||
|
int activeColorId = type == ItemType.CLEAR_DATA ? R.color.color_osm_edit_delete : getActiveTextColorId(nightMode);
|
||||||
|
int normalColorId = enabled ? activeColorId : getSecondaryTextColorId(nightMode);
|
||||||
|
ColorStateList textColorStateList = AndroidUtils.createPressedColorStateList(app, normalColorId, getPressedColorId(nightMode));
|
||||||
|
tv.setTextColor(textColorStateList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTintedIcon(AppCompatImageView iv, boolean enabled, boolean nightMode, ItemType type) {
|
||||||
|
Integer iconId = type.getIconId();
|
||||||
|
if (iv != null && iconId != null) {
|
||||||
|
Drawable icon = AppCompatResources.getDrawable(app, iconId);
|
||||||
|
int activeColorId = type == ItemType.CLEAR_DATA ? R.color.color_osm_edit_delete : getActiveIconColorId(nightMode);
|
||||||
|
int normalColorId = enabled ? activeColorId : getSecondaryIconColorId(nightMode);
|
||||||
|
ColorStateList iconColorStateList = AndroidUtils.createPressedColorStateList(app, normalColorId, getPressedColorId(nightMode));
|
||||||
|
if (icon != null) {
|
||||||
|
DrawableCompat.setTintList(icon, iconColorStateList);
|
||||||
|
}
|
||||||
|
iv.setImageDrawable(icon);
|
||||||
|
if (type == ItemType.STOP) {
|
||||||
|
int stopSize = iv.getResources().getDimensionPixelSize(R.dimen.bottom_sheet_icon_margin_large);
|
||||||
|
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(stopSize, stopSize);
|
||||||
|
iv.setLayoutParams(params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ColorRes
|
||||||
|
private static int getActiveTextColorId(boolean nightMode) {
|
||||||
|
return nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ColorRes
|
||||||
|
private static int getSecondaryTextColorId(boolean nightMode) {
|
||||||
|
return nightMode ? R.color.text_color_secondary_dark : R.color.text_color_secondary_light;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ColorRes
|
||||||
|
private static int getActiveIconColorId(boolean nightMode) {
|
||||||
|
return nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ColorRes
|
||||||
|
private static int getSecondaryIconColorId(boolean nightMode) {
|
||||||
|
return nightMode ? R.color.icon_color_secondary_dark : R.color.icon_color_secondary_light;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ColorRes
|
||||||
|
private static int getActiveButtonColorId(boolean nightMode) {
|
||||||
|
return nightMode ? R.color.active_buttons_and_links_bg_pressed_dark : R.color.active_buttons_and_links_bg_pressed_light;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ColorRes
|
||||||
|
private static int getInactiveButtonColorId(boolean nightMode) {
|
||||||
|
return nightMode ? R.color.inactive_buttons_and_links_bg_dark : R.color.inactive_buttons_and_links_bg_light;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ColorRes
|
||||||
|
private static int getOsmandIconColorId(boolean nightMode) {
|
||||||
|
return nightMode ? R.color.icon_color_osmand_dark : R.color.icon_color_osmand_light;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ColorRes
|
||||||
|
private static int getPressedColorId(boolean nightMode) {
|
||||||
|
return nightMode ? R.color.active_buttons_and_links_text_dark : R.color.active_buttons_and_links_text_light;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getDismissButtonHeight() {
|
||||||
|
return getResources().getDimensionPixelSize(R.dimen.bottom_sheet_cancel_button_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getDismissButtonTextId() {
|
||||||
|
return R.string.shared_string_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean useVerticalButtons() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,6 +32,7 @@ import net.osmand.plus.R;
|
||||||
import net.osmand.plus.UiUtilities;
|
import net.osmand.plus.UiUtilities;
|
||||||
import net.osmand.plus.UiUtilities.DialogButtonType;
|
import net.osmand.plus.UiUtilities.DialogButtonType;
|
||||||
import net.osmand.plus.activities.MapActivity;
|
import net.osmand.plus.activities.MapActivity;
|
||||||
|
import net.osmand.plus.activities.SavingTrackHelper;
|
||||||
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
|
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
|
||||||
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription;
|
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription;
|
||||||
import net.osmand.plus.helpers.AndroidUiHelper;
|
import net.osmand.plus.helpers.AndroidUiHelper;
|
||||||
|
@ -246,12 +247,12 @@ public class TripRecordingBottomSheet extends MenuBottomSheetDialogFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getRightButtonHeight(){
|
protected int getRightButtonHeight() {
|
||||||
return getResources().getDimensionPixelSize(R.dimen.bottom_sheet_cancel_button_height);
|
return getResources().getDimensionPixelSize(R.dimen.bottom_sheet_cancel_button_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getDismissButtonHeight(){
|
protected int getDismissButtonHeight() {
|
||||||
return getResources().getDimensionPixelSize(R.dimen.bottom_sheet_cancel_button_height);
|
return getResources().getDimensionPixelSize(R.dimen.bottom_sheet_cancel_button_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,9 +278,14 @@ public class TripRecordingBottomSheet extends MenuBottomSheetDialogFragment {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRightBottomButtonClick() {
|
protected void onRightBottomButtonClick() {
|
||||||
app.getSavingTrackHelper().startNewSegment();
|
SavingTrackHelper helper = app.getSavingTrackHelper();
|
||||||
|
helper.startNewSegment();
|
||||||
settings.SAVE_GLOBAL_TRACK_TO_GPX.set(true);
|
settings.SAVE_GLOBAL_TRACK_TO_GPX.set(true);
|
||||||
app.startNavigationService(NavigationService.USED_BY_GPX);
|
app.startNavigationService(NavigationService.USED_BY_GPX);
|
||||||
|
MapActivity mapActivity = getMapActivity();
|
||||||
|
if (mapActivity != null) {
|
||||||
|
TripRecordingActiveBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), helper.getCurrentTrack());
|
||||||
|
}
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,10 @@ public class SaveCurrentTrackTask extends AsyncTask<Void, Void, Boolean> {
|
||||||
}
|
}
|
||||||
for (final String f : files.keySet()) {
|
for (final String f : files.keySet()) {
|
||||||
File fout = new File(dir, f + IndexConstants.GPX_FILE_EXT);
|
File fout = new File(dir, f + IndexConstants.GPX_FILE_EXT);
|
||||||
GPXUtilities.writeGpxFile(fout, gpx);
|
Exception exception = GPXUtilities.writeGpxFile(fout, gpx);
|
||||||
|
if (exception == null) {
|
||||||
|
app.getSavingTrackHelper().setLastTimeFileSaved(fout.lastModified());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return shouldClearPath;
|
return shouldClearPath;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,9 @@ public class BugBottomSheetDialog extends MenuBottomSheetDialogFragment {
|
||||||
textBox.setDefaultHintTextColor(colorStateList);
|
textBox.setDefaultHintTextColor(colorStateList);
|
||||||
noteText = osmNoteView.findViewById(R.id.name_edit_text);
|
noteText = osmNoteView.findViewById(R.id.name_edit_text);
|
||||||
noteText.setText(text);
|
noteText.setText(text);
|
||||||
|
if (noteText.requestFocus()) {
|
||||||
|
AndroidUtils.showSoftKeyboard(getActivity(), noteText);
|
||||||
|
}
|
||||||
|
|
||||||
BaseBottomSheetItem editOsmNote = new BaseBottomSheetItem.Builder()
|
BaseBottomSheetItem editOsmNote = new BaseBottomSheetItem.Builder()
|
||||||
.setCustomView(osmNoteView)
|
.setCustomView(osmNoteView)
|
||||||
|
|
|
@ -62,10 +62,11 @@ import net.osmand.plus.routing.RouteProvider;
|
||||||
import net.osmand.plus.routing.RouteProvider.GPXRouteParamsBuilder;
|
import net.osmand.plus.routing.RouteProvider.GPXRouteParamsBuilder;
|
||||||
import net.osmand.plus.routing.RoutingHelper;
|
import net.osmand.plus.routing.RoutingHelper;
|
||||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||||
import net.osmand.plus.views.layers.MapControlsLayer;
|
import net.osmand.plus.track.TrackSelectSegmentBottomSheet;
|
||||||
|
import net.osmand.plus.track.TrackSelectSegmentBottomSheet.OnSegmentSelectedListener;
|
||||||
|
import net.osmand.plus.views.layers.MapControlsLayer.MapControlsThemeInfoProvider;
|
||||||
import net.osmand.plus.widgets.popup.PopUpMenuHelper;
|
import net.osmand.plus.widgets.popup.PopUpMenuHelper;
|
||||||
import net.osmand.plus.widgets.popup.PopUpMenuItem;
|
import net.osmand.plus.widgets.popup.PopUpMenuItem;
|
||||||
import net.osmand.util.Algorithms;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
|
||||||
|
@ -75,7 +76,7 @@ import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
public class FollowTrackFragment extends ContextMenuScrollFragment implements CardListener,
|
public class FollowTrackFragment extends ContextMenuScrollFragment implements CardListener,
|
||||||
IRouteInformationListener, MapControlsLayer.MapControlsThemeInfoProvider {
|
IRouteInformationListener, MapControlsThemeInfoProvider, OnSegmentSelectedListener {
|
||||||
|
|
||||||
public static final String TAG = FollowTrackFragment.class.getName();
|
public static final String TAG = FollowTrackFragment.class.getName();
|
||||||
|
|
||||||
|
@ -210,20 +211,8 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca
|
||||||
if (gpxFile == null || selectingTrack) {
|
if (gpxFile == null || selectingTrack) {
|
||||||
setupTracksCard();
|
setupTracksCard();
|
||||||
} else {
|
} else {
|
||||||
String fileName = null;
|
|
||||||
File file = null;
|
|
||||||
if (!Algorithms.isEmpty(gpxFile.path)) {
|
|
||||||
file = new File(gpxFile.path);
|
|
||||||
fileName = file.getName();
|
|
||||||
} else if (!Algorithms.isEmpty(gpxFile.tracks)) {
|
|
||||||
fileName = gpxFile.tracks.get(0).name;
|
|
||||||
}
|
|
||||||
if (Algorithms.isEmpty(fileName)) {
|
|
||||||
fileName = app.getString(R.string.shared_string_gpx_track);
|
|
||||||
}
|
|
||||||
sortButton.setVisibility(View.GONE);
|
sortButton.setVisibility(View.GONE);
|
||||||
GPXInfo gpxInfo = new GPXInfo(fileName, file != null ? file.lastModified() : 0, file != null ? file.length() : 0);
|
TrackEditCard importTrackCard = new TrackEditCard(mapActivity, gpxFile);
|
||||||
TrackEditCard importTrackCard = new TrackEditCard(mapActivity, gpxInfo);
|
|
||||||
importTrackCard.setListener(this);
|
importTrackCard.setListener(this);
|
||||||
cardsContainer.addView(importTrackCard.build(mapActivity));
|
cardsContainer.addView(importTrackCard.build(mapActivity));
|
||||||
|
|
||||||
|
@ -490,14 +479,26 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca
|
||||||
String fileName = gpxInfo.getFileName();
|
String fileName = gpxInfo.getFileName();
|
||||||
SelectedGpxFile selectedGpxFile = app.getSelectedGpxHelper().getSelectedFileByName(fileName);
|
SelectedGpxFile selectedGpxFile = app.getSelectedGpxHelper().getSelectedFileByName(fileName);
|
||||||
if (selectedGpxFile != null) {
|
if (selectedGpxFile != null) {
|
||||||
selectTrackToFollow(selectedGpxFile.getGpxFile());
|
GPXFile gpxFile = selectedGpxFile.getGpxFile();
|
||||||
|
if (gpxFile.getNonEmptySegmentsCount() > 1) {
|
||||||
|
TrackSelectSegmentBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), gpxFile, this);
|
||||||
|
} else {
|
||||||
|
selectTrackToFollow(gpxFile);
|
||||||
updateSelectionMode(false);
|
updateSelectionMode(false);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
CallbackWithObject<GPXFile[]> callback = new CallbackWithObject<GPXFile[]>() {
|
CallbackWithObject<GPXFile[]> callback = new CallbackWithObject<GPXFile[]>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean processResult(GPXFile[] result) {
|
public boolean processResult(GPXFile[] result) {
|
||||||
|
MapActivity mapActivity = getMapActivity();
|
||||||
|
if (mapActivity != null) {
|
||||||
|
if (result[0].getNonEmptySegmentsCount() > 1) {
|
||||||
|
TrackSelectSegmentBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), result[0], FollowTrackFragment.this);
|
||||||
|
} else {
|
||||||
selectTrackToFollow(result[0]);
|
selectTrackToFollow(result[0]);
|
||||||
updateSelectionMode(false);
|
updateSelectionMode(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -716,4 +717,16 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca
|
||||||
protected String getThemeInfoProviderTag() {
|
protected String getThemeInfoProviderTag() {
|
||||||
return TAG;
|
return TAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSegmentSelect(GPXFile gpxFile, int selectedSegment) {
|
||||||
|
selectTrackToFollow(gpxFile);
|
||||||
|
GPXRouteParamsBuilder paramsBuilder = app.getRoutingHelper().getCurrentGPXRoute();
|
||||||
|
if (paramsBuilder != null) {
|
||||||
|
paramsBuilder.setSelectedSegment(selectedSegment);
|
||||||
|
app.getSettings().GPX_ROUTE_SEGMENT.set(selectedSegment);
|
||||||
|
app.getRoutingHelper().onSettingsChanged(true);
|
||||||
|
}
|
||||||
|
updateSelectionMode(false);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1675,6 +1675,13 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
|
||||||
if (Algorithms.isEmpty(fileName)) {
|
if (Algorithms.isEmpty(fileName)) {
|
||||||
fileName = app.getString(R.string.shared_string_gpx_track);
|
fileName = app.getString(R.string.shared_string_gpx_track);
|
||||||
}
|
}
|
||||||
|
GPXRouteParamsBuilder routeParams = app.getRoutingHelper().getCurrentGPXRoute();
|
||||||
|
|
||||||
|
if (gpxFile.getNonEmptySegmentsCount() > 1 && routeParams != null && routeParams.getSelectedSegment() != -1) {
|
||||||
|
int selectedSegmentCount = routeParams.getSelectedSegment() + 1;
|
||||||
|
int totalSegmentCount = routeParams.getFile().getNonEmptyTrkSegments(false).size();
|
||||||
|
fileName = app.getResources().getString(R.string.of, selectedSegmentCount, totalSegmentCount) + ", " + fileName;
|
||||||
|
}
|
||||||
title.setText(GpxUiHelper.getGpxTitle(fileName));
|
title.setText(GpxUiHelper.getGpxTitle(fileName));
|
||||||
description.setText(R.string.follow_track);
|
description.setText(R.string.follow_track);
|
||||||
buttonDescription.setText(R.string.shared_string_add);
|
buttonDescription.setText(R.string.shared_string_add);
|
||||||
|
|
|
@ -4,26 +4,33 @@ import android.graphics.drawable.ColorDrawable;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import net.osmand.AndroidUtils;
|
import net.osmand.AndroidUtils;
|
||||||
|
import net.osmand.GPXUtilities;
|
||||||
|
import net.osmand.GPXUtilities.GPXFile;
|
||||||
import net.osmand.plus.GPXDatabase.GpxDataItem;
|
import net.osmand.plus.GPXDatabase.GpxDataItem;
|
||||||
import net.osmand.plus.GpxDbHelper.GpxDataItemCallback;
|
import net.osmand.plus.GpxDbHelper.GpxDataItemCallback;
|
||||||
|
import net.osmand.plus.OsmAndFormatter;
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.UiUtilities;
|
import net.osmand.plus.UiUtilities;
|
||||||
import net.osmand.plus.activities.MapActivity;
|
import net.osmand.plus.activities.MapActivity;
|
||||||
import net.osmand.plus.helpers.GpxUiHelper;
|
import net.osmand.plus.helpers.GpxUiHelper;
|
||||||
import net.osmand.plus.helpers.GpxUiHelper.GPXInfo;
|
import net.osmand.plus.helpers.GpxUiHelper.GPXInfo;
|
||||||
|
import net.osmand.plus.helpers.TrackSelectSegmentAdapter;
|
||||||
|
import net.osmand.plus.routing.RouteProvider.GPXRouteParamsBuilder;
|
||||||
import net.osmand.util.Algorithms;
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class TrackEditCard extends BaseCard {
|
public class TrackEditCard extends BaseCard {
|
||||||
|
|
||||||
private GPXInfo gpxInfo;
|
private final GPXFile gpxFile;
|
||||||
|
|
||||||
public TrackEditCard(MapActivity mapActivity, GPXInfo gpxInfo) {
|
public TrackEditCard(MapActivity mapActivity, GPXFile gpxFile) {
|
||||||
super(mapActivity);
|
super(mapActivity);
|
||||||
this.gpxInfo = gpxInfo;
|
this.gpxFile = gpxFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -50,11 +57,47 @@ public class TrackEditCard extends BaseCard {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateContent() {
|
protected void updateContent() {
|
||||||
String fileName = Algorithms.getFileWithoutDirs(gpxInfo.getFileName());
|
String fileName = null;
|
||||||
String title = GpxUiHelper.getGpxTitle(fileName);
|
File file = null;
|
||||||
|
if (!Algorithms.isEmpty(gpxFile.path)) {
|
||||||
|
file = new File(gpxFile.path);
|
||||||
|
fileName = gpxFile.path;
|
||||||
|
} else if (!Algorithms.isEmpty(gpxFile.tracks)) {
|
||||||
|
fileName = gpxFile.tracks.get(0).name;
|
||||||
|
}
|
||||||
|
if (Algorithms.isEmpty(fileName)) {
|
||||||
|
fileName = app.getString(R.string.shared_string_gpx_track);
|
||||||
|
}
|
||||||
|
|
||||||
|
GPXInfo gpxInfo = new GPXInfo(gpxFile.path, file != null ? file.lastModified() : 0, file != null ? file.length() : 0);
|
||||||
GpxDataItem dataItem = getDataItem(gpxInfo);
|
GpxDataItem dataItem = getDataItem(gpxInfo);
|
||||||
|
String title = GpxUiHelper.getGpxTitle(Algorithms.getFileWithoutDirs(fileName));
|
||||||
|
GPXRouteParamsBuilder routeParams = app.getRoutingHelper().getCurrentGPXRoute();
|
||||||
|
if (gpxFile.getNonEmptySegmentsCount() > 1 && routeParams != null && routeParams.getSelectedSegment() != -1) {
|
||||||
|
int selectedSegmentCount = routeParams.getSelectedSegment() + 1;
|
||||||
|
int totalSegmentCount = routeParams.getFile().getNonEmptyTrkSegments(false).size();
|
||||||
|
title = app.getResources().getString(R.string.of, selectedSegmentCount, totalSegmentCount) + ", " + title;
|
||||||
|
}
|
||||||
GpxUiHelper.updateGpxInfoView(view, title, gpxInfo, dataItem, false, app);
|
GpxUiHelper.updateGpxInfoView(view, title, gpxInfo, dataItem, false, app);
|
||||||
|
|
||||||
|
if (gpxFile.getNonEmptySegmentsCount() > 1 && routeParams != null && routeParams.getSelectedSegment() != -1) {
|
||||||
|
TextView distanceView = view.findViewById(R.id.distance);
|
||||||
|
TextView timeView = view.findViewById(R.id.time);
|
||||||
|
TextView pointsView = view.findViewById(R.id.points_count);
|
||||||
|
List<GPXUtilities.TrkSegment> segments = gpxFile.getNonEmptyTrkSegments(false);
|
||||||
|
GPXUtilities.TrkSegment segment = segments.get(routeParams.getSelectedSegment());
|
||||||
|
int point = segment.points.size();
|
||||||
|
double distance = TrackSelectSegmentAdapter.getDistance(segment);
|
||||||
|
long time = TrackSelectSegmentAdapter.getSegmentTime(segment);
|
||||||
|
if (time != 1) {
|
||||||
|
timeView.setText(OsmAndFormatter.getFormattedDurationShort((int) (time / 1000)));
|
||||||
|
} else {
|
||||||
|
timeView.setText("");
|
||||||
|
}
|
||||||
|
distanceView.setText(OsmAndFormatter.getFormattedDistance((float) distance, app));
|
||||||
|
pointsView.setText(String.valueOf(point));
|
||||||
|
}
|
||||||
|
|
||||||
ImageButton editButton = view.findViewById(R.id.show_on_map);
|
ImageButton editButton = view.findViewById(R.id.show_on_map);
|
||||||
editButton.setVisibility(View.VISIBLE);
|
editButton.setVisibility(View.VISIBLE);
|
||||||
editButton.setImageDrawable(getContentIcon(R.drawable.ic_action_edit_dark));
|
editButton.setImageDrawable(getContentIcon(R.drawable.ic_action_edit_dark));
|
||||||
|
|
|
@ -8,7 +8,6 @@ import android.util.Base64;
|
||||||
import net.osmand.GPXUtilities;
|
import net.osmand.GPXUtilities;
|
||||||
import net.osmand.GPXUtilities.GPXFile;
|
import net.osmand.GPXUtilities.GPXFile;
|
||||||
import net.osmand.GPXUtilities.Route;
|
import net.osmand.GPXUtilities.Route;
|
||||||
import net.osmand.GPXUtilities.Track;
|
|
||||||
import net.osmand.GPXUtilities.TrkSegment;
|
import net.osmand.GPXUtilities.TrkSegment;
|
||||||
import net.osmand.GPXUtilities.WptPt;
|
import net.osmand.GPXUtilities.WptPt;
|
||||||
import net.osmand.Location;
|
import net.osmand.Location;
|
||||||
|
@ -20,15 +19,15 @@ import net.osmand.data.LatLon;
|
||||||
import net.osmand.data.LocationPoint;
|
import net.osmand.data.LocationPoint;
|
||||||
import net.osmand.data.WptLocationPoint;
|
import net.osmand.data.WptLocationPoint;
|
||||||
import net.osmand.plus.OsmandApplication;
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.onlinerouting.OnlineRoutingHelper;
|
|
||||||
import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine.OnlineRoutingResponse;
|
|
||||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
|
||||||
import net.osmand.plus.settings.backend.CommonPreference;
|
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.TargetPointsHelper;
|
import net.osmand.plus.TargetPointsHelper;
|
||||||
import net.osmand.plus.TargetPointsHelper.TargetPoint;
|
import net.osmand.plus.TargetPointsHelper.TargetPoint;
|
||||||
|
import net.osmand.plus.onlinerouting.OnlineRoutingHelper;
|
||||||
|
import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine.OnlineRoutingResponse;
|
||||||
import net.osmand.plus.render.NativeOsmandLibrary;
|
import net.osmand.plus.render.NativeOsmandLibrary;
|
||||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||||
|
import net.osmand.plus.settings.backend.CommonPreference;
|
||||||
|
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||||
import net.osmand.router.GeneralRouter;
|
import net.osmand.router.GeneralRouter;
|
||||||
import net.osmand.router.GeneralRouter.RoutingParameter;
|
import net.osmand.router.GeneralRouter.RoutingParameter;
|
||||||
import net.osmand.router.GeneralRouter.RoutingParameterType;
|
import net.osmand.router.GeneralRouter.RoutingParameterType;
|
||||||
|
@ -161,6 +160,7 @@ public class RouteProvider {
|
||||||
private boolean leftSide;
|
private boolean leftSide;
|
||||||
private boolean passWholeRoute;
|
private boolean passWholeRoute;
|
||||||
private boolean calculateOsmAndRouteParts;
|
private boolean calculateOsmAndRouteParts;
|
||||||
|
private int selectedSegment = -1;
|
||||||
|
|
||||||
public GPXRouteParamsBuilder(GPXFile file, OsmandSettings settings) {
|
public GPXRouteParamsBuilder(GPXFile file, OsmandSettings settings) {
|
||||||
leftSide = settings.DRIVING_REGION.get().leftHandDriving;
|
leftSide = settings.DRIVING_REGION.get().leftHandDriving;
|
||||||
|
@ -191,6 +191,14 @@ public class RouteProvider {
|
||||||
this.calculateOsmAndRoute = calculateOsmAndRoute;
|
this.calculateOsmAndRoute = calculateOsmAndRoute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getSelectedSegment() {
|
||||||
|
return selectedSegment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSelectedSegment(int selectedSegment) {
|
||||||
|
this.selectedSegment = selectedSegment;
|
||||||
|
}
|
||||||
|
|
||||||
public void setPassWholeRoute(boolean passWholeRoute) {
|
public void setPassWholeRoute(boolean passWholeRoute) {
|
||||||
this.passWholeRoute = passWholeRoute;
|
this.passWholeRoute = passWholeRoute;
|
||||||
}
|
}
|
||||||
|
@ -278,8 +286,9 @@ public class RouteProvider {
|
||||||
wpt.add(new WptLocationPoint(w));
|
wpt.add(new WptLocationPoint(w));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int selectedSegment = builder.getSelectedSegment();
|
||||||
if (OSMAND_ROUTER_V2.equals(file.author)) {
|
if (OSMAND_ROUTER_V2.equals(file.author)) {
|
||||||
route = parseOsmAndGPXRoute(points, file);
|
route = parseOsmAndGPXRoute(points, file, selectedSegment);
|
||||||
routePoints = file.getRoutePoints();
|
routePoints = file.getRoutePoints();
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
Collections.reverse(points);
|
Collections.reverse(points);
|
||||||
|
@ -287,7 +296,7 @@ public class RouteProvider {
|
||||||
}
|
}
|
||||||
addMissingTurns = route != null && route.isEmpty();
|
addMissingTurns = route != null && route.isEmpty();
|
||||||
} else if (file.isCloudmadeRouteFile() || OSMAND_ROUTER.equals(file.author)) {
|
} else if (file.isCloudmadeRouteFile() || OSMAND_ROUTER.equals(file.author)) {
|
||||||
directions = parseOsmAndGPXRoute(points, file, OSMAND_ROUTER.equals(file.author), builder.leftSide, 10);
|
directions = parseOsmAndGPXRoute(points, file, OSMAND_ROUTER.equals(file.author), builder.leftSide, 10, selectedSegment);
|
||||||
if (OSMAND_ROUTER.equals(file.author) && file.hasRtePt()) {
|
if (OSMAND_ROUTER.equals(file.author) && file.hasRtePt()) {
|
||||||
// For files generated by OSMAND_ROUTER use directions contained unaltered
|
// For files generated by OSMAND_ROUTER use directions contained unaltered
|
||||||
addMissingTurns = false;
|
addMissingTurns = false;
|
||||||
|
@ -301,12 +310,16 @@ public class RouteProvider {
|
||||||
} else {
|
} else {
|
||||||
// first of all check tracks
|
// first of all check tracks
|
||||||
if (!useIntermediatePointsRTE) {
|
if (!useIntermediatePointsRTE) {
|
||||||
for (Track tr : file.tracks) {
|
List<TrkSegment> segments = file.getNonEmptyTrkSegments(false);
|
||||||
if (!tr.generalTrack) {
|
if (selectedSegment != -1 && segments.size() > selectedSegment) {
|
||||||
for (TrkSegment tkSeg : tr.segments) {
|
TrkSegment segment = segments.get(selectedSegment);
|
||||||
for (WptPt pt : tkSeg.points) {
|
for (WptPt p : segment.points) {
|
||||||
points.add(createLocation(pt));
|
points.add(createLocation(p));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
for (TrkSegment tkSeg : segments) {
|
||||||
|
for (WptPt p : tkSeg.points) {
|
||||||
|
points.add(createLocation(p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -998,28 +1011,42 @@ public class RouteProvider {
|
||||||
return new RouteCalculationResult("Empty result");
|
return new RouteCalculationResult("Empty result");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<RouteSegmentResult> parseOsmAndGPXRoute(List<Location> points, GPXFile gpxFile) {
|
private static List<RouteSegmentResult> parseOsmAndGPXRoute(List<Location> points, GPXFile gpxFile, int selectedSegment) {
|
||||||
for (Track tr : gpxFile.tracks) {
|
List<TrkSegment> segments = gpxFile.getNonEmptyTrkSegments(false);
|
||||||
for (TrkSegment ts : tr.segments) {
|
if (selectedSegment != -1 && segments.size() > selectedSegment) {
|
||||||
for (WptPt p : ts.points) {
|
TrkSegment segment = segments.get(selectedSegment);
|
||||||
|
for (WptPt p : segment.points) {
|
||||||
points.add(createLocation(p));
|
points.add(createLocation(p));
|
||||||
}
|
}
|
||||||
|
RouteImporter routeImporter = new RouteImporter(segment);
|
||||||
|
return routeImporter.importRoute();
|
||||||
|
} else {
|
||||||
|
for (TrkSegment ts : segments) {
|
||||||
|
for (WptPt p : ts.points) {
|
||||||
|
points.add(createLocation(p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RouteImporter routeImporter = new RouteImporter(gpxFile);
|
RouteImporter routeImporter = new RouteImporter(gpxFile);
|
||||||
return routeImporter.importRoute();
|
return routeImporter.importRoute();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static List<RouteDirectionInfo> parseOsmAndGPXRoute(List<Location> points, GPXFile gpxFile, boolean osmandRouter,
|
private static List<RouteDirectionInfo> parseOsmAndGPXRoute(List<Location> points, GPXFile gpxFile, boolean osmandRouter,
|
||||||
boolean leftSide, float defSpeed) {
|
boolean leftSide, float defSpeed, int selectedSegment) {
|
||||||
List<RouteDirectionInfo> directions = null;
|
List<RouteDirectionInfo> directions = null;
|
||||||
if (!osmandRouter) {
|
if (!osmandRouter) {
|
||||||
for (WptPt pt : gpxFile.getPoints()) {
|
for (WptPt pt : gpxFile.getPoints()) {
|
||||||
points.add(createLocation(pt));
|
points.add(createLocation(pt));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (Track tr : gpxFile.tracks) {
|
List<TrkSegment> segments = gpxFile.getNonEmptyTrkSegments(false);
|
||||||
for (TrkSegment ts : tr.segments) {
|
if (selectedSegment != -1 && segments.size() > selectedSegment) {
|
||||||
|
TrkSegment segment = segments.get(selectedSegment);
|
||||||
|
for (WptPt p : segment.points) {
|
||||||
|
points.add(createLocation(p));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (TrkSegment ts : segments) {
|
||||||
for (WptPt p : ts.points) {
|
for (WptPt p : ts.points) {
|
||||||
points.add(createLocation(p));
|
points.add(createLocation(p));
|
||||||
}
|
}
|
||||||
|
@ -1307,7 +1334,7 @@ public class RouteProvider {
|
||||||
|
|
||||||
GPXFile gpxFile = GPXUtilities.loadGPXFile(gpxStream);
|
GPXFile gpxFile = GPXUtilities.loadGPXFile(gpxStream);
|
||||||
|
|
||||||
dir = parseOsmAndGPXRoute(res, gpxFile, true, params.leftSide, params.mode.getDefaultSpeed());
|
dir = parseOsmAndGPXRoute(res, gpxFile, true, params.leftSide, params.mode.getDefaultSpeed(), -1);
|
||||||
|
|
||||||
if (dir != null) {
|
if (dir != null) {
|
||||||
addMissingTurns = false;
|
addMissingTurns = false;
|
||||||
|
|
|
@ -45,10 +45,8 @@ import net.osmand.plus.helpers.enums.DrivingRegion;
|
||||||
import net.osmand.plus.helpers.enums.MetricsConstants;
|
import net.osmand.plus.helpers.enums.MetricsConstants;
|
||||||
import net.osmand.plus.helpers.enums.SpeedConstants;
|
import net.osmand.plus.helpers.enums.SpeedConstants;
|
||||||
import net.osmand.plus.helpers.enums.TracksSortByMode;
|
import net.osmand.plus.helpers.enums.TracksSortByMode;
|
||||||
import net.osmand.plus.mapillary.MapillaryPlugin;
|
|
||||||
import net.osmand.plus.mapmarkers.CoordinateInputFormats.Format;
|
import net.osmand.plus.mapmarkers.CoordinateInputFormats.Format;
|
||||||
import net.osmand.plus.mapmarkers.MapMarkersMode;
|
import net.osmand.plus.mapmarkers.MapMarkersMode;
|
||||||
import net.osmand.plus.openplacereviews.OpenPlaceReviewsPlugin;
|
|
||||||
import net.osmand.plus.profiles.LocationIcon;
|
import net.osmand.plus.profiles.LocationIcon;
|
||||||
import net.osmand.plus.profiles.NavigationIcon;
|
import net.osmand.plus.profiles.NavigationIcon;
|
||||||
import net.osmand.plus.profiles.ProfileIconColors;
|
import net.osmand.plus.profiles.ProfileIconColors;
|
||||||
|
@ -1389,6 +1387,7 @@ public class OsmandSettings {
|
||||||
public final OsmandPreference<Boolean> GPX_ROUTE_CALC_OSMAND_PARTS = new BooleanPreference(this, "gpx_routing_calculate_osmand_route", true).makeGlobal().makeShared().cache();
|
public final OsmandPreference<Boolean> GPX_ROUTE_CALC_OSMAND_PARTS = new BooleanPreference(this, "gpx_routing_calculate_osmand_route", true).makeGlobal().makeShared().cache();
|
||||||
public final OsmandPreference<Boolean> GPX_CALCULATE_RTEPT = new BooleanPreference(this, "gpx_routing_calculate_rtept", true).makeGlobal().makeShared().cache();
|
public final OsmandPreference<Boolean> GPX_CALCULATE_RTEPT = new BooleanPreference(this, "gpx_routing_calculate_rtept", true).makeGlobal().makeShared().cache();
|
||||||
public final OsmandPreference<Boolean> GPX_ROUTE_CALC = new BooleanPreference(this, "calc_gpx_route", false).makeGlobal().makeShared().cache();
|
public final OsmandPreference<Boolean> GPX_ROUTE_CALC = new BooleanPreference(this, "calc_gpx_route", false).makeGlobal().makeShared().cache();
|
||||||
|
public final OsmandPreference<Integer> GPX_ROUTE_SEGMENT = new IntPreference(this, "gpx_route_segment", -1).makeGlobal().makeShared().cache();
|
||||||
public final OsmandPreference<Boolean> SHOW_START_FINISH_ICONS = new BooleanPreference(this, "show_start_finish_icons", true).makeGlobal().makeShared().cache();
|
public final OsmandPreference<Boolean> SHOW_START_FINISH_ICONS = new BooleanPreference(this, "show_start_finish_icons", true).makeGlobal().makeShared().cache();
|
||||||
|
|
||||||
public final OsmandPreference<Boolean> AVOID_TOLL_ROADS = new BooleanPreference(this, "avoid_toll_roads", false).makeProfile().cache();
|
public final OsmandPreference<Boolean> AVOID_TOLL_ROADS = new BooleanPreference(this, "avoid_toll_roads", false).makeProfile().cache();
|
||||||
|
@ -2594,7 +2593,7 @@ public class OsmandSettings {
|
||||||
|
|
||||||
public static final String VOICE_PROVIDER_NOT_USE = "VOICE_PROVIDER_NOT_USE";
|
public static final String VOICE_PROVIDER_NOT_USE = "VOICE_PROVIDER_NOT_USE";
|
||||||
|
|
||||||
public static final String[] TTS_AVAILABLE_VOICES = new String[]{
|
public static final String[] TTS_AVAILABLE_VOICES = new String[] {
|
||||||
"de", "en", "es", "fr", "it", "ja", "nl", "pl", "pt", "ru", "zh"
|
"de", "en", "es", "fr", "it", "ja", "nl", "pl", "pt", "ru", "zh"
|
||||||
};
|
};
|
||||||
// this value string is synchronized with settings_pref.xml preference name
|
// this value string is synchronized with settings_pref.xml preference name
|
||||||
|
|
|
@ -102,6 +102,8 @@ public class ImportCompleteFragment extends BaseOsmAndFragment {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (needRestart) {
|
if (needRestart) {
|
||||||
|
description.append("\n\n");
|
||||||
|
description.append(app.getString(R.string.app_restart_required));
|
||||||
setupRestartButton(root);
|
setupRestartButton(root);
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
package net.osmand.plus.track;
|
package net.osmand.plus.track;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.appcompat.widget.AppCompatImageView;
|
|
||||||
|
|
||||||
import com.squareup.picasso.Callback;
|
import com.squareup.picasso.Callback;
|
||||||
import com.squareup.picasso.Picasso;
|
import com.squareup.picasso.Picasso;
|
||||||
import com.squareup.picasso.RequestCreator;
|
import com.squareup.picasso.RequestCreator;
|
||||||
|
|
||||||
|
import net.osmand.AndroidUtils;
|
||||||
import net.osmand.GPXUtilities;
|
import net.osmand.GPXUtilities;
|
||||||
import net.osmand.GPXUtilities.GPXFile;
|
import net.osmand.GPXUtilities.GPXFile;
|
||||||
import net.osmand.PicassoUtils;
|
import net.osmand.PicassoUtils;
|
||||||
|
@ -19,10 +19,13 @@ import net.osmand.plus.activities.MapActivity;
|
||||||
import net.osmand.plus.helpers.AndroidUiHelper;
|
import net.osmand.plus.helpers.AndroidUiHelper;
|
||||||
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
|
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
|
||||||
import net.osmand.plus.widgets.TextViewEx;
|
import net.osmand.plus.widgets.TextViewEx;
|
||||||
|
import net.osmand.plus.wikipedia.WikiArticleHelper;
|
||||||
import net.osmand.util.Algorithms;
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.appcompat.widget.AppCompatImageView;
|
||||||
|
|
||||||
import static net.osmand.plus.myplaces.TrackActivityFragmentAdapter.getMetadataImageLink;
|
import static net.osmand.plus.myplaces.TrackActivityFragmentAdapter.getMetadataImageLink;
|
||||||
import static net.osmand.plus.wikipedia.WikiArticleHelper.getFirstParagraph;
|
|
||||||
|
|
||||||
public class DescriptionCard extends BaseCard {
|
public class DescriptionCard extends BaseCard {
|
||||||
|
|
||||||
|
@ -59,8 +62,9 @@ public class DescriptionCard extends BaseCard {
|
||||||
|
|
||||||
private void showAddBtn() {
|
private void showAddBtn() {
|
||||||
LinearLayout descriptionContainer = view.findViewById(R.id.description_container);
|
LinearLayout descriptionContainer = view.findViewById(R.id.description_container);
|
||||||
FrameLayout addBtn = view.findViewById(R.id.btn_add);
|
View addBtn = view.findViewById(R.id.btn_add);
|
||||||
|
|
||||||
|
setupButton(addBtn);
|
||||||
addBtn.setOnClickListener(new View.OnClickListener() {
|
addBtn.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
|
@ -81,7 +85,8 @@ public class DescriptionCard extends BaseCard {
|
||||||
TextViewEx tvDescription = view.findViewById(R.id.description);
|
TextViewEx tvDescription = view.findViewById(R.id.description);
|
||||||
tvDescription.setText(getFirstParagraph(descriptionHtml));
|
tvDescription.setText(getFirstParagraph(descriptionHtml));
|
||||||
|
|
||||||
TextViewEx readBtn = view.findViewById(R.id.btn_read_full);
|
View readBtn = view.findViewById(R.id.btn_read_full);
|
||||||
|
setupButton(readBtn);
|
||||||
readBtn.setOnClickListener(new View.OnClickListener() {
|
readBtn.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
|
@ -89,7 +94,8 @@ public class DescriptionCard extends BaseCard {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
TextViewEx editBtn = view.findViewById(R.id.btn_edit);
|
View editBtn = view.findViewById(R.id.btn_edit);
|
||||||
|
setupButton(editBtn);
|
||||||
editBtn.setOnClickListener(new View.OnClickListener() {
|
editBtn.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
|
@ -98,6 +104,25 @@ public class DescriptionCard extends BaseCard {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getFirstParagraph(String descriptionHtml) {
|
||||||
|
if (descriptionHtml != null) {
|
||||||
|
String firstParagraph = WikiArticleHelper.getPartialContent(descriptionHtml);
|
||||||
|
if (!Algorithms.isEmpty(firstParagraph)) {
|
||||||
|
return firstParagraph;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return descriptionHtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupButton(View button) {
|
||||||
|
Context ctx = button.getContext();
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
AndroidUtils.setBackground(ctx, button, nightMode, R.drawable.ripple_light, R.drawable.ripple_dark);
|
||||||
|
} else {
|
||||||
|
AndroidUtils.setBackground(ctx, button, nightMode, R.drawable.btn_unstroked_light, R.drawable.btn_unstroked_dark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void setupImage(final String imageUrl) {
|
private void setupImage(final String imageUrl) {
|
||||||
if (imageUrl == null) {
|
if (imageUrl == null) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -11,6 +11,7 @@ import androidx.annotation.ColorInt;
|
||||||
import androidx.annotation.ColorRes;
|
import androidx.annotation.ColorRes;
|
||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.widget.AppCompatImageView;
|
import androidx.appcompat.widget.AppCompatImageView;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
@ -18,6 +19,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||||
import net.osmand.AndroidUtils;
|
import net.osmand.AndroidUtils;
|
||||||
import net.osmand.GPXUtilities.GPXFile;
|
import net.osmand.GPXUtilities.GPXFile;
|
||||||
import net.osmand.GPXUtilities.GPXTrackAnalysis;
|
import net.osmand.GPXUtilities.GPXTrackAnalysis;
|
||||||
|
import net.osmand.PlatformUtil;
|
||||||
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
|
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
|
||||||
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
|
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
|
||||||
import net.osmand.plus.OsmAndFormatter;
|
import net.osmand.plus.OsmAndFormatter;
|
||||||
|
@ -30,17 +32,24 @@ import net.osmand.plus.myplaces.SegmentActionsListener;
|
||||||
import net.osmand.plus.widgets.TextViewEx;
|
import net.osmand.plus.widgets.TextViewEx;
|
||||||
import net.osmand.util.Algorithms;
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class GpxBlockStatisticsBuilder {
|
public class GpxBlockStatisticsBuilder {
|
||||||
|
|
||||||
|
private static final Log log = PlatformUtil.getLog(GpxBlockStatisticsBuilder.class);
|
||||||
|
private static final int GENERAL_UPDATE_INTERVAL = 1000;
|
||||||
|
|
||||||
private final OsmandApplication app;
|
private final OsmandApplication app;
|
||||||
private RecyclerView blocksView;
|
private RecyclerView blocksView;
|
||||||
private final SelectedGpxFile selectedGpxFile;
|
private final SelectedGpxFile selectedGpxFile;
|
||||||
|
|
||||||
private BlockStatisticsAdapter adapter;
|
private BlockStatisticsAdapter adapter;
|
||||||
private final List<StatBlock> items = new ArrayList<>();
|
private final List<StatBlock> items = new ArrayList<>();
|
||||||
|
private boolean blocksClickable = true;
|
||||||
|
|
||||||
private final Handler handler = new Handler();
|
private final Handler handler = new Handler();
|
||||||
private Runnable updatingItems;
|
private Runnable updatingItems;
|
||||||
|
@ -51,28 +60,34 @@ public class GpxBlockStatisticsBuilder {
|
||||||
this.selectedGpxFile = selectedGpxFile;
|
this.selectedGpxFile = selectedGpxFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isUpdateRunning() {
|
||||||
|
return updateRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBlocksClickable(boolean blocksClickable) {
|
||||||
|
this.blocksClickable = blocksClickable;
|
||||||
|
}
|
||||||
|
|
||||||
public void setBlocksView(RecyclerView blocksView) {
|
public void setBlocksView(RecyclerView blocksView) {
|
||||||
this.blocksView = blocksView;
|
this.blocksView = blocksView;
|
||||||
}
|
}
|
||||||
|
|
||||||
private GpxDisplayItem getDisplayItem(GPXFile gpxFile) {
|
@Nullable
|
||||||
return GpxUiHelper.makeGpxDisplayItem(app, gpxFile);
|
public GpxDisplayItem getDisplayItem(GPXFile gpxFile) {
|
||||||
|
return gpxFile.tracks.size() > 0 ? GpxUiHelper.makeGpxDisplayItem(app, gpxFile) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private GPXFile getGPXFile() {
|
private GPXFile getGPXFile() {
|
||||||
return selectedGpxFile.getGpxFile();
|
return selectedGpxFile.getGpxFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initStatBlocks(SegmentActionsListener actionsListener, @ColorInt int activeColor, boolean nightMode) {
|
public void initStatBlocks(@Nullable SegmentActionsListener actionsListener, @ColorInt int activeColor, boolean nightMode) {
|
||||||
initItems();
|
initItems();
|
||||||
boolean isNotEmpty = !Algorithms.isEmpty(items);
|
|
||||||
AndroidUiHelper.updateVisibility(blocksView, isNotEmpty);
|
|
||||||
if (isNotEmpty) {
|
|
||||||
adapter = new BlockStatisticsAdapter(getDisplayItem(getGPXFile()), actionsListener, activeColor, nightMode);
|
adapter = new BlockStatisticsAdapter(getDisplayItem(getGPXFile()), actionsListener, activeColor, nightMode);
|
||||||
adapter.setItems(items);
|
adapter.setItems(items);
|
||||||
blocksView.setLayoutManager(new LinearLayoutManager(app, LinearLayoutManager.HORIZONTAL, false));
|
blocksView.setLayoutManager(new LinearLayoutManager(app, LinearLayoutManager.HORIZONTAL, false));
|
||||||
blocksView.setAdapter(adapter);
|
blocksView.setAdapter(adapter);
|
||||||
}
|
AndroidUiHelper.updateVisibility(blocksView, !Algorithms.isEmpty(items));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopUpdatingStatBlocks() {
|
public void stopUpdatingStatBlocks() {
|
||||||
|
@ -80,30 +95,29 @@ public class GpxBlockStatisticsBuilder {
|
||||||
updateRunning = false;
|
updateRunning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void runUpdatingStatBlocks() {
|
public void runUpdatingStatBlocksIfNeeded() {
|
||||||
|
if (!isUpdateRunning()) {
|
||||||
updatingItems = new Runnable() {
|
updatingItems = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (adapter != null) {
|
|
||||||
initItems();
|
initItems();
|
||||||
|
if (adapter != null) {
|
||||||
adapter.setItems(items);
|
adapter.setItems(items);
|
||||||
AndroidUiHelper.updateVisibility(blocksView, !Algorithms.isEmpty(items));
|
|
||||||
}
|
}
|
||||||
|
AndroidUiHelper.updateVisibility(blocksView, !Algorithms.isEmpty(items));
|
||||||
int interval = app.getSettings().SAVE_GLOBAL_TRACK_INTERVAL.get();
|
int interval = app.getSettings().SAVE_GLOBAL_TRACK_INTERVAL.get();
|
||||||
handler.postDelayed(this, Math.max(1000, interval));
|
updateRunning = handler.postDelayed(this, Math.max(GENERAL_UPDATE_INTERVAL, interval));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
updateRunning = handler.post(updatingItems);
|
updateRunning = handler.post(updatingItems);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void initItems() {
|
public void initItems() {
|
||||||
GPXFile gpxFile = getGPXFile();
|
GPXFile gpxFile = getGPXFile();
|
||||||
GpxDisplayItem gpxDisplayItem = null;
|
GpxDisplayItem gpxDisplayItem = getDisplayItem(gpxFile);
|
||||||
GPXTrackAnalysis analysis = null;
|
GPXTrackAnalysis analysis = null;
|
||||||
boolean withoutGaps = true;
|
boolean withoutGaps = true;
|
||||||
if (gpxFile.tracks.size() > 0) {
|
|
||||||
gpxDisplayItem = getDisplayItem(gpxFile);
|
|
||||||
}
|
|
||||||
if (gpxDisplayItem != null) {
|
if (gpxDisplayItem != null) {
|
||||||
analysis = gpxDisplayItem.analysis;
|
analysis = gpxDisplayItem.analysis;
|
||||||
withoutGaps = !selectedGpxFile.isJoinSegments() && gpxDisplayItem.isGeneralTrack();
|
withoutGaps = !selectedGpxFile.isJoinSegments() && gpxDisplayItem.isGeneralTrack();
|
||||||
|
@ -165,7 +179,7 @@ public class GpxBlockStatisticsBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StatBlock {
|
public static class StatBlock {
|
||||||
private final String title;
|
private final String title;
|
||||||
private final String value;
|
private final String value;
|
||||||
private final int imageResId;
|
private final int imageResId;
|
||||||
|
@ -201,6 +215,9 @@ public class GpxBlockStatisticsBuilder {
|
||||||
@ColorInt
|
@ColorInt
|
||||||
private final int activeColor;
|
private final int activeColor;
|
||||||
private final boolean nightMode;
|
private final boolean nightMode;
|
||||||
|
private final int minWidthPx;
|
||||||
|
private final int maxWidthPx;
|
||||||
|
private final int textSize;
|
||||||
|
|
||||||
public BlockStatisticsAdapter(GpxDisplayItem displayItem, SegmentActionsListener actionsListener,
|
public BlockStatisticsAdapter(GpxDisplayItem displayItem, SegmentActionsListener actionsListener,
|
||||||
@ColorInt int activeColor, boolean nightMode) {
|
@ColorInt int activeColor, boolean nightMode) {
|
||||||
|
@ -208,6 +225,9 @@ public class GpxBlockStatisticsBuilder {
|
||||||
this.actionsListener = actionsListener;
|
this.actionsListener = actionsListener;
|
||||||
this.activeColor = activeColor;
|
this.activeColor = activeColor;
|
||||||
this.nightMode = nightMode;
|
this.nightMode = nightMode;
|
||||||
|
minWidthPx = AndroidUtils.dpToPx(app, 60f);
|
||||||
|
maxWidthPx = AndroidUtils.dpToPx(app, 120f);
|
||||||
|
textSize = app.getResources().getDimensionPixelSize(R.dimen.default_desc_text_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -227,17 +247,15 @@ public class GpxBlockStatisticsBuilder {
|
||||||
public void onBindViewHolder(BlockStatisticsViewHolder holder, int position) {
|
public void onBindViewHolder(BlockStatisticsViewHolder holder, int position) {
|
||||||
final StatBlock item = items.get(position);
|
final StatBlock item = items.get(position);
|
||||||
holder.valueText.setText(item.value);
|
holder.valueText.setText(item.value);
|
||||||
holder.titleText.setText(item.title);
|
|
||||||
if (updateRunning) {
|
|
||||||
holder.titleText.setWidth(app.getResources().getDimensionPixelSize(R.dimen.map_route_buttons_width));
|
|
||||||
}
|
|
||||||
holder.valueText.setTextColor(activeColor);
|
holder.valueText.setTextColor(activeColor);
|
||||||
|
holder.titleText.setText(item.title);
|
||||||
holder.titleText.setTextColor(app.getResources().getColor(R.color.text_color_secondary_light));
|
holder.titleText.setTextColor(app.getResources().getColor(R.color.text_color_secondary_light));
|
||||||
|
holder.titleText.setWidth(calculateWidthWithin(item.title, item.value));
|
||||||
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
GPXTrackAnalysis analysis = displayItem != null ? displayItem.analysis : null;
|
GPXTrackAnalysis analysis = displayItem != null ? displayItem.analysis : null;
|
||||||
if (analysis != null) {
|
if (blocksClickable && analysis != null && actionsListener != null) {
|
||||||
ArrayList<GPXDataSetType> list = new ArrayList<>();
|
ArrayList<GPXDataSetType> list = new ArrayList<>();
|
||||||
if (analysis.hasElevationData || analysis.isSpeedSpecified() || analysis.hasSpeedData) {
|
if (analysis.hasElevationData || analysis.isSpeedSpecified() || analysis.hasSpeedData) {
|
||||||
if (item.firstType != null) {
|
if (item.firstType != null) {
|
||||||
|
@ -264,9 +282,14 @@ public class GpxBlockStatisticsBuilder {
|
||||||
this.items.addAll(items);
|
this.items.addAll(items);
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int calculateWidthWithin(String... texts) {
|
||||||
|
int textWidth = AndroidUtils.getTextMaxWidth(textSize, Arrays.asList(texts));
|
||||||
|
return Math.min(maxWidthPx, Math.max(minWidthPx, textWidth));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BlockStatisticsViewHolder extends RecyclerView.ViewHolder {
|
private static class BlockStatisticsViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
private final TextViewEx valueText;
|
private final TextViewEx valueText;
|
||||||
private final TextView titleText;
|
private final TextView titleText;
|
||||||
|
|
|
@ -1,14 +1,19 @@
|
||||||
package net.osmand.plus.track;
|
package net.osmand.plus.track;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.Dialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.Window;
|
||||||
|
|
||||||
|
import net.osmand.AndroidUtils;
|
||||||
import net.osmand.GPXUtilities.GPXFile;
|
import net.osmand.GPXUtilities.GPXFile;
|
||||||
import net.osmand.PlatformUtil;
|
import net.osmand.PlatformUtil;
|
||||||
import net.osmand.plus.OsmandApplication;
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
@ -26,6 +31,7 @@ import java.io.File;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
@ -63,7 +69,50 @@ public class GpxEditDescriptionDialogFragment extends BaseOsmAndDialogFragment {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
view.findViewById(R.id.btn_save).setOnClickListener(new View.OnClickListener() {
|
setupSaveButton(view);
|
||||||
|
|
||||||
|
Bundle args = getArguments();
|
||||||
|
if (args != null) {
|
||||||
|
htmlCode = args.getString(CONTENT_KEY);
|
||||||
|
if (htmlCode != null) {
|
||||||
|
editableHtml.append(htmlCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||||
|
Activity ctx = getActivity();
|
||||||
|
int themeId = isNightMode(true) ? R.style.OsmandDarkTheme_DarkActionbar : R.style.OsmandLightTheme_DarkActionbar_LightStatusBar;
|
||||||
|
Dialog dialog = new Dialog(ctx, themeId);
|
||||||
|
Window window = dialog.getWindow();
|
||||||
|
if (window != null) {
|
||||||
|
if (!getSettings().DO_NOT_USE_ANIMATIONS.get()) {
|
||||||
|
window.getAttributes().windowAnimations = R.style.Animations_Alpha;
|
||||||
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
int statusBarColor = isNightMode(true) ? R.color.activity_background_color_dark : R.color.activity_background_color_light;
|
||||||
|
window.setStatusBarColor(ContextCompat.getColor(ctx, statusBarColor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldClose() {
|
||||||
|
Editable editable = editableHtml.getText();
|
||||||
|
if (htmlCode == null || editable == null || editable.toString() == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return htmlCode.equals(editable.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupSaveButton(View view) {
|
||||||
|
View btnSave = view.findViewById(R.id.btn_save);
|
||||||
|
|
||||||
|
btnSave.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Editable editable = editableHtml.getText();
|
Editable editable = editableHtml.getText();
|
||||||
|
@ -73,25 +122,14 @@ public class GpxEditDescriptionDialogFragment extends BaseOsmAndDialogFragment {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Bundle args = getArguments();
|
Context ctx = btnSave.getContext();
|
||||||
if (args != null) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
htmlCode = args.getString(CONTENT_KEY);
|
AndroidUtils.setBackground(ctx, btnSave, isNightMode(true), R.drawable.ripple_light, R.drawable.ripple_dark);
|
||||||
if (htmlCode != null) {
|
} else {
|
||||||
editableHtml.setText(htmlCode);
|
AndroidUtils.setBackground(ctx, btnSave, isNightMode(true), R.drawable.btn_unstroked_light, R.drawable.btn_unstroked_dark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean shouldClose() {
|
|
||||||
Editable editable = editableHtml.getText();
|
|
||||||
if (htmlCode == null || editable == null || editable.toString() == null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return htmlCode.equals(editable.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showDismissDialog() {
|
private void showDismissDialog() {
|
||||||
Context themedContext = UiUtilities.getThemedContext(getMapActivity(), isNightMode(false));
|
Context themedContext = UiUtilities.getThemedContext(getMapActivity(), isNightMode(false));
|
||||||
AlertDialog.Builder dismissDialog = new AlertDialog.Builder(themedContext);
|
AlertDialog.Builder dismissDialog = new AlertDialog.Builder(themedContext);
|
||||||
|
|
|
@ -1,28 +1,20 @@
|
||||||
package net.osmand.plus.track;
|
package net.osmand.plus.track;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.Dialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.Window;
|
||||||
import android.webkit.WebSettings;
|
import android.webkit.WebSettings;
|
||||||
import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
import android.webkit.WebViewClient;
|
import android.webkit.WebViewClient;
|
||||||
|
import android.widget.TextView;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.appcompat.widget.AppCompatImageView;
|
|
||||||
import androidx.appcompat.widget.Toolbar;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
import androidx.fragment.app.FragmentManager;
|
|
||||||
|
|
||||||
import com.squareup.picasso.Callback;
|
import com.squareup.picasso.Callback;
|
||||||
import com.squareup.picasso.Picasso;
|
import com.squareup.picasso.Picasso;
|
||||||
|
@ -35,11 +27,17 @@ import net.osmand.plus.R;
|
||||||
import net.osmand.plus.UiUtilities;
|
import net.osmand.plus.UiUtilities;
|
||||||
import net.osmand.plus.base.BaseOsmAndDialogFragment;
|
import net.osmand.plus.base.BaseOsmAndDialogFragment;
|
||||||
import net.osmand.plus.helpers.AndroidUiHelper;
|
import net.osmand.plus.helpers.AndroidUiHelper;
|
||||||
import net.osmand.plus.widgets.TextViewEx;
|
|
||||||
import net.osmand.plus.widgets.WebViewEx;
|
import net.osmand.plus.widgets.WebViewEx;
|
||||||
import net.osmand.plus.wikivoyage.WikivoyageUtils;
|
import net.osmand.plus.wikivoyage.WikivoyageUtils;
|
||||||
import net.osmand.util.Algorithms;
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.widget.AppCompatImageView;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
public class GpxReadDescriptionDialogFragment extends BaseOsmAndDialogFragment {
|
public class GpxReadDescriptionDialogFragment extends BaseOsmAndDialogFragment {
|
||||||
|
|
||||||
public static final String TAG = GpxReadDescriptionDialogFragment.class.getSimpleName();
|
public static final String TAG = GpxReadDescriptionDialogFragment.class.getSimpleName();
|
||||||
|
@ -47,7 +45,6 @@ public class GpxReadDescriptionDialogFragment extends BaseOsmAndDialogFragment {
|
||||||
private static final String TITLE_KEY = "title_key";
|
private static final String TITLE_KEY = "title_key";
|
||||||
private static final String IMAGE_URL_KEY = "image_url_key";
|
private static final String IMAGE_URL_KEY = "image_url_key";
|
||||||
private static final String CONTENT_KEY = "content_key";
|
private static final String CONTENT_KEY = "content_key";
|
||||||
private static final int EDIT_ID = 1;
|
|
||||||
|
|
||||||
private WebViewEx webView;
|
private WebViewEx webView;
|
||||||
|
|
||||||
|
@ -93,34 +90,6 @@ public class GpxReadDescriptionDialogFragment extends BaseOsmAndDialogFragment {
|
||||||
loadWebviewData();
|
loadWebviewData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
|
||||||
if (item.getItemId() == EDIT_ID) {
|
|
||||||
FragmentActivity activity = getActivity();
|
|
||||||
if (activity != null) {
|
|
||||||
GpxEditDescriptionDialogFragment.showInstance(activity, contentHtml, this);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
|
|
||||||
menu.clear();
|
|
||||||
OsmandApplication app = getMyApplication();
|
|
||||||
int color = AndroidUtils.resolveAttribute(app, R.attr.pstsTextColor);
|
|
||||||
MenuItem menuItem = menu.add(0, EDIT_ID, 0, app.getString(R.string.shared_string_edit));
|
|
||||||
menuItem.setIcon(getIcon(R.drawable.ic_action_edit_dark, color));
|
|
||||||
menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onMenuItemClick(MenuItem item) {
|
|
||||||
return onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
|
@ -129,30 +98,49 @@ public class GpxReadDescriptionDialogFragment extends BaseOsmAndDialogFragment {
|
||||||
outState.putString(CONTENT_KEY, contentHtml);
|
outState.putString(CONTENT_KEY, contentHtml);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupToolbar(View view) {
|
@NonNull
|
||||||
Toolbar toolbar = view.findViewById(R.id.toolbar);
|
@Override
|
||||||
getMyActivity().setSupportActionBar(toolbar);
|
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||||
setHasOptionsMenu(true);
|
Activity ctx = getActivity();
|
||||||
toolbar.setClickable(true);
|
int themeId = isNightMode(true) ? R.style.OsmandDarkTheme_DarkActionbar : R.style.OsmandLightTheme_DarkActionbar_LightStatusBar;
|
||||||
|
Dialog dialog = new Dialog(ctx, themeId);
|
||||||
Context ctx = getMyActivity();
|
Window window = dialog.getWindow();
|
||||||
int iconColor = AndroidUtils.resolveAttribute(ctx, R.attr.pstsTextColor);
|
if (window != null) {
|
||||||
Drawable icBack = getMyApplication().getUIUtilities().getIcon(R.drawable.ic_arrow_back, iconColor);
|
if (!getSettings().DO_NOT_USE_ANIMATIONS.get()) {
|
||||||
toolbar.setNavigationIcon(icBack);
|
window.getAttributes().windowAnimations = R.style.Animations_Alpha;
|
||||||
toolbar.setNavigationContentDescription(R.string.access_shared_string_navigate_up);
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
if (!Algorithms.isEmpty(title)) {
|
int statusBarColor = isNightMode(true) ? R.color.status_bar_color_dark : R.color.status_bar_color_light;
|
||||||
toolbar.setTitle(title);
|
window.setStatusBarColor(ContextCompat.getColor(ctx, statusBarColor));
|
||||||
int titleColor = AndroidUtils.resolveAttribute(ctx, R.attr.pstsTextColor);
|
}
|
||||||
toolbar.setTitleTextColor(ContextCompat.getColor(ctx, titleColor));
|
}
|
||||||
|
return dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
|
private void setupToolbar(View view) {
|
||||||
|
View back = view.findViewById(R.id.toolbar_back);
|
||||||
|
back.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(final View v) {
|
public void onClick(View v) {
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
View edit = view.findViewById(R.id.toolbar_edit);
|
||||||
|
edit.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
FragmentActivity activity = getActivity();
|
||||||
|
if (activity != null) {
|
||||||
|
GpxEditDescriptionDialogFragment.showInstance(activity, contentHtml, GpxReadDescriptionDialogFragment.this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
TextView toolbarTitle = view.findViewById(R.id.toolbar_title);
|
||||||
|
if (!Algorithms.isEmpty(title)) {
|
||||||
|
toolbarTitle.setText(title);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupImage(View view) {
|
private void setupImage(View view) {
|
||||||
|
@ -216,15 +204,23 @@ public class GpxReadDescriptionDialogFragment extends BaseOsmAndDialogFragment {
|
||||||
private void loadWebviewData() {
|
private void loadWebviewData() {
|
||||||
String content = contentHtml;
|
String content = contentHtml;
|
||||||
if (content != null) {
|
if (content != null) {
|
||||||
content = isNightMode(false) ? getColoredContent(content) : content;
|
content = isNightMode(true) ? getColoredContent(content) : content;
|
||||||
String encoded = Base64.encodeToString(content.getBytes(), Base64.NO_PADDING);
|
String encoded = Base64.encodeToString(content.getBytes(), Base64.NO_PADDING);
|
||||||
webView.loadData(encoded, "text/html", "base64");
|
webView.loadData(encoded, "text/html", "base64");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupDependentViews(final View view) {
|
private void setupDependentViews(final View view) {
|
||||||
TextViewEx readBtn = view.findViewById(R.id.btn_edit);
|
View editBtn = view.findViewById(R.id.btn_edit);
|
||||||
readBtn.setOnClickListener(new View.OnClickListener() {
|
|
||||||
|
Context ctx = editBtn.getContext();
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
AndroidUtils.setBackground(ctx, editBtn, isNightMode(true), R.drawable.ripple_light, R.drawable.ripple_dark);
|
||||||
|
} else {
|
||||||
|
AndroidUtils.setBackground(ctx, editBtn, isNightMode(true), R.drawable.btn_unstroked_light, R.drawable.btn_unstroked_dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
editBtn.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
FragmentActivity activity = getActivity();
|
FragmentActivity activity = getActivity();
|
||||||
|
@ -234,7 +230,7 @@ public class GpxReadDescriptionDialogFragment extends BaseOsmAndDialogFragment {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
AndroidUiHelper.setVisibility(View.VISIBLE,
|
AndroidUiHelper.setVisibility(View.VISIBLE,
|
||||||
readBtn, view.findViewById(R.id.divider), view.findViewById(R.id.bottom_empty_space));
|
editBtn, view.findViewById(R.id.divider), view.findViewById(R.id.bottom_empty_space));
|
||||||
int backgroundColor = isNightMode(false) ?
|
int backgroundColor = isNightMode(false) ?
|
||||||
R.color.activity_background_color_dark : R.color.activity_background_color_light;
|
R.color.activity_background_color_dark : R.color.activity_background_color_light;
|
||||||
view.findViewById(R.id.root).setBackgroundResource(backgroundColor);
|
view.findViewById(R.id.root).setBackgroundResource(backgroundColor);
|
||||||
|
|
|
@ -43,6 +43,10 @@ public class OverviewCard extends BaseCard {
|
||||||
private final SelectedGpxFile selectedGpxFile;
|
private final SelectedGpxFile selectedGpxFile;
|
||||||
private final GpxBlockStatisticsBuilder blockStatisticsBuilder;
|
private final GpxBlockStatisticsBuilder blockStatisticsBuilder;
|
||||||
|
|
||||||
|
public GpxBlockStatisticsBuilder getBlockStatisticsBuilder() {
|
||||||
|
return blockStatisticsBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
public OverviewCard(@NonNull MapActivity mapActivity, @NonNull SegmentActionsListener actionsListener, SelectedGpxFile selectedGpxFile) {
|
public OverviewCard(@NonNull MapActivity mapActivity, @NonNull SegmentActionsListener actionsListener, SelectedGpxFile selectedGpxFile) {
|
||||||
super(mapActivity);
|
super(mapActivity);
|
||||||
this.actionsListener = actionsListener;
|
this.actionsListener = actionsListener;
|
||||||
|
|
|
@ -44,6 +44,7 @@ import net.osmand.plus.dialogs.GpxAppearanceAdapter;
|
||||||
import net.osmand.plus.dialogs.GpxAppearanceAdapter.AppearanceListItem;
|
import net.osmand.plus.dialogs.GpxAppearanceAdapter.AppearanceListItem;
|
||||||
import net.osmand.plus.dialogs.GpxAppearanceAdapter.GpxAppearanceAdapterType;
|
import net.osmand.plus.dialogs.GpxAppearanceAdapter.GpxAppearanceAdapterType;
|
||||||
import net.osmand.plus.helpers.AndroidUiHelper;
|
import net.osmand.plus.helpers.AndroidUiHelper;
|
||||||
|
import net.osmand.plus.monitoring.TripRecordingActiveBottomSheet;
|
||||||
import net.osmand.plus.monitoring.TripRecordingBottomSheet;
|
import net.osmand.plus.monitoring.TripRecordingBottomSheet;
|
||||||
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
|
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
|
||||||
import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener;
|
import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener;
|
||||||
|
@ -383,6 +384,8 @@ public class TrackAppearanceFragment extends ContextMenuScrollFragment implement
|
||||||
Fragment target = getTargetFragment();
|
Fragment target = getTargetFragment();
|
||||||
if (target instanceof TripRecordingBottomSheet) {
|
if (target instanceof TripRecordingBottomSheet) {
|
||||||
((TripRecordingBottomSheet) target).show();
|
((TripRecordingBottomSheet) target).show();
|
||||||
|
} else if (target instanceof TripRecordingActiveBottomSheet) {
|
||||||
|
((TripRecordingActiveBottomSheet) target).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,7 @@ import net.osmand.plus.myplaces.TrackActivityFragmentAdapter;
|
||||||
import net.osmand.plus.osmedit.OsmEditingPlugin;
|
import net.osmand.plus.osmedit.OsmEditingPlugin;
|
||||||
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
|
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
|
||||||
import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener;
|
import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener;
|
||||||
|
import net.osmand.plus.routing.RouteProvider;
|
||||||
import net.osmand.plus.track.SaveGpxAsyncTask.SaveGpxListener;
|
import net.osmand.plus.track.SaveGpxAsyncTask.SaveGpxListener;
|
||||||
import net.osmand.plus.views.AddGpxPointBottomSheetHelper.NewGpxPoint;
|
import net.osmand.plus.views.AddGpxPointBottomSheetHelper.NewGpxPoint;
|
||||||
import net.osmand.plus.widgets.IconPopupMenu;
|
import net.osmand.plus.widgets.IconPopupMenu;
|
||||||
|
@ -114,7 +115,7 @@ import static net.osmand.plus.track.TrackPointsCard.OPEN_WAYPOINT_INDEX;
|
||||||
|
|
||||||
public class TrackMenuFragment extends ContextMenuScrollFragment implements CardListener,
|
public class TrackMenuFragment extends ContextMenuScrollFragment implements CardListener,
|
||||||
SegmentActionsListener, RenameCallback, OnTrackFileMoveListener, OnPointsDeleteListener,
|
SegmentActionsListener, RenameCallback, OnTrackFileMoveListener, OnPointsDeleteListener,
|
||||||
OsmAndLocationListener, OsmAndCompassListener {
|
OsmAndLocationListener, OsmAndCompassListener, TrackSelectSegmentBottomSheet.OnSegmentSelectedListener {
|
||||||
|
|
||||||
public static final String OPEN_TRACK_MENU = "open_track_menu";
|
public static final String OPEN_TRACK_MENU = "open_track_menu";
|
||||||
public static final String RETURN_SCREEN_NAME = "return_screen_name";
|
public static final String RETURN_SCREEN_NAME = "return_screen_name";
|
||||||
|
@ -160,6 +161,7 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
|
||||||
private int toolbarHeightPx;
|
private int toolbarHeightPx;
|
||||||
private boolean mapPositionAdjusted;
|
private boolean mapPositionAdjusted;
|
||||||
|
|
||||||
|
|
||||||
public enum TrackMenuType {
|
public enum TrackMenuType {
|
||||||
OVERVIEW(R.id.action_overview, R.string.shared_string_overview),
|
OVERVIEW(R.id.action_overview, R.string.shared_string_overview),
|
||||||
TRACK(R.id.action_track, R.string.shared_string_gpx_tracks),
|
TRACK(R.id.action_track, R.string.shared_string_gpx_tracks),
|
||||||
|
@ -175,6 +177,7 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
|
||||||
public final int titleId;
|
public final int titleId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMainLayoutId() {
|
public int getMainLayoutId() {
|
||||||
return R.layout.track_menu;
|
return R.layout.track_menu;
|
||||||
|
@ -231,7 +234,8 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
|
||||||
}
|
}
|
||||||
displayHelper.setGpx(selectedGpxFile.getGpxFile());
|
displayHelper.setGpx(selectedGpxFile.getGpxFile());
|
||||||
String fileName = Algorithms.getFileWithoutDirs(getGpx().path);
|
String fileName = Algorithms.getFileWithoutDirs(getGpx().path);
|
||||||
gpxTitle = GpxUiHelper.getGpxTitle(fileName);
|
gpxTitle = !isCurrentRecordingTrack() ? GpxUiHelper.getGpxTitle(fileName)
|
||||||
|
: app.getResources().getString(R.string.shared_string_currently_recording_track);
|
||||||
toolbarHeightPx = getResources().getDimensionPixelSize(R.dimen.dashboard_map_toolbar);
|
toolbarHeightPx = getResources().getDimensionPixelSize(R.dimen.dashboard_map_toolbar);
|
||||||
|
|
||||||
FragmentActivity activity = requireMyActivity();
|
FragmentActivity activity = requireMyActivity();
|
||||||
|
@ -330,8 +334,13 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
|
||||||
overviewCard.setListener(this);
|
overviewCard.setListener(this);
|
||||||
headerContainer.addView(overviewCard.build(getMapActivity()));
|
headerContainer.addView(overviewCard.build(getMapActivity()));
|
||||||
}
|
}
|
||||||
|
GpxBlockStatisticsBuilder blocksBuilder = overviewCard.getBlockStatisticsBuilder();
|
||||||
|
if (isCurrentRecordingTrack()) {
|
||||||
|
blocksBuilder.runUpdatingStatBlocksIfNeeded();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (overviewCard != null && overviewCard.getView() != null) {
|
if (overviewCard != null && overviewCard.getView() != null) {
|
||||||
|
overviewCard.getBlockStatisticsBuilder().stopUpdatingStatBlocks();
|
||||||
headerContainer.removeView(overviewCard.getView());
|
headerContainer.removeView(overviewCard.getView());
|
||||||
}
|
}
|
||||||
boolean isOptions = menuType == TrackMenuType.OPTIONS;
|
boolean isOptions = menuType == TrackMenuType.OPTIONS;
|
||||||
|
@ -544,6 +553,10 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
|
||||||
}
|
}
|
||||||
updateControlsVisibility(true);
|
updateControlsVisibility(true);
|
||||||
startLocationUpdate();
|
startLocationUpdate();
|
||||||
|
GpxBlockStatisticsBuilder blockStats = overviewCard.getBlockStatisticsBuilder();
|
||||||
|
if (menuType == TrackMenuType.OVERVIEW && isCurrentRecordingTrack()) {
|
||||||
|
blockStats.runUpdatingStatBlocksIfNeeded();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -555,6 +568,7 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
|
||||||
}
|
}
|
||||||
updateControlsVisibility(false);
|
updateControlsVisibility(false);
|
||||||
stopLocationUpdate();
|
stopLocationUpdate();
|
||||||
|
overviewCard.getBlockStatisticsBuilder().stopUpdatingStatBlocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -591,8 +605,8 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
|
||||||
MapActivity mapActivity = getMapActivity();
|
MapActivity mapActivity = getMapActivity();
|
||||||
View view = overviewCard.getView();
|
View view = overviewCard.getView();
|
||||||
if (mapActivity != null && view != null) {
|
if (mapActivity != null && view != null) {
|
||||||
TextView distanceText = (TextView) view.findViewById(R.id.distance);
|
TextView distanceText = view.findViewById(R.id.distance);
|
||||||
ImageView direction = (ImageView) view.findViewById(R.id.direction);
|
ImageView direction = view.findViewById(R.id.direction);
|
||||||
app.getUIUtilities().updateLocationView(updateLocationViewCache, direction, distanceText, latLon);
|
app.getUIUtilities().updateLocationView(updateLocationViewCache, direction, distanceText, latLon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -723,24 +737,13 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
|
||||||
TrackAppearanceFragment.showInstance(mapActivity, selectedGpxFile, this);
|
TrackAppearanceFragment.showInstance(mapActivity, selectedGpxFile, this);
|
||||||
} else if (buttonIndex == DIRECTIONS_BUTTON_INDEX) {
|
} else if (buttonIndex == DIRECTIONS_BUTTON_INDEX) {
|
||||||
MapActivityActions mapActions = mapActivity.getMapActions();
|
MapActivityActions mapActions = mapActivity.getMapActions();
|
||||||
if (app.getRoutingHelper().isFollowingMode()) {
|
if (gpxFile.getNonEmptySegmentsCount() > 1) {
|
||||||
mapActions.stopNavigationActionConfirm(null, new Runnable() {
|
TrackSelectSegmentBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), gpxFile, this);
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
MapActivity mapActivity = getMapActivity();
|
|
||||||
if (mapActivity != null) {
|
|
||||||
mapActivity.getMapActions().enterRoutePlanningModeGivenGpx(gpxFile, null,
|
|
||||||
null, null, true, true, MenuState.HEADER_ONLY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
mapActions.stopNavigationWithoutConfirm();
|
startNavigationForGPX(gpxFile, mapActions);
|
||||||
mapActions.enterRoutePlanningModeGivenGpx(gpxFile, null, null,
|
|
||||||
null, true, true, MenuState.HEADER_ONLY);
|
|
||||||
}
|
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (buttonIndex == JOIN_GAPS_BUTTON_INDEX) {
|
if (buttonIndex == JOIN_GAPS_BUTTON_INDEX) {
|
||||||
displayHelper.setJoinSegments(!displayHelper.isJoinSegments());
|
displayHelper.setJoinSegments(!displayHelper.isJoinSegments());
|
||||||
mapActivity.refreshMap();
|
mapActivity.refreshMap();
|
||||||
|
@ -830,6 +833,25 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startNavigationForGPX(final GPXFile gpxFile, MapActivityActions mapActions) {
|
||||||
|
if (app.getRoutingHelper().isFollowingMode()) {
|
||||||
|
mapActions.stopNavigationActionConfirm(null, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
MapActivity mapActivity = getMapActivity();
|
||||||
|
if (mapActivity != null) {
|
||||||
|
mapActivity.getMapActions().enterRoutePlanningModeGivenGpx(gpxFile, null,
|
||||||
|
null, null, true, true, MenuState.HEADER_ONLY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
mapActions.stopNavigationWithoutConfirm();
|
||||||
|
mapActions.enterRoutePlanningModeGivenGpx(gpxFile, null, null,
|
||||||
|
null, true, true, MenuState.HEADER_ONLY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void updateToolbar(int y, boolean animated) {
|
public void updateToolbar(int y, boolean animated) {
|
||||||
final MapActivity mapActivity = getMapActivity();
|
final MapActivity mapActivity = getMapActivity();
|
||||||
if (mapActivity != null) {
|
if (mapActivity != null) {
|
||||||
|
@ -1066,6 +1088,21 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSegmentSelect(GPXFile gpxFile, int selectedSegment) {
|
||||||
|
MapActivity mapActivity = getMapActivity();
|
||||||
|
if (mapActivity != null) {
|
||||||
|
startNavigationForGPX(gpxFile, mapActivity.getMapActions());
|
||||||
|
app.getSettings().GPX_ROUTE_SEGMENT.set(selectedSegment);
|
||||||
|
RouteProvider.GPXRouteParamsBuilder paramsBuilder = app.getRoutingHelper().getCurrentGPXRoute();
|
||||||
|
if (paramsBuilder != null) {
|
||||||
|
paramsBuilder.setSelectedSegment(selectedSegment);
|
||||||
|
app.getRoutingHelper().onSettingsChanged(true);
|
||||||
|
}
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void editSegment(TrkSegment segment) {
|
private void editSegment(TrkSegment segment) {
|
||||||
GPXFile gpxFile = getGpx();
|
GPXFile gpxFile = getGpx();
|
||||||
openPlanRoute(new GpxData(gpxFile));
|
openPlanRoute(new GpxData(gpxFile));
|
||||||
|
@ -1120,6 +1157,10 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
|
||||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isCurrentRecordingTrack() {
|
||||||
|
return app.getSavingTrackHelper().getCurrentTrack() == selectedGpxFile;
|
||||||
|
}
|
||||||
|
|
||||||
private void hide() {
|
private void hide() {
|
||||||
try {
|
try {
|
||||||
MapActivity mapActivity = getMapActivity();
|
MapActivity mapActivity = getMapActivity();
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
package net.osmand.plus.track;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Typeface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.Spannable;
|
||||||
|
import android.text.SpannableString;
|
||||||
|
import android.text.style.ForegroundColorSpan;
|
||||||
|
import android.util.TypedValue;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import net.osmand.AndroidUtils;
|
||||||
|
import net.osmand.GPXUtilities;
|
||||||
|
import net.osmand.GPXUtilities.GPXFile;
|
||||||
|
import net.osmand.GPXUtilities.TrkSegment;
|
||||||
|
import net.osmand.plus.OsmAndFormatter;
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.plus.UiUtilities;
|
||||||
|
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
|
||||||
|
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
|
||||||
|
import net.osmand.plus.helpers.FontCache;
|
||||||
|
import net.osmand.plus.helpers.TrackSelectSegmentAdapter;
|
||||||
|
import net.osmand.plus.helpers.TrackSelectSegmentAdapter.OnItemClickListener;
|
||||||
|
import net.osmand.plus.widgets.style.CustomTypefaceSpan;
|
||||||
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TrackSelectSegmentBottomSheet extends MenuBottomSheetDialogFragment {
|
||||||
|
|
||||||
|
public static final String TAG = TrackSelectSegmentBottomSheet.class.getSimpleName();
|
||||||
|
|
||||||
|
private OsmandApplication app;
|
||||||
|
private GPXFile gpxFile;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createMenuItems(Bundle savedInstanceState) {
|
||||||
|
app = requiredMyApplication();
|
||||||
|
Context context = requireContext();
|
||||||
|
|
||||||
|
LayoutInflater inflater = UiUtilities.getInflater(context, nightMode);
|
||||||
|
View itemView = inflater.inflate(R.layout.bottom_sheet_select_segment, null, false);
|
||||||
|
|
||||||
|
String titleGpxTrack = Algorithms.getFileWithoutDirs(gpxFile.path);
|
||||||
|
Typeface typeface = FontCache.getRobotoMedium(app);
|
||||||
|
String selectSegmentDescription = getString(R.string.select_segments_description, titleGpxTrack);
|
||||||
|
SpannableString gpxTrackName = new SpannableString(selectSegmentDescription);
|
||||||
|
int startIndex = selectSegmentDescription.indexOf(titleGpxTrack);
|
||||||
|
int descriptionColor = getResolvedColor(nightMode ? R.color.text_color_secondary_dark : R.color.text_color_secondary_light);
|
||||||
|
int endIndex = startIndex + titleGpxTrack.length();
|
||||||
|
gpxTrackName.setSpan(new CustomTypefaceSpan(typeface), startIndex, endIndex, 0);
|
||||||
|
gpxTrackName.setSpan(new ForegroundColorSpan(descriptionColor), startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
|
items.add(new BaseBottomSheetItem.Builder()
|
||||||
|
.setCustomView(itemView)
|
||||||
|
.create());
|
||||||
|
|
||||||
|
LinearLayout gpxTrackContainer = itemView.findViewById(R.id.gpx_track_container);
|
||||||
|
GPXUtilities.GPXTrackAnalysis analysis = gpxFile.getAnalysis(0);
|
||||||
|
|
||||||
|
ImageView icon = gpxTrackContainer.findViewById(R.id.icon);
|
||||||
|
int sidePadding = AndroidUtils.dpToPx(context, 16f);
|
||||||
|
int bottomTopPadding = AndroidUtils.dpToPx(context, 2f);
|
||||||
|
|
||||||
|
LinearLayout readContainer = gpxTrackContainer.findViewById(R.id.read_section);
|
||||||
|
readContainer.setPadding(0, bottomTopPadding, 0, bottomTopPadding);
|
||||||
|
TextView name = gpxTrackContainer.findViewById(R.id.name);
|
||||||
|
TextView description = itemView.findViewById(R.id.description);
|
||||||
|
TextView distance = gpxTrackContainer.findViewById(R.id.distance);
|
||||||
|
TextView pointsCount = gpxTrackContainer.findViewById(R.id.points_count);
|
||||||
|
TextView time = gpxTrackContainer.findViewById(R.id.time);
|
||||||
|
LinearLayout container = gpxTrackContainer.findViewById(R.id.container);
|
||||||
|
LinearLayout containerNameAndReadSection = gpxTrackContainer.findViewById(R.id.name_and_read_section_container);
|
||||||
|
container.setPadding(sidePadding, 0, 0, 0);
|
||||||
|
containerNameAndReadSection.setPadding(sidePadding, 0, 0, 0);
|
||||||
|
icon.setImageDrawable(app.getUIUtilities().getThemedIcon(R.drawable.ic_action_polygom_dark));
|
||||||
|
name.setText(titleGpxTrack);
|
||||||
|
description.setText(gpxTrackName);
|
||||||
|
distance.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
|
||||||
|
distance.setText(OsmAndFormatter.getFormattedDistance(analysis.totalDistance, app));
|
||||||
|
pointsCount.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
|
||||||
|
pointsCount.setText(String.valueOf(analysis.wptPoints));
|
||||||
|
time.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
|
||||||
|
time.setText(analysis.isTimeSpecified() ? Algorithms.formatDuration((int) (analysis.timeSpan / 1000), app.accessibilityEnabled()) : "");
|
||||||
|
|
||||||
|
RecyclerView recyclerView = itemView.findViewById(R.id.gpx_segment_list);
|
||||||
|
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||||
|
recyclerView.setNestedScrollingEnabled(false);
|
||||||
|
|
||||||
|
List<TrkSegment> segments = gpxFile.getNonEmptyTrkSegments(false);
|
||||||
|
TrackSelectSegmentAdapter adapterSegments = new TrackSelectSegmentAdapter(context, segments);
|
||||||
|
adapterSegments.setAdapterListener(new OnItemClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemClick(int position) {
|
||||||
|
Fragment fragment = getTargetFragment();
|
||||||
|
if (fragment instanceof OnSegmentSelectedListener) {
|
||||||
|
((OnSegmentSelectedListener) fragment).onSegmentSelect(gpxFile, position);
|
||||||
|
}
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
recyclerView.setAdapter(adapterSegments);
|
||||||
|
|
||||||
|
gpxTrackContainer.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Fragment fragment = getTargetFragment();
|
||||||
|
if (fragment instanceof OnSegmentSelectedListener) {
|
||||||
|
((OnSegmentSelectedListener) fragment).onSegmentSelect(gpxFile, -1);
|
||||||
|
}
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnSegmentSelectedListener {
|
||||||
|
void onSegmentSelect(GPXFile gpxFile, int selectedSegment);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showInstance(@NonNull FragmentManager fragmentManager, @NonNull GPXFile gpxFile, @Nullable Fragment target) {
|
||||||
|
if (!fragmentManager.isStateSaved()) {
|
||||||
|
TrackSelectSegmentBottomSheet fragment = new TrackSelectSegmentBottomSheet();
|
||||||
|
fragment.setRetainInstance(true);
|
||||||
|
fragment.setTargetFragment(target, 0);
|
||||||
|
fragment.gpxFile = gpxFile;
|
||||||
|
fragment.show(fragmentManager, TAG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue