Merge branch 'master' into transliterate

# Conflicts:
#	OsmAnd-java/src/main/java/net/osmand/data/MapObject.java
This commit is contained in:
Vitaliy 2021-04-20 11:30:22 +03:00
commit 109d9aa1bb
70 changed files with 2393 additions and 1358 deletions

View file

@ -181,8 +181,9 @@ public abstract class MapObject implements Comparable<MapObject> {
public String getName(String lang, boolean transliterate) { public String getName(String lang, boolean transliterate) {
if (lang != null && lang.length() > 0) { if (lang != null && lang.length() > 0) {
if (lang.equals("en")) { if (lang.equals("en")) {
// for some objects like wikipedia, english name is stored 'name' tag
String enName = getEnName(transliterate); String enName = getEnName(transliterate);
return !Algorithms.isEmpty(enName) ? enName : getEnName(true); return !Algorithms.isEmpty(enName) ? enName : getName();
} else { } else {
// get name // get name
if (names != null) { if (names != null) {

View file

@ -5,8 +5,11 @@ import net.osmand.data.QuadRect;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set;
public class WorldRegion implements Serializable { public class WorldRegion implements Serializable {
@ -212,4 +215,22 @@ public class WorldRegion implements Serializable {
} }
return false; return false;
} }
public static List<WorldRegion> removeDuplicates(List<WorldRegion> regions) {
List<WorldRegion> copy = new ArrayList<>(regions);
Set<WorldRegion> duplicates = new HashSet<>();
for (int i = 0; i < copy.size() - 1; i++) {
WorldRegion r1 = copy.get(i);
for (int j = i + 1; j < copy.size(); j++) {
WorldRegion r2 = copy.get(j);
if (r1.containsRegion(r2)) {
duplicates.add(r2);
} else if (r2.containsRegion(r1)) {
duplicates.add(r1);
}
}
}
copy.removeAll(duplicates);
return copy;
}
} }

View file

@ -55,7 +55,9 @@ public class SearchResult {
public double getSumPhraseMatchWeight() { public double getSumPhraseMatchWeight() {
// if result is a complete match in the search we prioritize it higher // if result is a complete match in the search we prioritize it higher
boolean match = requiredSearchPhrase.countWords(localeName) <= getSelfWordCount(); int localWordsMatched = alternateName != null ?
requiredSearchPhrase.countWords(alternateName) : requiredSearchPhrase.countWords(localeName) ;
boolean match = localWordsMatched <= getSelfWordCount();
double res = ObjectType.getTypeWeight(match ? objectType : null); double res = ObjectType.getTypeWeight(match ? objectType : null);
if (parentSearchResult != null) { if (parentSearchResult != null) {
res = res + parentSearchResult.getSumPhraseMatchWeight() / MAX_TYPE_WEIGHT; res = res + parentSearchResult.getSumPhraseMatchWeight() / MAX_TYPE_WEIGHT;

View file

@ -191,10 +191,10 @@ public class SearchUICoreTest {
if (!Algorithms.stringsEqual(expected, present)) { if (!Algorithms.stringsEqual(expected, present)) {
System.out.println(String.format("Phrase: %s", phrase)); System.out.println(String.format("Phrase: %s", phrase));
System.out.println(String.format("Mismatch for '%s' != '%s'. Result: ", expected, present)); System.out.println(String.format("Mismatch for '%s' != '%s'. Result: ", expected, present));
}
for (SearchResult r : searchResults) { for (SearchResult r : searchResults) {
System.out.println(String.format("\t\"%s\",", formatResult(false, r, phrase))); System.out.println(String.format("\t\"%s\",", formatResult(false, r, phrase)));
} }
}
Assert.assertEquals(expected, present); Assert.assertEquals(expected, present);
} }
} }

View file

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

View file

@ -16,7 +16,16 @@
android:focusable="true" android:focusable="true"
android:orientation="vertical" android:orientation="vertical"
android:clickable="true" android:clickable="true"
tools:background="@drawable/bg_bottom_menu_dark"> tools:ignore="UselessParent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@drawable/bg_contextmenu_shadow_top_light" />
<ProgressBar <ProgressBar
android:id="@+id/snap_to_road_progress_bar" android:id="@+id/snap_to_road_progress_bar"
@ -24,12 +33,17 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minHeight="0dp" android:minHeight="0dp"
android:visibility="gone" android:background="?attr/list_background_color"
android:visibility="invisible"
tools:visibility="visible" /> tools:visibility="visible" />
</FrameLayout>
<LinearLayout <LinearLayout
android:id="@+id/main_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:background="?attr/list_background_color">
<RelativeLayout <RelativeLayout
android:id="@+id/up_down_row" android:id="@+id/up_down_row"
@ -53,6 +67,19 @@
android:background="@null" android:background="@null"
tools:src="@drawable/ic_action_ruler"/> tools:src="@drawable/ic_action_ruler"/>
<include
layout="@layout/custom_icon_radio_buttons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/content_padding_half"
android:layout_marginLeft="@dimen/bottom_sheet_content_margin"
android:layout_marginRight="@dimen/content_padding_half"
android:layout_marginStart="@dimen/bottom_sheet_content_margin"
android:background="@null" />
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/up_down_button" android:id="@+id/up_down_button"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -65,6 +92,7 @@
android:layout_marginRight="@dimen/bottom_sheet_content_margin" android:layout_marginRight="@dimen/bottom_sheet_content_margin"
android:layout_marginStart="@dimen/bottom_sheet_content_margin" android:layout_marginStart="@dimen/bottom_sheet_content_margin"
android:background="@null" android:background="@null"
android:visibility="gone"
tools:src="@drawable/ic_action_arrow_down"/> tools:src="@drawable/ic_action_arrow_down"/>
<TextView <TextView

View file

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

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/custom_radio_buttons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/btn_bg_border_inactive"
android:baselineAligned="false"
android:minHeight="@dimen/dialog_button_height"
android:orientation="horizontal">
<include
layout="@layout/custom_radio_btn_icon_item"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<include
layout="@layout/custom_radio_btn_icon_item"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:background="?attr/selectableItemBackground"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="@dimen/content_padding_small_half"
android:paddingBottom="@dimen/content_padding_small_half"
android:paddingLeft="@dimen/content_padding_small"
android:paddingRight="@dimen/content_padding_small">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_gravity="center"
tools:src="@drawable/ic_action_info_dark"/>
</FrameLayout>

View file

@ -13,10 +13,19 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom" android:layout_gravity="bottom"
android:background="@drawable/bg_bottom_menu_dark"
android:orientation="vertical" android:orientation="vertical"
android:clickable="true" android:clickable="true"
android:focusable="true"> android:focusable="true"
tools:ignore="UselessParent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@drawable/bg_contextmenu_shadow_top_light" />
<ProgressBar <ProgressBar
android:id="@+id/snap_to_road_progress_bar" android:id="@+id/snap_to_road_progress_bar"
@ -24,9 +33,19 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minHeight="0dp" android:minHeight="0dp"
android:visibility="gone" android:background="?attr/list_background_color"
android:visibility="invisible"
tools:visibility="visible" /> tools:visibility="visible" />
</FrameLayout>
<LinearLayout
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/list_background_color"
android:orientation="vertical">
<RelativeLayout <RelativeLayout
android:id="@+id/up_down_row" android:id="@+id/up_down_row"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -305,4 +324,6 @@
</LinearLayout> </LinearLayout>
</LinearLayout>
</FrameLayout> </FrameLayout>

View file

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

View file

@ -31,7 +31,7 @@
tools:text="Some title" /> tools:text="Some title" />
<net.osmand.plus.widgets.TextViewEx <net.osmand.plus.widgets.TextViewEx
android:id="@+id/description" android:id="@+id/title_description"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/title" android:layout_below="@+id/title"
@ -60,6 +60,54 @@
</RelativeLayout> </RelativeLayout>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/primary_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dialog_content_margin"
android:letterSpacing="@dimen/description_letter_spacing"
android:orientation="vertical"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
android:visibility="gone"
app:typeface="@string/font_roboto_regular"
tools:text="@string/srtm_download_single_help_message"
tools:visibility="visible" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/secondary_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/content_padding_small"
android:letterSpacing="@dimen/description_letter_spacing"
android:orientation="vertical"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
android:visibility="gone"
app:typeface="@string/font_roboto_regular"
tools:text="@string/srtm_download_list_help_message"
tools:visibility="visible" />
<include
layout="@layout/custom_radio_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginBottom="@dimen/content_padding_half"
android:visibility="gone"
tools:visibility="visible" />
<LinearLayout <LinearLayout
android:id="@+id/select_all_button" android:id="@+id/select_all_button"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -67,12 +115,12 @@
android:background="?attr/selectableItemBackground" android:background="?attr/selectableItemBackground"
android:gravity="center_vertical" android:gravity="center_vertical"
android:minHeight="@dimen/bottom_sheet_list_item_height" android:minHeight="@dimen/bottom_sheet_list_item_height"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding" android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding_small" android:paddingTop="@dimen/content_padding_small"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding" android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding_small" android:paddingBottom="@dimen/content_padding_small">
android:paddingStart="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding">
<net.osmand.plus.widgets.TextViewEx <net.osmand.plus.widgets.TextViewEx
android:id="@+id/check_box_title" android:id="@+id/check_box_title"

View file

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

View file

@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/bg_color" android:background="?attr/bg_color"
@ -13,78 +11,13 @@
android:layout_height="@dimen/list_content_padding" android:layout_height="@dimen/list_content_padding"
android:background="?attr/activity_background_color" /> android:background="?attr/activity_background_color" />
<include <include layout="@layout/divider" />
layout="@layout/divider" />
<FrameLayout <FrameLayout
android:id="@+id/subscriptions_list_container" android:id="@+id/subscriptions_list_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<LinearLayout
android:id="@+id/support_region_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="?android:attr/selectableItemBackground"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="@dimen/setting_list_item_group_height"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/map_widget_height"
android:layout_marginRight="@dimen/map_widget_height"
app:srcCompat="@drawable/ic_world_globe_dark"
app:tint="?attr/default_icon_color" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="@dimen/content_padding_small"
android:layout_marginBottom="@dimen/content_padding_small"
android:layout_gravity="center_vertical"
android:orientation="vertical">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/support_region_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_regular"
tools:text="@string/osm_live_support_region"/>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/support_region"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:text="@string/osm_live_support_region"
android:textColor="?android:attr/textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_regular"
tools:text="@string/clear_updates_proposition_message"/>
</LinearLayout>
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
app:srcCompat="@drawable/ic_action_settings"
app:tint="?attr/default_icon_color" />
</LinearLayout>
<include layout="@layout/simple_divider_item" />
<LinearLayout <LinearLayout
android:id="@+id/report_container" android:id="@+id/report_container"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -206,8 +139,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/activity_background_color"> android:background="?attr/activity_background_color">
<include <include layout="@layout/card_bottom_divider" />
layout="@layout/card_bottom_divider" />
</FrameLayout> </FrameLayout>

View file

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

View file

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

View file

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

View file

@ -2818,9 +2818,9 @@ POIの更新は利用できません</string>
<string name="osm_live_subscriptions">サブスクリプション</string> <string name="osm_live_subscriptions">サブスクリプション</string>
<string name="powered_by_osmand">By OsmAnd</string> <string name="powered_by_osmand">By OsmAnd</string>
<string name="osm_live_plan_pricing">プランと料金</string> <string name="osm_live_plan_pricing">プランと料金</string>
<string name="osm_live_payment_monthly_title"></string> <string name="osm_live_payment_monthly_title"></string>
<string name="osm_live_payment_3_months_title">3ヶ月毎</string> <string name="osm_live_payment_3_months_title">3ヶ月毎</string>
<string name="osm_live_payment_annual_title"></string> <string name="osm_live_payment_annual_title"></string>
<string name="osm_live_payment_month_cost_descr">%1$s / 月</string> <string name="osm_live_payment_month_cost_descr">%1$s / 月</string>
<string name="osm_live_payment_month_cost_descr_ex">%1$.2f %2$s / 月</string> <string name="osm_live_payment_month_cost_descr_ex">%1$.2f %2$s / 月</string>
<string name="osm_live_payment_discount_descr">%1$s割引</string> <string name="osm_live_payment_discount_descr">%1$s割引</string>

View file

@ -1802,7 +1802,7 @@ failu(s)?
<string name="first_usage_item">Sākt lietot</string> <string name="first_usage_item">Sākt lietot</string>
<string name="first_usage_item_description">Kā lejupielādēt kartes un pamatiestatījumu lietošana</string> <string name="first_usage_item_description">Kā lejupielādēt kartes un pamatiestatījumu lietošana</string>
<string name="navigation_item_description">Navigācija</string> <string name="navigation_item_description">Navigācija</string>
<string name="planning_trip_item">Ceļa plānošana</string> <string name="planning_trip_item">Ceļojuma plānošana</string>
<string name="faq_item">BUJ</string> <string name="faq_item">BUJ</string>
<string name="faq_item_description">Biežāk uzdotie jautājumi</string> <string name="faq_item_description">Biežāk uzdotie jautājumi</string>
<string name="map_viewing_item">Kartes skatīšana</string> <string name="map_viewing_item">Kartes skatīšana</string>
@ -2162,7 +2162,6 @@ Apraksta laukumu: %1$s x %2$s</string>
<string name="shared_string_time">Laiks</string> <string name="shared_string_time">Laiks</string>
<string name="total_distance">Maršruta garums</string> <string name="total_distance">Maršruta garums</string>
<string name="routing_attr_height_obstacles_name">Lietot elevācijas datus</string> <string name="routing_attr_height_obstacles_name">Lietot elevācijas datus</string>
<string name="relief_smoothness_factor_descr">Ieteicamais reljefs: līdzens vai kalnains.</string> <string name="relief_smoothness_factor_descr">Ieteicamais reljefs: līdzens vai kalnains.</string>
<string name="shared_string_slope">Slīpums</string> <string name="shared_string_slope">Slīpums</string>
<string name="lang_ber">Berberu</string> <string name="lang_ber">Berberu</string>
@ -2415,7 +2414,7 @@ No Afganistānas līdz Zimbabvei, no Austrālijas līdz ASV, Argentīna, Brazīl
<string name="show_map">Rādīt karti</string> <string name="show_map">Rādīt karti</string>
<string name="route_is_calculated">Maršruts aprēķināts</string> <string name="route_is_calculated">Maršruts aprēķināts</string>
<string name="round_trip">Turp un atpakaļ</string> <string name="round_trip">Turp un atpakaļ</string>
<string name="plan_route_no_markers_toast">Jums vajag pievienot vismaz vienu marķieri, lai lietotu šo funkciju.</string> <string name="plan_route_no_markers_toast">Lai lietotu šo funkciju, vajag pievienot vismaz vienu marķieri.</string>
<string name="osn_modify_dialog_error">Piezīmei nevarēja veikt izmaiņas</string> <string name="osn_modify_dialog_error">Piezīmei nevarēja veikt izmaiņas</string>
<string name="osn_modify_dialog_title">Labot piezīmi</string> <string name="osn_modify_dialog_title">Labot piezīmi</string>
<string name="context_menu_item_modify_note">!abot OSM piezīmi</string> <string name="context_menu_item_modify_note">!abot OSM piezīmi</string>
@ -2429,7 +2428,7 @@ No Afganistānas līdz Zimbabvei, no Austrālijas līdz ASV, Argentīna, Brazīl
<string name="routing_attr_avoid_ice_roads_fords_name">No ledus ceļiem un brasla</string> <string name="routing_attr_avoid_ice_roads_fords_name">No ledus ceļiem un brasla</string>
<string name="routing_attr_avoid_ice_roads_fords_description">Izvairīties no ledus ceļiem un brasliem.</string> <string name="routing_attr_avoid_ice_roads_fords_description">Izvairīties no ledus ceļiem un brasliem.</string>
<string name="use_location">Lietot pozīciju</string> <string name="use_location">Lietot pozīciju</string>
<string name="add_location_as_first_point_descr">Pievienot jūsu atrašanās vietu kā sākuma punktu maršrutam.</string> <string name="add_location_as_first_point_descr">Pievienot patreizējo atrašanās vietu kā sākuma punktu ideālā maršruta izveidei.</string>
<string name="my_location">Mana pozīcija</string> <string name="my_location">Mana pozīcija</string>
<string name="shared_string_finish">Finišs</string> <string name="shared_string_finish">Finišs</string>
<string name="plan_route">Plānot maršrutu</string> <string name="plan_route">Plānot maršrutu</string>
@ -3333,4 +3332,19 @@ No Afganistānas līdz Zimbabvei, no Austrālijas līdz ASV, Argentīna, Brazīl
<string name="select_items_for_import">Izvēlieties lietas, ko importēt.</string> <string name="select_items_for_import">Izvēlieties lietas, ko importēt.</string>
<string name="use_dev_url_descr">Lietot dev.openstreetmap.org nevis openstreetmap.org OSM piezīmju/ POI / GPX augšuielādei un testēšanai.</string> <string name="use_dev_url_descr">Lietot dev.openstreetmap.org nevis openstreetmap.org OSM piezīmju/ POI / GPX augšuielādei un testēšanai.</string>
<string name="use_dev_url">Lietot dev.openstreetmap.org</string> <string name="use_dev_url">Lietot dev.openstreetmap.org</string>
<string name="plan_a_route">Plānot maršrutu</string>
<string name="plan_route_last_edited">Pēdējo reizi labots</string>
<string name="plan_route_import_track">Importēt treku</string>
<string name="plan_route_open_existing_track">Atvērt saglabāto treku</string>
<string name="plan_route_create_new_route">Veidot jaunu maršrutu</string>
<string name="plan_route_select_track_file_for_open">Izvēlieties treka failu atvēršanai.</string>
<string name="plan_route_exit_dialog_descr">Vai tiešām gribat atmest visas izmaiņas ieplānotajā maršrutā\?</string>
<string name="plan_route_trim_before">Griezt pirms</string>
<string name="plan_route_trim_after">Griezt pēc</string>
<string name="plan_route_change_route_type_before">Mainīt maršruta veidu pirms</string>
<string name="plan_route_change_route_type_after">Mainīt maršruta veidu pēc</string>
<string name="plan_route_join_segments">Pievienot segmentus</string>
<string name="plan_route_split_before">Sadalīt pirms</string>
<string name="plan_route_split_after">Sadalīt pēc</string>
<string name="plan_route_add_new_segment">Pievienot jaunu segmentu</string>
</resources> </resources>

View file

@ -3918,4 +3918,13 @@
<string name="poi_jiu_jitsu">Jiu-jitsu</string> <string name="poi_jiu_jitsu">Jiu-jitsu</string>
<string name="poi_karate">Karatê</string> <string name="poi_karate">Karatê</string>
<string name="poi_hoops">Aros</string> <string name="poi_hoops">Aros</string>
<string name="poi_club_social">Clube social</string>
<string name="poi_plateau">Planalto</string>
<string name="poi_office_diplomatic">Escritório diplomático</string>
<string name="poi_kickboxing">Kickboxe</string>
<string name="poi_cycle_polo">Polo de bicicleta</string>
<string name="poi_curling">Curling</string>
<string name="poi_cliff_diving">Mergulho de falésia</string>
<string name="poi_zurkhaneh_sport">Zurkhaneh</string>
<string name="poi_bay_filter">Tipo de baía</string>
</resources> </resources>

View file

@ -4006,7 +4006,7 @@
<string name="routing_attr_driving_style_description">Zvoľte účel jazdy pre získanie kratšej, rýchlejšej alebo bezpečnejšej trasy</string> <string name="routing_attr_driving_style_description">Zvoľte účel jazdy pre získanie kratšej, rýchlejšej alebo bezpečnejšej trasy</string>
<string name="map_orientation_threshold_descr">Neotáčať mapu, ak je rýchlosť nižšia ako hranica</string> <string name="map_orientation_threshold_descr">Neotáčať mapu, ak je rýchlosť nižšia ako hranica</string>
<string name="restart">Reštartovať</string> <string name="restart">Reštartovať</string>
<string name="shared_strings_all_regions">Všetky regióny</string> <string name="shared_strings_all_regions">Všetky oblasti</string>
<string name="delete_number_files_question">Zmazať %1$d súborov\?</string> <string name="delete_number_files_question">Zmazať %1$d súborov\?</string>
<string name="track_recording_stop_without_saving">Zastaviť bez uloženia</string> <string name="track_recording_stop_without_saving">Zastaviť bez uloženia</string>
<string name="track_recording_save_and_stop">Uložiť a zastaviť záznam</string> <string name="track_recording_save_and_stop">Uložiť a zastaviť záznam</string>

View file

@ -3927,4 +3927,5 @@
<string name="poi_office_diplomatic">Diplomatiskt kontor</string> <string name="poi_office_diplomatic">Diplomatiskt kontor</string>
<string name="poi_bay_filter">Typ av vik</string> <string name="poi_bay_filter">Typ av vik</string>
<string name="poi_plateau">Platå</string> <string name="poi_plateau">Platå</string>
<string name="poi_club_social">Social klubb</string>
</resources> </resources>

View file

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

View file

@ -16,6 +16,10 @@
<string name="user_points">User points</string> <string name="user_points">User points</string>
<string name="announce_when_exceeded">Announce when exceeded</string> <string name="announce_when_exceeded">Announce when exceeded</string>
<string name="exit_number">Exit number</string> <string name="exit_number">Exit number</string>
<string name="srtm_download_single_help_message">Please select the needed format. You will need to re-download the file to change the format.</string>
<string name="srtm_download_list_help_message">OsmAnd provides contour lines data in meters and feet. You will need to re-download the file to change the format.</string>
<string name="srtm_unit_format">Contour lines unit format</string>
<string name="shared_string_feet">feet</string>
<string name="update_all_maps_added">Update all maps added to %1$s?</string> <string name="update_all_maps_added">Update all maps added to %1$s?</string>
<string name="release_4_0_beta"> <string name="release_4_0_beta">
• OsmAnd Live updates moved to \"Downloads > Updates\"\n\n • OsmAnd Live updates moved to \"Downloads > Updates\"\n\n

View file

@ -442,15 +442,14 @@ public class UiUtilities {
} catch (Throwable e) { } } catch (Throwable e) { }
} }
public static void rotateImageByLayoutDirection(ImageView image, int layoutDirection) { public static void rotateImageByLayoutDirection(ImageView image) {
if (image == null) { if (image == null) {
return; return;
} }
int rotation = layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL ? 180 : 0; int rotation = AndroidUtils.getLayoutDirection(image.getContext()) == ViewCompat.LAYOUT_DIRECTION_RTL ? 180 : 0;
image.setRotationY(rotation); image.setRotationY(rotation);
} }
public static void updateCustomRadioButtons(Context app, View buttonsView, boolean nightMode, public static void updateCustomRadioButtons(Context app, View buttonsView, boolean nightMode,
CustomRadioButtonType buttonType) { CustomRadioButtonType buttonType) {
int activeColor = ContextCompat.getColor(app, nightMode int activeColor = ContextCompat.getColor(app, nightMode

View file

@ -13,6 +13,7 @@ import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.SQLiteTileSource; import net.osmand.plus.SQLiteTileSource;
import net.osmand.plus.Version; import net.osmand.plus.Version;
import net.osmand.plus.download.SrtmDownloadItem;
import net.osmand.plus.download.ui.AbstractLoadLocalIndexTask; import net.osmand.plus.download.ui.AbstractLoadLocalIndexTask;
import net.osmand.plus.voice.JSMediaCommandPlayerImpl; import net.osmand.plus.voice.JSMediaCommandPlayerImpl;
import net.osmand.plus.voice.JSTTSCommandPlayerImpl; import net.osmand.plus.voice.JSTTSCommandPlayerImpl;
@ -143,8 +144,6 @@ public class LocalIndexHelper {
return null; return null;
} }
public List<LocalIndexInfo> getLocalIndexInfos(String downloadName) { public List<LocalIndexInfo> getLocalIndexInfos(String downloadName) {
List<LocalIndexInfo> list = new ArrayList<>(); List<LocalIndexInfo> list = new ArrayList<>();
LocalIndexInfo info = getLocalIndexInfo(LocalIndexType.MAP_DATA, downloadName, false, false); LocalIndexInfo info = getLocalIndexInfo(LocalIndexType.MAP_DATA, downloadName, false, false);
@ -333,14 +332,15 @@ public class LocalIndexHelper {
if (mapPath.canRead()) { if (mapPath.canRead()) {
for (File mapFile : listFilesSorted(mapPath)) { for (File mapFile : listFilesSorted(mapPath)) {
if (mapFile.isFile() && mapFile.getName().endsWith(IndexConstants.BINARY_MAP_INDEX_EXT)) { if (mapFile.isFile() && mapFile.getName().endsWith(IndexConstants.BINARY_MAP_INDEX_EXT)) {
String fileName = mapFile.getName();
LocalIndexType lt = LocalIndexType.MAP_DATA; LocalIndexType lt = LocalIndexType.MAP_DATA;
if (mapFile.getName().endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)) { if (SrtmDownloadItem.isSrtmFile(fileName)) {
lt = LocalIndexType.SRTM_DATA; lt = LocalIndexType.SRTM_DATA;
} else if (mapFile.getName().endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) { } else if (fileName.endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) {
lt = LocalIndexType.WIKI_DATA; lt = LocalIndexType.WIKI_DATA;
} }
LocalIndexInfo info = new LocalIndexInfo(lt, mapFile, backup, app); LocalIndexInfo info = new LocalIndexInfo(lt, mapFile, backup, app);
if (loadedMaps.containsKey(mapFile.getName()) && !backup) { if (loadedMaps.containsKey(fileName) && !backup) {
info.setLoaded(true); info.setLoaded(true);
} }
updateDescription(info); updateDescription(info);
@ -430,5 +430,4 @@ public class LocalIndexHelper {
return fileName; return fileName;
} }
} }
} }

View file

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

View file

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

View file

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

View file

@ -0,0 +1,80 @@
package net.osmand.plus.base;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentManager;
import net.osmand.AndroidUtils;
import net.osmand.plus.R;
import net.osmand.plus.widgets.multistatetoggle.RadioItem;
import java.util.Collections;
import java.util.List;
public class ModeSelectionBottomSheet extends SelectionBottomSheet {
public static final String TAG = ModeSelectionBottomSheet.class.getSimpleName();
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
showElements(primaryDescription, toggleContainer);
hideElements(checkBox, checkBoxTitle, titleDescription,
secondaryDescription, selectedSize, selectAllButton);
}
@Override
protected void updateItemView(SelectableItem item, View view) {
ImageView ivIcon = view.findViewById(R.id.icon);
TextView tvTitle = view.findViewById(R.id.title);
TextView tvDescr = view.findViewById(R.id.description);
Drawable icon = uiUtilities.getIcon(item.getIconId(), activeColorRes);
ivIcon.setImageDrawable(icon);
tvTitle.setText(item.getTitle());
tvDescr.setText(item.getDescription());
tvDescr.setTextColor(ContextCompat.getColor(app, AndroidUtils.getSecondaryTextColorId(nightMode)));
}
@Override
protected int getItemLayoutId() {
return R.layout.bottom_sheet_item_with_descr_56dp;
}
public void setItem(SelectableItem item) {
setItems(Collections.singletonList(item));
}
@NonNull
@Override
public List<SelectableItem> getSelectedItems() {
return allItems;
}
@Override
protected boolean shouldShowDivider() {
return false;
}
public static ModeSelectionBottomSheet showInstance(@NonNull AppCompatActivity activity,
@NonNull SelectableItem previewItem,
@NonNull List<RadioItem> radioItems,
boolean usedOnMap) {
ModeSelectionBottomSheet fragment = new ModeSelectionBottomSheet();
fragment.setUsedOnMap(usedOnMap);
fragment.setModes(radioItems);
fragment.setItems(Collections.singletonList(previewItem));
FragmentManager fm = activity.getSupportFragmentManager();
fragment.show(fm, TAG);
return fragment;
}
}

View file

@ -0,0 +1,180 @@
package net.osmand.plus.base;
import android.content.res.ColorStateList;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.core.widget.CompoundButtonCompat;
import androidx.fragment.app.FragmentManager;
import net.osmand.AndroidUtils;
import net.osmand.plus.R;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.util.Algorithms;
import java.util.ArrayList;
import java.util.List;
import static net.osmand.view.ThreeStateCheckbox.State.CHECKED;
import static net.osmand.view.ThreeStateCheckbox.State.MISC;
import static net.osmand.view.ThreeStateCheckbox.State.UNCHECKED;
public class MultipleSelectionBottomSheet extends SelectionBottomSheet {
public static final String TAG = MultipleSelectionBottomSheet.class.getSimpleName();
private final List<SelectableItem> selectedItems = new ArrayList<>();
private SelectionUpdateListener selectionUpdateListener;
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
selectAllButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
checkBox.performClick();
boolean checked = checkBox.getState() == CHECKED;
if (checked) {
selectedItems.addAll(allItems);
} else {
selectedItems.clear();
}
onSelectedItemsChanged();
updateItemsSelection(checked);
}
});
}
@Override
protected boolean shouldShowDivider() {
return true;
}
@Override
protected void updateItemView(final SelectableItem item, View view) {
boolean checked = selectedItems.contains(item);
ImageView imageView = view.findViewById(R.id.icon);
TextView title = view.findViewById(R.id.title);
TextView description = view.findViewById(R.id.description);
final CheckBox checkBox = view.findViewById(R.id.compound_button);
AndroidUiHelper.setVisibility(View.VISIBLE, imageView, title, description, checkBox);
checkBox.setChecked(checked);
CompoundButtonCompat.setButtonTintList(checkBox, AndroidUtils.createCheckedColorStateList(app, secondaryColorRes, activeColorRes));
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
boolean checked = !checkBox.isChecked();
checkBox.setChecked(checked);
if (checked) {
selectedItems.add(item);
} else {
selectedItems.remove(item);
}
onSelectedItemsChanged();
}
});
title.setText(item.getTitle());
description.setText(item.getDescription());
imageView.setImageDrawable(uiUtilities.getIcon(item.getIconId(), activeColorRes));
}
@Override
protected int getItemLayoutId() {
return R.layout.bottom_sheet_item_with_descr_and_checkbox_56dp;
}
@Override
protected void notifyUiInitialized() {
onSelectedItemsChanged();
super.notifyUiInitialized();
}
private void onSelectedItemsChanged() {
updateSelectAllButton();
updateSelectedSizeView();
updateApplyButtonEnable();
if (selectionUpdateListener != null) {
selectionUpdateListener.onSelectionUpdate();
}
}
private void updateSelectAllButton() {
String checkBoxTitle;
if (Algorithms.isEmpty(selectedItems)) {
checkBox.setState(UNCHECKED);
checkBoxTitle = getString(R.string.shared_string_select_all);
} else {
checkBox.setState(selectedItems.containsAll(allItems) ? CHECKED : MISC);
checkBoxTitle = getString(R.string.shared_string_deselect_all);
}
int checkBoxColor = checkBox.getState() == UNCHECKED ? secondaryColorRes : activeColorRes;
CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, checkBoxColor)));
this.checkBoxTitle.setText(checkBoxTitle);
}
private void updateSelectedSizeView() {
String selected = String.valueOf(selectedItems.size());
String all = String.valueOf(allItems.size());
selectedSize.setText(getString(R.string.ltr_or_rtl_combine_via_slash, selected, all));
}
private void updateApplyButtonEnable() {
boolean noEmptySelection = !Algorithms.isEmpty(selectedItems);
rightButton.setEnabled(noEmptySelection);
}
private void updateItemsSelection(boolean checked) {
for (SelectableItem item : allItems) {
View v = listViews.get(item);
CheckBox checkBox = v != null ? (CheckBox) v.findViewById(R.id.compound_button) : null;
if (checkBox != null) {
checkBox.setChecked(checked);
}
}
}
protected void setSelectedItems(List<SelectableItem> selected) {
selectedItems.clear();
if (!Algorithms.isEmpty(selected)) {
selectedItems.addAll(selected);
}
}
@NonNull
@Override
public List<SelectableItem> getSelectedItems() {
return selectedItems;
}
public void setSelectionUpdateListener(SelectionUpdateListener selectionUpdateListener) {
this.selectionUpdateListener = selectionUpdateListener;
}
public static MultipleSelectionBottomSheet showInstance(@NonNull AppCompatActivity activity,
@NonNull List<SelectableItem> items,
@Nullable List<SelectableItem> selected,
boolean usedOnMap) {
MultipleSelectionBottomSheet fragment = new MultipleSelectionBottomSheet();
fragment.setUsedOnMap(usedOnMap);
fragment.setItems(items);
fragment.setSelectedItems(selected);
FragmentManager fm = activity.getSupportFragmentManager();
fragment.show(fm, TAG);
return fragment;
}
public interface SelectionUpdateListener {
void onSelectionUpdate();
}
}

View file

@ -0,0 +1,41 @@
package net.osmand.plus.base;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;
import net.osmand.plus.widgets.multistatetoggle.RadioItem;
import java.util.List;
public class MultipleSelectionWithModeBottomSheet extends MultipleSelectionBottomSheet {
public static final String TAG = MultipleSelectionWithModeBottomSheet.class.getSimpleName();
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
showElements(secondaryDescription, toggleContainer, checkBox,
checkBoxTitle, titleDescription, selectedSize, selectAllButton);
}
public static MultipleSelectionWithModeBottomSheet showInstance(@NonNull AppCompatActivity activity,
@NonNull List<SelectableItem> items,
@Nullable List<SelectableItem> selected,
@NonNull List<RadioItem> modes,
boolean usedOnMap) {
MultipleSelectionWithModeBottomSheet fragment = new MultipleSelectionWithModeBottomSheet();
fragment.setUsedOnMap(usedOnMap);
fragment.setItems(items);
fragment.setSelectedItems(selected);
fragment.setModes(modes);
FragmentManager fm = activity.getSupportFragmentManager();
fragment.show(fm, TAG);
return fragment;
}
}

View file

@ -1,301 +0,0 @@
package net.osmand.plus.base;
import android.content.res.ColorStateList;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.core.widget.CompoundButtonCompat;
import androidx.fragment.app.FragmentManager;
import net.osmand.AndroidUtils;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithCompoundButton;
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithCompoundButton.Builder;
import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.SimpleDividerItem;
import net.osmand.util.Algorithms;
import net.osmand.view.ThreeStateCheckbox;
import java.util.ArrayList;
import java.util.List;
import static net.osmand.view.ThreeStateCheckbox.State.CHECKED;
import static net.osmand.view.ThreeStateCheckbox.State.MISC;
import static net.osmand.view.ThreeStateCheckbox.State.UNCHECKED;
public class SelectMultipleItemsBottomSheet extends MenuBottomSheetDialogFragment {
private OsmandApplication app;
private UiUtilities uiUtilities;
private TextView title;
private TextView description;
private TextView applyButtonTitle;
private TextView checkBoxTitle;
private TextView selectedSize;
private ThreeStateCheckbox checkBox;
private int activeColorRes;
private int secondaryColorRes;
private final List<SelectableItem> allItems = new ArrayList<>();
private final List<SelectableItem> selectedItems = new ArrayList<>();
private SelectionUpdateListener selectionUpdateListener;
private OnApplySelectionListener onApplySelectionListener;
public static final String TAG = SelectMultipleItemsBottomSheet.class.getSimpleName();
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
View mainView = super.onCreateView(inflater, parent, savedInstanceState);
onSelectedItemsChanged();
return mainView;
}
@Override
public void createMenuItems(Bundle savedInstanceState) {
app = requiredMyApplication();
uiUtilities = app.getUIUtilities();
activeColorRes = nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light;
secondaryColorRes = nightMode ? R.color.icon_color_secondary_dark : R.color.icon_color_secondary_light;
items.add(createTitleItem());
items.add(new SimpleDividerItem(app));
createListItems();
}
private BaseBottomSheetItem createTitleItem() {
LayoutInflater themedInflater = UiUtilities.getInflater(requireContext(), nightMode);
View view = themedInflater.inflate(R.layout.settings_group_title, null);
checkBox = view.findViewById(R.id.check_box);
checkBoxTitle = view.findViewById(R.id.check_box_title);
description = view.findViewById(R.id.description);
selectedSize = view.findViewById(R.id.selected_size);
title = view.findViewById(R.id.title);
View selectAllButton = view.findViewById(R.id.select_all_button);
selectAllButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
checkBox.performClick();
boolean checked = checkBox.getState() == CHECKED;
if (checked) {
selectedItems.addAll(allItems);
} else {
selectedItems.clear();
}
onSelectedItemsChanged();
updateItems(checked);
}
});
return new SimpleBottomSheetItem.Builder().setCustomView(view).create();
}
private void createListItems() {
for (final SelectableItem item : allItems) {
boolean checked = selectedItems.contains(item);
final BottomSheetItemWithCompoundButton[] uiItem = new BottomSheetItemWithCompoundButton[1];
final Builder builder = (BottomSheetItemWithCompoundButton.Builder) new Builder();
builder.setChecked(checked)
.setButtonTintList(AndroidUtils.createCheckedColorStateList(app, secondaryColorRes, activeColorRes))
.setLayoutId(R.layout.bottom_sheet_item_with_descr_and_checkbox_56dp)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean checked = !uiItem[0].isChecked();
uiItem[0].setChecked(checked);
SelectableItem tag = (SelectableItem) uiItem[0].getTag();
if (checked) {
selectedItems.add(tag);
} else {
selectedItems.remove(tag);
}
onSelectedItemsChanged();
}
})
.setTag(item);
setupListItem(builder, item);
uiItem[0] = builder.create();
items.add(uiItem[0]);
}
}
@Override
protected void setupRightButton() {
super.setupRightButton();
applyButtonTitle = rightButton.findViewById(R.id.button_text);
}
@Override
protected void onRightBottomButtonClick() {
if (onApplySelectionListener != null) {
onApplySelectionListener.onSelectionApplied(selectedItems);
}
dismiss();
}
private void onSelectedItemsChanged() {
updateSelectAllButton();
updateSelectedSizeView();
updateApplyButtonEnable();
if (selectionUpdateListener != null) {
selectionUpdateListener.onSelectionUpdate();
}
}
@Override
protected int getRightBottomButtonTextId() {
return R.string.shared_string_apply;
}
@Override
protected boolean useVerticalButtons() {
return true;
}
private void setupListItem(Builder builder, SelectableItem item) {
builder.setTitle(item.title);
builder.setDescription(item.description);
builder.setIcon(uiUtilities.getIcon(item.iconId, activeColorRes));
}
private void updateSelectAllButton() {
String checkBoxTitle;
if (Algorithms.isEmpty(selectedItems)) {
checkBox.setState(UNCHECKED);
checkBoxTitle = getString(R.string.shared_string_select_all);
} else {
checkBox.setState(selectedItems.containsAll(allItems) ? CHECKED : MISC);
checkBoxTitle = getString(R.string.shared_string_deselect_all);
}
int checkBoxColor = checkBox.getState() == UNCHECKED ? secondaryColorRes : activeColorRes;
CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, checkBoxColor)));
this.checkBoxTitle.setText(checkBoxTitle);
}
private void updateSelectedSizeView() {
String selected = String.valueOf(selectedItems.size());
String all = String.valueOf(allItems.size());
selectedSize.setText(getString(R.string.ltr_or_rtl_combine_via_slash, selected, all));
}
private void updateApplyButtonEnable() {
if (Algorithms.isEmpty(selectedItems)) {
rightButton.setEnabled(false);
} else {
rightButton.setEnabled(true);
}
}
private void updateItems(boolean checked) {
for (BaseBottomSheetItem item : items) {
if (item instanceof BottomSheetItemWithCompoundButton) {
((BottomSheetItemWithCompoundButton) item).setChecked(checked);
}
}
}
public void setTitle(@NonNull String title) {
this.title.setText(title);
}
public void setDescription(@NonNull String description) {
this.description.setText(description);
}
public void setConfirmButtonTitle(@NonNull String confirmButtonTitle) {
applyButtonTitle.setText(confirmButtonTitle);
}
private void setItems(List<SelectableItem> allItems) {
if (!Algorithms.isEmpty(allItems)) {
this.allItems.addAll(allItems);
}
}
private void setSelectedItems(List<SelectableItem> selected) {
if (!Algorithms.isEmpty(selected)) {
this.selectedItems.addAll(selected);
}
}
public List<SelectableItem> getSelectedItems() {
return selectedItems;
}
@Override
public void onPause() {
super.onPause();
if (requireActivity().isChangingConfigurations()) {
dismiss();
}
}
public static SelectMultipleItemsBottomSheet showInstance(@NonNull AppCompatActivity activity,
@NonNull List<SelectableItem> items,
@Nullable List<SelectableItem> selected,
boolean usedOnMap) {
SelectMultipleItemsBottomSheet fragment = new SelectMultipleItemsBottomSheet();
fragment.setUsedOnMap(usedOnMap);
fragment.setItems(items);
fragment.setSelectedItems(selected);
FragmentManager fm = activity.getSupportFragmentManager();
fragment.show(fm, TAG);
return fragment;
}
public void setSelectionUpdateListener(SelectionUpdateListener selectionUpdateListener) {
this.selectionUpdateListener = selectionUpdateListener;
}
public void setOnApplySelectionListener(OnApplySelectionListener onApplySelectionListener) {
this.onApplySelectionListener = onApplySelectionListener;
}
public interface SelectionUpdateListener {
void onSelectionUpdate();
}
public interface OnApplySelectionListener {
void onSelectionApplied(List<SelectableItem> selectedItems);
}
public static class SelectableItem {
private String title;
private String description;
private int iconId;
private Object object;
public void setTitle(String title) {
this.title = title;
}
public void setDescription(String description) {
this.description = description;
}
public void setIconId(int iconId) {
this.iconId = iconId;
}
public void setObject(Object object) {
this.object = object;
}
public Object getObject() {
return object;
}
}
}

View file

@ -0,0 +1,290 @@
package net.osmand.plus.base;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.SimpleDividerItem;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.widgets.multistatetoggle.MultiStateToggleButton;
import net.osmand.plus.widgets.multistatetoggle.RadioItem;
import net.osmand.plus.widgets.multistatetoggle.TextToggleButton;
import net.osmand.util.Algorithms;
import net.osmand.view.ThreeStateCheckbox;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public abstract class SelectionBottomSheet extends MenuBottomSheetDialogFragment {
protected OsmandApplication app;
protected LayoutInflater inflater;
protected UiUtilities uiUtilities;
protected TextView title;
protected TextView titleDescription;
protected TextView primaryDescription;
protected TextView secondaryDescription;
protected TextView selectedSize;
protected LinearLayout toggleContainer;
protected MultiStateToggleButton radioGroup;
protected View selectAllButton;
protected TextView checkBoxTitle;
protected ThreeStateCheckbox checkBox;
protected LinearLayout listContainer;
protected TextView applyButtonTitle;
protected int activeColorRes;
protected int secondaryColorRes;
private OnUiInitializedAdapter onUiInitializedAdapter;
private OnApplySelectionListener onApplySelectionListener;
protected List<SelectableItem> allItems = new ArrayList<>();
protected Map<SelectableItem, View> listViews = new HashMap<>();
private List<RadioItem> modes;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
View mainView = super.onCreateView(inflater, parent, savedInstanceState);
createSelectionListIfPossible();
notifyUiInitialized();
return mainView;
}
@Override
public void createMenuItems(Bundle savedInstanceState) {
app = requiredMyApplication();
uiUtilities = app.getUIUtilities();
inflater = UiUtilities.getInflater(requireContext(), nightMode);
activeColorRes = nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light;
secondaryColorRes = nightMode ? R.color.icon_color_secondary_dark : R.color.icon_color_secondary_light;
items.add(createHeaderView());
if (shouldShowDivider()) {
items.add(new SimpleDividerItem(app));
}
items.add(createSelectionView());
}
private BaseBottomSheetItem createHeaderView() {
View view = inflater.inflate(R.layout.settings_group_title, null);
title = view.findViewById(R.id.title);
titleDescription = view.findViewById(R.id.title_description);
primaryDescription = view.findViewById(R.id.primary_description);
secondaryDescription = view.findViewById(R.id.secondary_description);
selectedSize = view.findViewById(R.id.selected_size);
toggleContainer = view.findViewById(R.id.custom_radio_buttons);
radioGroup = new TextToggleButton(app, toggleContainer, nightMode);
selectAllButton = view.findViewById(R.id.select_all_button);
checkBoxTitle = view.findViewById(R.id.check_box_title);
checkBox = view.findViewById(R.id.check_box);
if (modes != null) {
radioGroup.setItems(modes);
}
return new SimpleBottomSheetItem.Builder().setCustomView(view).create();
}
private BaseBottomSheetItem createSelectionView() {
Context themedCtx = UiUtilities.getThemedContext(requireContext(), nightMode);
listContainer = new LinearLayout(themedCtx);
listContainer.setLayoutParams(new LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
listContainer.setOrientation(LinearLayout.VERTICAL);
return new SimpleBottomSheetItem.Builder().setCustomView(listContainer).create();
}
public void setTitle(@NonNull String title) {
this.title.setText(title);
}
public void setTitleDescription(@NonNull String description) {
titleDescription.setText(description);
}
public void setPrimaryDescription(@NonNull String description) {
primaryDescription.setText(description);
}
public void setSecondaryDescription(@NonNull String description) {
secondaryDescription.setText(description);
}
public void setApplyButtonTitle(@NonNull String title) {
applyButtonTitle.setText(title);
}
public void setModes(@NonNull List<RadioItem> modes) {
this.modes = modes;
if (radioGroup != null) {
radioGroup.setItems(modes);
}
}
public void setSelectedMode(@NonNull RadioItem mode) {
radioGroup.setSelectedItem(mode);
}
public void setItems(List<SelectableItem> allItems) {
this.allItems.clear();
if (!Algorithms.isEmpty(allItems)) {
this.allItems.addAll(allItems);
createSelectionListIfPossible();
}
}
public void setOnUiInitializedAdapter(OnUiInitializedAdapter onUiInitializedAdapter) {
this.onUiInitializedAdapter = onUiInitializedAdapter;
}
public void setOnApplySelectionListener(OnApplySelectionListener onApplySelectionListener) {
this.onApplySelectionListener = onApplySelectionListener;
}
private void createSelectionListIfPossible() {
if (listContainer != null && allItems != null) {
recreateList();
}
}
private void recreateList() {
listViews.clear();
listContainer.removeAllViews();
for (SelectableItem item : allItems) {
setupItemView(item, inflater.inflate(getItemLayoutId(), null));
}
}
private void setupItemView(SelectableItem item, View view) {
updateItemView(item, view);
listViews.put(item, view);
listContainer.addView(view);
}
public List<SelectableItem> getAllItems() {
return allItems;
}
@NonNull
public abstract List<SelectableItem> getSelectedItems();
protected abstract void updateItemView(SelectableItem item, View view);
protected abstract int getItemLayoutId();
protected abstract boolean shouldShowDivider();
protected void notifyUiInitialized() {
if (onUiInitializedAdapter != null) {
onUiInitializedAdapter.onUiInitialized();
}
}
protected void showElements(View... views) {
AndroidUiHelper.setVisibility(View.VISIBLE, views);
}
protected void hideElements(View... views) {
AndroidUiHelper.setVisibility(View.GONE, views);
}
@Override
protected void setupRightButton() {
super.setupRightButton();
applyButtonTitle = rightButton.findViewById(R.id.button_text);
}
@Override
protected void onRightBottomButtonClick() {
if (onApplySelectionListener != null) {
onApplySelectionListener.onSelectionApplied(getSelectedItems());
}
dismiss();
}
@Override
protected int getRightBottomButtonTextId() {
return R.string.shared_string_apply;
}
@Override
protected boolean useVerticalButtons() {
return true;
}
@Override
public void onPause() {
super.onPause();
if (requireActivity().isChangingConfigurations()) {
dismiss();
}
}
public interface OnUiInitializedAdapter {
void onUiInitialized();
}
public interface OnApplySelectionListener {
void onSelectionApplied(List<SelectableItem> selectedItems);
}
public static class SelectableItem {
private String title;
private String description;
private int iconId;
private Object object;
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
public int getIconId() {
return iconId;
}
public Object getObject() {
return object;
}
public void setTitle(String title) {
this.title = title;
}
public void setDescription(String description) {
this.description = description;
}
public void setIconId(int iconId) {
this.iconId = iconId;
}
public void setObject(Object object) {
this.object = object;
}
}
}

View file

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

View file

@ -10,6 +10,7 @@ import net.osmand.map.OsmandRegions;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.Version; import net.osmand.plus.Version;
import net.osmand.plus.activities.LocalIndexInfo;
import net.osmand.plus.helpers.FileNameTranslationHelper; import net.osmand.plus.helpers.FileNameTranslationHelper;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
@ -27,6 +28,7 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import static net.osmand.IndexConstants.BINARY_MAP_INDEX_EXT; import static net.osmand.IndexConstants.BINARY_MAP_INDEX_EXT;
import static net.osmand.plus.activities.LocalIndexHelper.LocalIndexType.SRTM_DATA;
public class DownloadActivityType { public class DownloadActivityType {
private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.MM.yyyy", Locale.US); private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.MM.yyyy", Locale.US);
@ -145,8 +147,9 @@ public class DownloadActivityType {
return fileName.endsWith(addVersionToExt(IndexConstants.BINARY_TRAVEL_GUIDE_MAP_INDEX_EXT_ZIP, return fileName.endsWith(addVersionToExt(IndexConstants.BINARY_TRAVEL_GUIDE_MAP_INDEX_EXT_ZIP,
IndexConstants.BINARY_MAP_VERSION)); IndexConstants.BINARY_MAP_VERSION));
} else if (SRTM_COUNTRY_FILE == this) { } else if (SRTM_COUNTRY_FILE == this) {
return fileName.endsWith(addVersionToExt(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT_ZIP, boolean srtm = fileName.endsWith(addVersionToExt(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT_ZIP, IndexConstants.BINARY_MAP_VERSION));
IndexConstants.BINARY_MAP_VERSION)); boolean srtmf = fileName.endsWith(addVersionToExt(IndexConstants.BINARY_SRTM_FEET_MAP_INDEX_EXT_ZIP, IndexConstants.BINARY_MAP_VERSION));
return srtm || srtmf;
} else if (HILLSHADE_FILE == this) { } else if (HILLSHADE_FILE == this) {
return fileName.endsWith(IndexConstants.SQLITE_EXT); return fileName.endsWith(IndexConstants.SQLITE_EXT);
} else if (SLOPE_FILE == this) { } else if (SLOPE_FILE == this) {
@ -227,7 +230,7 @@ public class DownloadActivityType {
} else if (FONT_FILE == this) { } else if (FONT_FILE == this) {
return IndexConstants.FONT_INDEX_EXT; return IndexConstants.FONT_INDEX_EXT;
} else if (SRTM_COUNTRY_FILE == this) { } else if (SRTM_COUNTRY_FILE == this) {
return IndexConstants.BINARY_SRTM_MAP_INDEX_EXT; return SrtmDownloadItem.getExtension(indexItem);
} else if (WIKIPEDIA_FILE == this) { } else if (WIKIPEDIA_FILE == this) {
return IndexConstants.BINARY_WIKI_MAP_INDEX_EXT; return IndexConstants.BINARY_WIKI_MAP_INDEX_EXT;
} else if (WIKIVOYAGE_FILE == this) { } else if (WIKIVOYAGE_FILE == this) {
@ -361,6 +364,9 @@ public class DownloadActivityType {
if (basename.endsWith(FileNameTranslationHelper.WIKI_NAME)) { if (basename.endsWith(FileNameTranslationHelper.WIKI_NAME)) {
return FileNameTranslationHelper.getWikiName(ctx, basename); return FileNameTranslationHelper.getWikiName(ctx, basename);
} }
if (basename.endsWith(FileNameTranslationHelper.WIKIVOYAGE_NAME)) {
return FileNameTranslationHelper.getWikivoyageName(ctx, basename);
}
// if (this == HILLSHADE_FILE){ // if (this == HILLSHADE_FILE){
// return FileNameTranslationHelper.getHillShadeName(ctx, osmandRegions, bn); // return FileNameTranslationHelper.getHillShadeName(ctx, osmandRegions, bn);
// } // }
@ -423,7 +429,7 @@ public class DownloadActivityType {
} }
String baseNameWithoutVersion = fileName.substring(0, l); String baseNameWithoutVersion = fileName.substring(0, l);
if (this == SRTM_COUNTRY_FILE) { if (this == SRTM_COUNTRY_FILE) {
return baseNameWithoutVersion + IndexConstants.BINARY_SRTM_MAP_INDEX_EXT; return baseNameWithoutVersion + SrtmDownloadItem.getExtension(item);
} }
if (this == WIKIPEDIA_FILE) { if (this == WIKIPEDIA_FILE) {
return baseNameWithoutVersion + IndexConstants.BINARY_WIKI_MAP_INDEX_EXT; return baseNameWithoutVersion + IndexConstants.BINARY_WIKI_MAP_INDEX_EXT;

View file

@ -240,9 +240,12 @@ public class DownloadIndexesThread {
} }
public void cancelDownload(DownloadItem item) { public void cancelDownload(DownloadItem item) {
if (item instanceof MultipleIndexItem) { if (item instanceof MultipleDownloadItem) {
MultipleIndexItem multipleIndexItem = (MultipleIndexItem) item; MultipleDownloadItem multipleDownloadItem = (MultipleDownloadItem) item;
cancelDownload(multipleIndexItem.getAllIndexes()); cancelDownload(multipleDownloadItem.getAllIndexes());
} else if (item instanceof SrtmDownloadItem) {
IndexItem indexItem = ((SrtmDownloadItem) item).getIndexItem();
cancelDownload(indexItem);
} else if (item instanceof IndexItem) { } else if (item instanceof IndexItem) {
IndexItem indexItem = (IndexItem) item; IndexItem indexItem = (IndexItem) item;
cancelDownload(indexItem); cancelDownload(indexItem);

View file

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

View file

@ -1,5 +1,26 @@
package net.osmand.plus.download; package net.osmand.plus.download;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
import android.provider.Settings.Secure;
import net.osmand.AndroidUtils;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.osm.io.NetworkUtils;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -11,26 +32,6 @@ import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import net.osmand.AndroidUtils;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.osm.io.NetworkUtils;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.settings.backend.OsmandSettings;
import org.apache.commons.logging.Log;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
import android.provider.Settings.Secure;
public class DownloadOsmandIndexesHelper { public class DownloadOsmandIndexesHelper {
private final static Log log = PlatformUtil.getLog(DownloadOsmandIndexesHelper.class); private final static Log log = PlatformUtil.getLog(DownloadOsmandIndexesHelper.class);

View file

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

View file

@ -1,6 +1,9 @@
package net.osmand.plus.download; package net.osmand.plus.download;
import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.osmand.IndexConstants; import net.osmand.IndexConstants;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
@ -19,6 +22,7 @@ import java.util.Date;
import java.util.List; import java.util.List;
public class IndexItem extends DownloadItem implements Comparable<IndexItem> { public class IndexItem extends DownloadItem implements Comparable<IndexItem> {
private static final Log log = PlatformUtil.getLog(IndexItem.class); private static final Log log = PlatformUtil.getLog(IndexItem.class);
String description; String description;
@ -226,6 +230,12 @@ public class IndexItem extends DownloadItem implements Comparable<IndexItem> {
return format.format(new Date(timestamp)); return format.format(new Date(timestamp));
} }
@Nullable
@Override
public String getAdditionalDescription(Context ctx) {
return null;
}
public static class DownloadEntry { public static class DownloadEntry {
public long dateModified; public long dateModified;
public double sizeMB; public double sizeMB;
@ -254,5 +264,4 @@ public class IndexItem extends DownloadItem implements Comparable<IndexItem> {
} }
} }
} }

View file

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

View file

@ -1,113 +0,0 @@
package net.osmand.plus.download;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import net.osmand.map.OsmandRegions;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.base.SelectMultipleItemsBottomSheet;
import net.osmand.plus.base.SelectMultipleItemsBottomSheet.OnApplySelectionListener;
import net.osmand.plus.base.SelectMultipleItemsBottomSheet.SelectableItem;
import net.osmand.plus.base.SelectMultipleItemsBottomSheet.SelectionUpdateListener;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.List;
public class MultipleIndexesUiHelper {
public static void showDialog(@NonNull MultipleIndexItem multipleIndexItem,
@NonNull AppCompatActivity activity,
@NonNull final OsmandApplication app,
@NonNull DateFormat dateFormat,
boolean showRemoteDate,
@NonNull final SelectItemsToDownloadListener listener) {
List<IndexItem> indexesToDownload = getIndexesToDownload(multipleIndexItem);
List<SelectableItem> allItems = new ArrayList<>();
List<SelectableItem> selectedItems = new ArrayList<>();
OsmandRegions osmandRegions = app.getRegions();
for (IndexItem indexItem : multipleIndexItem.getAllIndexes()) {
SelectableItem selectableItem = new SelectableItem();
selectableItem.setTitle(indexItem.getVisibleName(app, osmandRegions, false));
String size = indexItem.getSizeDescription(app);
String date = indexItem.getDate(dateFormat, showRemoteDate);
String description = app.getString(R.string.ltr_or_rtl_combine_via_bold_point, size, date);
selectableItem.setDescription(description);
selectableItem.setIconId(indexItem.getType().getIconResource());
selectableItem.setObject(indexItem);
allItems.add(selectableItem);
if (indexesToDownload.contains(indexItem)) {
selectedItems.add(selectableItem);
}
}
final SelectMultipleItemsBottomSheet dialog =
SelectMultipleItemsBottomSheet.showInstance(activity, allItems, selectedItems, true);
dialog.setSelectionUpdateListener(new SelectionUpdateListener() {
@Override
public void onSelectionUpdate() {
dialog.setTitle(app.getString(R.string.welmode_download_maps));
String total = app.getString(R.string.shared_string_total);
double sizeToDownload = getDownloadSizeInMb(dialog.getSelectedItems());
String size = DownloadItem.getFormattedMb(app, sizeToDownload);
String description =
app.getString(R.string.ltr_or_rtl_combine_via_colon, total, size);
dialog.setDescription(description);
String btnTitle = app.getString(R.string.shared_string_download);
if (sizeToDownload > 0) {
btnTitle = app.getString(R.string.ltr_or_rtl_combine_via_dash, btnTitle, size);
}
dialog.setConfirmButtonTitle(btnTitle);
}
});
dialog.setOnApplySelectionListener(new OnApplySelectionListener() {
@Override
public void onSelectionApplied(List<SelectableItem> selectedItems) {
List<IndexItem> indexItems = new ArrayList<>();
for (SelectableItem item : selectedItems) {
Object obj = item.getObject();
if (obj instanceof IndexItem) {
indexItems.add((IndexItem) obj);
}
}
listener.onItemsToDownloadSelected(indexItems);
}
});
}
private static List<IndexItem> getIndexesToDownload(MultipleIndexItem multipleIndexItem) {
if (multipleIndexItem.hasActualDataToDownload()) {
// download left regions
return multipleIndexItem.getIndexesToDownload();
} else {
// download all regions again
return multipleIndexItem.getAllIndexes();
}
}
private static double getDownloadSizeInMb(@NonNull List<SelectableItem> selectableItems) {
List<IndexItem> indexItems = new ArrayList<>();
for (SelectableItem i : selectableItems) {
Object obj = i.getObject();
if (obj instanceof IndexItem) {
indexItems.add((IndexItem) obj);
}
}
double totalSizeMb = 0.0d;
for (IndexItem item : indexItems) {
totalSizeMb += item.getSizeToDownloadInMb();
}
return totalSizeMb;
}
public interface SelectItemsToDownloadListener {
void onItemsToDownloadSelected(List<IndexItem> items);
}
}

View file

@ -0,0 +1,281 @@
package net.osmand.plus.download;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.base.MultipleSelectionBottomSheet;
import net.osmand.plus.base.MultipleSelectionBottomSheet.SelectionUpdateListener;
import net.osmand.plus.base.ModeSelectionBottomSheet;
import net.osmand.plus.base.MultipleSelectionWithModeBottomSheet;
import net.osmand.plus.base.SelectionBottomSheet;
import net.osmand.plus.base.SelectionBottomSheet.OnApplySelectionListener;
import net.osmand.plus.base.SelectionBottomSheet.OnUiInitializedAdapter;
import net.osmand.plus.base.SelectionBottomSheet.SelectableItem;
import net.osmand.plus.widgets.multistatetoggle.RadioItem;
import net.osmand.plus.widgets.multistatetoggle.RadioItem.OnRadioItemClickListener;
import net.osmand.plus.widgets.multistatetoggle.TextToggleButton.TextRadioItem;
import net.osmand.util.Algorithms;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.List;
import static net.osmand.plus.download.MultipleDownloadItem.getIndexItem;
public class SelectIndexesUiHelper {
private final OsmandApplication app;
private final AppCompatActivity activity;
private final ItemsToDownloadSelectedListener listener;
private final DateFormat dateFormat;
private final boolean showRemoteDate;
private final DownloadItem downloadItem;
private SelectionBottomSheet dialog;
private SelectIndexesUiHelper(@NonNull DownloadItem downloadItem,
@NonNull AppCompatActivity activity,
@NonNull DateFormat dateFormat,
boolean showRemoteDate,
@NonNull ItemsToDownloadSelectedListener listener) {
this.app = (OsmandApplication) activity.getApplicationContext();
this.activity = activity;
this.downloadItem = downloadItem;
this.dateFormat = dateFormat;
this.showRemoteDate = showRemoteDate;
this.listener = listener;
}
public static void showDialog(@NonNull DownloadItem i,
@NonNull AppCompatActivity a,
@NonNull DateFormat df,
boolean showRemoteDate,
@NonNull ItemsToDownloadSelectedListener l) {
new SelectIndexesUiHelper(i, a, df, showRemoteDate, l).showDialogInternal();
}
private void showDialogInternal() {
if (downloadItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE) {
if (downloadItem instanceof MultipleDownloadItem) {
showSrtmMultipleSelectionDialog();
} else {
showSrtmModeSelectionDialog();
}
} else if (downloadItem instanceof MultipleDownloadItem) {
showMultipleSelectionDialog();
}
}
private void showMultipleSelectionDialog() {
List<SelectableItem> allItems = new ArrayList<>();
List<SelectableItem> selectedItems = new ArrayList<>();
prepareItems(allItems, selectedItems);
MultipleSelectionBottomSheet msDialog = MultipleSelectionBottomSheet.showInstance(
activity, allItems, selectedItems, true);
this.dialog = msDialog;
msDialog.setOnUiInitializedAdapter(new OnUiInitializedAdapter() {
@Override
public void onUiInitialized() {
dialog.setTitle(app.getString(R.string.welmode_download_maps));
}
});
msDialog.setSelectionUpdateListener(new SelectionUpdateListener() {
@Override
public void onSelectionUpdate() {
updateSize();
}
});
msDialog.setOnApplySelectionListener(getOnApplySelectionListener(listener));
}
private void showSrtmMultipleSelectionDialog() {
List<SelectableItem> allItems = new ArrayList<>();
List<SelectableItem> selectedItems = new ArrayList<>();
prepareItems(allItems, selectedItems);
SrtmDownloadItem srtmItem = (SrtmDownloadItem) ((MultipleDownloadItem)downloadItem).getAllItems().get(0);
final int selectedModeOrder = srtmItem.isUseMetric() ? 0 : 1;
final List<RadioItem> radioItems = createSrtmRadioItems();
MultipleSelectionBottomSheet msDialog = MultipleSelectionWithModeBottomSheet.showInstance(
activity, allItems, selectedItems, radioItems, true);
this.dialog = msDialog;
msDialog.setOnUiInitializedAdapter(new OnUiInitializedAdapter() {
@Override
public void onUiInitialized() {
dialog.setTitle(app.getString(R.string.welmode_download_maps));
dialog.setSelectedMode(radioItems.get(selectedModeOrder));
dialog.setSecondaryDescription(app.getString(R.string.srtm_download_list_help_message));
}
});
msDialog.setSelectionUpdateListener(new SelectionUpdateListener() {
@Override
public void onSelectionUpdate() {
updateSize();
}
});
msDialog.setOnApplySelectionListener(getOnApplySelectionListener(listener));
}
private void showSrtmModeSelectionDialog() {
SrtmDownloadItem srtmItem = (SrtmDownloadItem) downloadItem;
final int selectedModeOrder = srtmItem.isUseMetric() ? 0 : 1;
final List<RadioItem> radioItems = createSrtmRadioItems();
SelectableItem preview = createSelectableItem(srtmItem);
dialog = ModeSelectionBottomSheet.showInstance(activity, preview, radioItems, true);
dialog.setOnUiInitializedAdapter(new OnUiInitializedAdapter() {
@Override
public void onUiInitialized() {
ModeSelectionBottomSheet dialog = (ModeSelectionBottomSheet) SelectIndexesUiHelper.this.dialog;
dialog.setTitle(app.getString(R.string.srtm_unit_format));
dialog.setPrimaryDescription(app.getString(R.string.srtm_download_single_help_message));
updateSize();
dialog.setSelectedMode(radioItems.get(selectedModeOrder));
}
});
dialog.setOnApplySelectionListener(getOnApplySelectionListener(listener));
}
private void prepareItems(List<SelectableItem> allItems,
List<SelectableItem> selectedItems) {
final MultipleDownloadItem multipleDownloadItem = (MultipleDownloadItem) downloadItem;
final List<DownloadItem> itemsToDownload = getItemsToDownload(multipleDownloadItem);
for (DownloadItem downloadItem : multipleDownloadItem.getAllItems()) {
SelectableItem selectableItem = createSelectableItem(downloadItem);
allItems.add(selectableItem);
if (itemsToDownload.contains(downloadItem)) {
selectedItems.add(selectableItem);
}
}
}
private List<RadioItem> createSrtmRadioItems() {
List<RadioItem> radioItems = new ArrayList<>();
radioItems.add(createSrtmRadioBtn(R.string.shared_string_meters, true));
radioItems.add(createSrtmRadioBtn(R.string.shared_string_feet, false));
return radioItems;
}
private RadioItem createSrtmRadioBtn(int titleId,
final boolean useMeters) {
String title = Algorithms.capitalizeFirstLetter(app.getString(titleId));
RadioItem radioItem = new TextRadioItem(title);
radioItem.setOnClickListener(new OnRadioItemClickListener() {
@Override
public boolean onRadioItemClick(RadioItem radioItem, View view) {
updateDialogListItems(useMeters);
updateSize();
return true;
}
});
return radioItem;
}
private void updateDialogListItems(boolean useMeters) {
List<SelectableItem> items = new ArrayList<>(dialog.getAllItems());
for (SelectableItem item : items) {
DownloadItem downloadItem = (DownloadItem) item.getObject();
if (downloadItem instanceof SrtmDownloadItem) {
((SrtmDownloadItem) downloadItem).setUseMetric(useMeters);
updateSelectableItem(item, downloadItem);
}
}
dialog.setItems(items);
}
private SelectableItem createSelectableItem(DownloadItem item) {
SelectableItem selectableItem = new SelectableItem();
updateSelectableItem(selectableItem, item);
return selectableItem;
}
private void updateSelectableItem(SelectableItem selectableItem,
DownloadItem downloadItem) {
selectableItem.setTitle(downloadItem.getVisibleName(app, app.getRegions(), false));
String size = downloadItem.getSizeDescription(app);
String addDescr = downloadItem.getAdditionalDescription(app);
if (addDescr != null) {
size += " " + addDescr;
}
String date = downloadItem.getDate(dateFormat, showRemoteDate);
String description = app.getString(R.string.ltr_or_rtl_combine_via_bold_point, size, date);
selectableItem.setDescription(description);
selectableItem.setIconId(downloadItem.getType().getIconResource());
selectableItem.setObject(downloadItem);
}
private OnApplySelectionListener getOnApplySelectionListener(final ItemsToDownloadSelectedListener listener) {
return new OnApplySelectionListener() {
@Override
public void onSelectionApplied(List<SelectableItem> selectedItems) {
List<IndexItem> indexes = new ArrayList<>();
for (SelectableItem item : selectedItems) {
IndexItem index = getIndexItem((DownloadItem) item.getObject());
if (index != null) {
indexes.add(index);
}
}
listener.onItemsToDownloadSelected(indexes);
}
};
}
private void updateSize() {
double sizeToDownload = getDownloadSizeInMb(dialog.getSelectedItems());
String size = DownloadItem.getFormattedMb(app, sizeToDownload);
String total = app.getString(R.string.shared_string_total);
String description = app.getString(R.string.ltr_or_rtl_combine_via_colon, total, size);
dialog.setTitleDescription(description);
String btnTitle = app.getString(R.string.shared_string_download);
if (sizeToDownload > 0) {
btnTitle = app.getString(R.string.ltr_or_rtl_combine_via_dash, btnTitle, size);
}
dialog.setApplyButtonTitle(btnTitle);
}
private double getDownloadSizeInMb(@NonNull List<SelectableItem> selectableItems) {
double totalSizeMb = 0.0d;
for (SelectableItem i : selectableItems) {
Object obj = i.getObject();
if (obj instanceof DownloadItem) {
totalSizeMb += ((DownloadItem) obj).getSizeToDownloadInMb();
}
}
return totalSizeMb;
}
private static List<DownloadItem> getItemsToDownload(MultipleDownloadItem md) {
if (md.hasActualDataToDownload()) {
// download left regions
return md.getItemsToDownload();
} else {
// download all regions again
return md.getAllItems();
}
}
public interface ItemsToDownloadSelectedListener {
void onItemsToDownloadSelected(List<IndexItem> items);
}
}

View file

@ -0,0 +1,191 @@
package net.osmand.plus.download;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.osmand.IndexConstants;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.activities.LocalIndexInfo;
import net.osmand.plus.helpers.enums.MetricsConstants;
import net.osmand.util.Algorithms;
import java.io.File;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.List;
import static net.osmand.IndexConstants.BINARY_SRTM_MAP_INDEX_EXT;
import static net.osmand.IndexConstants.BINARY_SRTM_MAP_INDEX_EXT_ZIP;
import static net.osmand.plus.activities.LocalIndexHelper.LocalIndexType.SRTM_DATA;
import static net.osmand.plus.download.DownloadActivityType.SRTM_COUNTRY_FILE;
public class SrtmDownloadItem extends DownloadItem {
private final List<IndexItem> indexes;
private boolean useMetric;
public SrtmDownloadItem(List<IndexItem> indexes, boolean useMetric) {
super(SRTM_COUNTRY_FILE);
this.indexes = indexes;
this.useMetric = useMetric;
}
public void setUseMetric(boolean useMetric) {
this.useMetric = useMetric;
}
public boolean isUseMetric() {
for (IndexItem index : indexes) {
if (index.isDownloaded()) {
return isMetricItem(index);
}
}
return useMetric;
}
@NonNull
public IndexItem getIndexItem() {
for (IndexItem index : indexes) {
if (index.isDownloaded()) {
return index;
}
}
for (IndexItem index : indexes) {
if (useMetric && isMetricItem(index) || !useMetric && !isMetricItem(index)) {
return index;
}
}
return indexes.get(0);
}
@Override
protected double getSizeToDownloadInMb() {
return getIndexItem().getSizeToDownloadInMb();
}
@Override
public double getArchiveSizeMB() {
return getIndexItem().getArchiveSizeMB();
}
@Override
public boolean isOutdated() {
for (DownloadItem item : indexes) {
if (item.isOutdated()) {
return true;
}
}
return false;
}
@Override
public boolean isDownloaded() {
for (DownloadItem item : indexes) {
if (item.isDownloaded()) {
return true;
}
}
return false;
}
@Override
public boolean hasActualDataToDownload() {
for (IndexItem item : indexes) {
if (!item.hasActualDataToDownload()) {
return false;
}
}
return true;
}
@Override
public boolean isDownloading(@NonNull DownloadIndexesThread thread) {
for (IndexItem item : indexes) {
if (thread.isDownloading(item)) {
return true;
}
}
return false;
}
@Override
public String getFileName() {
return getIndexItem().getFileName();
}
@NonNull
@Override
public List<File> getDownloadedFiles(@NonNull OsmandApplication app) {
List<File> result = new ArrayList<>();
for (IndexItem index : indexes) {
result.addAll(index.getDownloadedFiles(app));
}
return result;
}
public String getDate(@NonNull DateFormat dateFormat, boolean remote) {
return getIndexItem().getDate(dateFormat, remote);
}
@Override
public @Nullable String getAdditionalDescription(Context ctx) {
return getAbbreviationInScopes(ctx, this);
}
public static boolean shouldUseMetersByDefault(@NonNull OsmandApplication app) {
MetricsConstants metricSystem = app.getSettings().METRIC_SYSTEM.get();
return metricSystem != MetricsConstants.MILES_AND_FEET;
}
@NonNull
public static String getAbbreviationInScopes(Context ctx, Object obj) {
String abbreviation = ctx.getString(isMetricItem(obj) ? R.string.m : R.string.foot);
return "(" + abbreviation + ")";
}
public static boolean containsSrtmExtension(@NonNull String fileName) {
return fileName.contains(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)
|| fileName.contains(IndexConstants.BINARY_SRTM_FEET_MAP_INDEX_EXT);
}
public static boolean isSrtmFile(@NonNull String fileName) {
return fileName.endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)
|| fileName.endsWith(IndexConstants.BINARY_SRTM_FEET_MAP_INDEX_EXT);
}
@NonNull
public static String getExtension(IndexItem indexItem) {
return isMetricItem(indexItem) ?
IndexConstants.BINARY_SRTM_MAP_INDEX_EXT :
IndexConstants.BINARY_SRTM_FEET_MAP_INDEX_EXT;
}
public static boolean isSRTMItem(Object item) {
if (item instanceof DownloadItem) {
return ((DownloadItem) item).getType() == SRTM_COUNTRY_FILE;
} else if (item instanceof LocalIndexInfo) {
return ((LocalIndexInfo) item).getType() == SRTM_DATA;
}
return false;
}
private static boolean isMetricItem(Object item) {
if (item instanceof IndexItem) {
return ((IndexItem) item).getFileName().endsWith(BINARY_SRTM_MAP_INDEX_EXT_ZIP);
} else if (item instanceof LocalIndexInfo) {
return ((LocalIndexInfo) item).getFileName().endsWith(BINARY_SRTM_MAP_INDEX_EXT);
} else if (item instanceof SrtmDownloadItem) {
return isMetricItem(((SrtmDownloadItem) item).getIndexItem());
} else if (item instanceof MultipleDownloadItem) {
List<DownloadItem> items = ((MultipleDownloadItem) item).getAllItems();
if (!Algorithms.isEmpty(items)) {
return isMetricItem(items.get(0));
}
}
return false;
}
}

View file

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

View file

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

View file

@ -41,9 +41,9 @@ import net.osmand.plus.download.DownloadActivityType;
import net.osmand.plus.download.DownloadResourceGroup; import net.osmand.plus.download.DownloadResourceGroup;
import net.osmand.plus.download.DownloadResources; import net.osmand.plus.download.DownloadResources;
import net.osmand.plus.download.IndexItem; import net.osmand.plus.download.IndexItem;
import net.osmand.plus.download.MultipleIndexesUiHelper; import net.osmand.plus.download.SelectIndexesUiHelper;
import net.osmand.plus.download.MultipleIndexesUiHelper.SelectItemsToDownloadListener; import net.osmand.plus.download.SelectIndexesUiHelper.ItemsToDownloadSelectedListener;
import net.osmand.plus.download.MultipleIndexItem; import net.osmand.plus.download.MultipleDownloadItem;
import net.osmand.plus.download.ui.LocalIndexesFragment.LocalIndexOperationTask; import net.osmand.plus.download.ui.LocalIndexesFragment.LocalIndexOperationTask;
import net.osmand.plus.helpers.FileNameTranslationHelper; import net.osmand.plus.helpers.FileNameTranslationHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper; import net.osmand.plus.inapp.InAppPurchaseHelper;
@ -146,11 +146,11 @@ public class ItemViewHolder {
depthContoursPurchased = InAppPurchaseHelper.isDepthContoursPurchased(context.getMyApplication()); depthContoursPurchased = InAppPurchaseHelper.isDepthContoursPurchased(context.getMyApplication());
} }
public void bindIndexItem(final DownloadItem downloadItem) { public void bindDownloadItem(final DownloadItem downloadItem) {
bindIndexItem(downloadItem, null); bindDownloadItem(downloadItem, null);
} }
public void bindIndexItem(final DownloadItem downloadItem, final String cityName) { public void bindDownloadItem(final DownloadItem downloadItem, final String cityName) {
initAppStatusVariables(); initAppStatusVariables();
boolean isDownloading = downloadItem.isDownloading(context.getDownloadThread()); boolean isDownloading = downloadItem.isDownloading(context.getDownloadThread());
int progress = -1; int progress = -1;
@ -203,12 +203,12 @@ public class ItemViewHolder {
} else { } else {
descrTextView.setText(downloadItem.getType().getString(context)); descrTextView.setText(downloadItem.getType().getString(context));
} }
} else if (downloadItem instanceof MultipleIndexItem) { } else if (downloadItem instanceof MultipleDownloadItem) {
MultipleIndexItem item = (MultipleIndexItem) downloadItem; MultipleDownloadItem item = (MultipleDownloadItem) downloadItem;
String allRegionsHeader = context.getString(R.string.shared_strings_all_regions); String allRegionsHeader = context.getString(R.string.shared_strings_all_regions);
String regionsHeader = context.getString(R.string.regions); String regionsHeader = context.getString(R.string.regions);
String allRegionsCount = String.valueOf(item.getAllIndexes().size()); String allRegionsCount = String.valueOf(item.getAllItems().size());
String leftToDownloadCount = String.valueOf(item.getIndexesToDownload().size()); String leftToDownloadCount = String.valueOf(item.getItemsToDownload().size());
String header; String header;
String count; String count;
if (item.hasActualDataToDownload()) { if (item.hasActualDataToDownload()) {
@ -226,8 +226,11 @@ public class ItemViewHolder {
header = allRegionsHeader; header = allRegionsHeader;
count = allRegionsCount; count = allRegionsCount;
} }
String fullDescription = String fullDescription = context.getString(R.string.ltr_or_rtl_combine_via_colon, header, count);
context.getString(R.string.ltr_or_rtl_combine_via_colon, header, count); String addDescr = item.getAdditionalDescription(context);
if (addDescr != null) {
fullDescription += " " + addDescr;
}
if (item.hasActualDataToDownload()) { if (item.hasActualDataToDownload()) {
fullDescription = context.getString( fullDescription = context.getString(
R.string.ltr_or_rtl_combine_via_bold_point, fullDescription, R.string.ltr_or_rtl_combine_via_bold_point, fullDescription,
@ -235,11 +238,14 @@ public class ItemViewHolder {
} }
descrTextView.setText(fullDescription); descrTextView.setText(fullDescription);
} else { } else {
IndexItem item = (IndexItem) downloadItem;
String pattern = context.getString(R.string.ltr_or_rtl_combine_via_bold_point); String pattern = context.getString(R.string.ltr_or_rtl_combine_via_bold_point);
String type = item.getType().getString(context); String type = downloadItem.getType().getString(context);
String size = item.getSizeDescription(context); String size = downloadItem.getSizeDescription(context);
String date = item.getDate(dateFormat, showRemoteDate); String addDescr = downloadItem.getAdditionalDescription(context);
if (addDescr != null) {
size += " " + addDescr;
}
String date = downloadItem.getDate(dateFormat, showRemoteDate);
String fullDescription = String.format(pattern, size, date); String fullDescription = String.format(pattern, size, date);
if (showTypeInDesc) { if (showTypeInDesc) {
fullDescription = String.format(pattern, type, fullDescription); fullDescription = String.format(pattern, type, fullDescription);
@ -274,9 +280,9 @@ public class ItemViewHolder {
} }
} }
public void bindIndexItem(final CityItem cityItem) { public void bindDownloadItem(final CityItem cityItem) {
if (cityItem.getIndexItem() != null) { if (cityItem.getIndexItem() != null) {
bindIndexItem(cityItem.getIndexItem(), cityItem.getName()); bindDownloadItem(cityItem.getIndexItem(), cityItem.getName());
} else { } else {
nameTextView.setText(cityItem.getName()); nameTextView.setText(cityItem.getName());
nameTextView.setTextColor(textColorPrimary); nameTextView.setTextColor(textColorPrimary);
@ -316,9 +322,9 @@ public class ItemViewHolder {
} }
private int getDownloadActionIconId(@NonNull DownloadItem item) { private int getDownloadActionIconId(@NonNull DownloadItem item) {
return item instanceof MultipleIndexItem ? return item instanceof MultipleDownloadItem ?
R.drawable.ic_action_multi_download : R.drawable.ic_action_multi_download :
R.drawable.ic_action_import; R.drawable.ic_action_gsave_dark;
} }
@SuppressLint("DefaultLocale") @SuppressLint("DefaultLocale")
@ -459,6 +465,7 @@ public class ItemViewHolder {
startDownload(item); startDownload(item);
} }
} }
private void confirmDownload(final DownloadItem item) { private void confirmDownload(final DownloadItem item) {
AlertDialog.Builder builder = new AlertDialog.Builder(context); AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.are_you_sure); builder.setTitle(R.string.are_you_sure);
@ -476,18 +483,17 @@ public class ItemViewHolder {
} }
private void startDownload(DownloadItem item) { private void startDownload(DownloadItem item) {
if (item instanceof MultipleIndexItem) { if (item instanceof IndexItem) {
selectIndexesToDownload((MultipleIndexItem) item);
} else if (item instanceof IndexItem) {
IndexItem indexItem = (IndexItem) item; IndexItem indexItem = (IndexItem) item;
context.startDownload(indexItem); context.startDownload(indexItem);
} else {
selectIndexesToDownload(item);
} }
} }
private void selectIndexesToDownload(MultipleIndexItem item) { private void selectIndexesToDownload(DownloadItem item) {
OsmandApplication app = context.getMyApplication(); SelectIndexesUiHelper.showDialog(item, context, dateFormat, showRemoteDate,
MultipleIndexesUiHelper.showDialog(item, context, app, dateFormat, showRemoteDate, new ItemsToDownloadSelectedListener() {
new SelectItemsToDownloadListener() {
@Override @Override
public void onItemsToDownloadSelected(List<IndexItem> indexes) { public void onItemsToDownloadSelected(List<IndexItem> indexes) {
IndexItem[] indexesArray = new IndexItem[indexes.size()]; IndexItem[] indexesArray = new IndexItem[indexes.size()];

View file

@ -55,6 +55,7 @@ import net.osmand.plus.dialogs.DirectionsDialogs;
import net.osmand.plus.download.DownloadActivity; import net.osmand.plus.download.DownloadActivity;
import net.osmand.plus.download.DownloadIndexesThread.DownloadEvents; import net.osmand.plus.download.DownloadIndexesThread.DownloadEvents;
import net.osmand.plus.download.IndexItem; import net.osmand.plus.download.IndexItem;
import net.osmand.plus.download.SrtmDownloadItem;
import net.osmand.plus.helpers.FileNameTranslationHelper; import net.osmand.plus.helpers.FileNameTranslationHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper; import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.mapsource.EditMapSourceDialogFragment.OnMapSourceUpdateListener; import net.osmand.plus.mapsource.EditMapSourceDialogFragment.OnMapSourceUpdateListener;
@ -74,6 +75,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
public class LocalIndexesFragment extends OsmandExpandableListFragment implements DownloadEvents, public class LocalIndexesFragment extends OsmandExpandableListFragment implements DownloadEvents,
OnMapSourceUpdateListener, RenameCallback { OnMapSourceUpdateListener, RenameCallback {
private LoadLocalIndexTask asyncLoader; private LoadLocalIndexTask asyncLoader;
@ -963,7 +965,7 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
return ctx.getString(R.string.download_roads_only_item); return ctx.getString(R.string.download_roads_only_item);
} else if (child.isBackupedData() && child.getFileName().endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) { } else if (child.isBackupedData() && child.getFileName().endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) {
return ctx.getString(R.string.download_wikipedia_maps); return ctx.getString(R.string.download_wikipedia_maps);
} else if (child.isBackupedData() && child.getFileName().endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)) { } else if (child.isBackupedData() && (SrtmDownloadItem.isSrtmFile(child.getFileName()))) {
return ctx.getString(R.string.download_srtm_maps); return ctx.getString(R.string.download_srtm_maps);
} }
return ""; return "";
@ -1029,6 +1031,10 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
builder.append(AndroidUtils.formatSize(ctx, child.getSize() * 1024l)); builder.append(AndroidUtils.formatSize(ctx, child.getSize() * 1024l));
} }
if (SrtmDownloadItem.isSRTMItem(child)) {
builder.append(" ").append(SrtmDownloadItem.getAbbreviationInScopes(ctx, child));
}
if (!Algorithms.isEmpty(child.getDescription())) { if (!Algorithms.isEmpty(child.getDescription())) {
if (builder.length() > 0) { if (builder.length() > 0) {
builder.append(""); builder.append("");
@ -1150,5 +1156,4 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
private DownloadActivity getDownloadActivity() { private DownloadActivity getDownloadActivity() {
return (DownloadActivity) getActivity(); return (DownloadActivity) getActivity();
} }
} }

View file

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

View file

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

View file

@ -1,9 +1,11 @@
package net.osmand.plus.helpers; package net.osmand.plus.helpers;
import android.content.Context; import android.content.Context;
import net.osmand.IndexConstants; import net.osmand.IndexConstants;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
import net.osmand.map.OsmandRegions; import net.osmand.map.OsmandRegions;
import net.osmand.map.WorldRegion;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.download.DownloadResources; import net.osmand.plus.download.DownloadResources;
@ -19,6 +21,7 @@ import java.lang.reflect.Field;
public class FileNameTranslationHelper { public class FileNameTranslationHelper {
private static final Log LOG = PlatformUtil.getLog(FileNameTranslationHelper.class); private static final Log LOG = PlatformUtil.getLog(FileNameTranslationHelper.class);
public static final String WIKI_NAME = "_wiki"; public static final String WIKI_NAME = "_wiki";
public static final String WIKIVOYAGE_NAME = "_wikivoyage";
public static final String HILL_SHADE = "Hillshade"; public static final String HILL_SHADE = "Hillshade";
public static final String SLOPE = "Slope"; public static final String SLOPE = "Slope";
public static final String SEA_DEPTH = "Depth_"; public static final String SEA_DEPTH = "Depth_";
@ -31,6 +34,8 @@ public class FileNameTranslationHelper {
String basename = getBasename(fileName); String basename = getBasename(fileName);
if (basename.endsWith(WIKI_NAME)) { //wiki files if (basename.endsWith(WIKI_NAME)) { //wiki files
return getWikiName(ctx, basename); return getWikiName(ctx, basename);
} else if (basename.endsWith(WIKIVOYAGE_NAME)) {
return getWikivoyageName(ctx, basename);
} else if (fileName.endsWith("tts")) { //tts files } else if (fileName.endsWith("tts")) { //tts files
return getVoiceName(ctx, fileName); return getVoiceName(ctx, fileName);
} else if (fileName.endsWith(IndexConstants.FONT_INDEX_EXT)) { //otf files } else if (fileName.endsWith(IndexConstants.FONT_INDEX_EXT)) { //otf files
@ -90,6 +95,17 @@ public class FileNameTranslationHelper {
return wikiName + " " + ctx.getString(R.string.amenity_type_osmwiki); return wikiName + " " + ctx.getString(R.string.amenity_type_osmwiki);
} }
public static String getWikivoyageName(Context ctx, String basename) {
String formattedName = basename.substring(0, basename.indexOf(WIKIVOYAGE_NAME)).replaceAll("-", "").replaceAll("all", "");
String wikiVoyageName = getSuggestedWikivoyageMaps(ctx, formattedName);
if (wikiVoyageName == null) {
wikiVoyageName = formattedName;
}
String wikiVoyageWord = ctx.getString(R.string.shared_string_wikivoyage);
return ctx.getString(R.string.ltr_or_rtl_combine_via_space, wikiVoyageName, wikiVoyageWord);
}
public static String getVoiceName(Context ctx, String fileName) { public static String getVoiceName(Context ctx, String fileName) {
try { try {
String nm = fileName.replace('-', '_').replace(' ', '_'); String nm = fileName.replace('-', '_').replace(' ', '_');
@ -245,4 +261,27 @@ public class FileNameTranslationHelper {
} }
return null; return null;
} }
private static String getSuggestedWikivoyageMaps(Context ctx, String filename) {
if (WorldRegion.AFRICA_REGION_ID.equalsIgnoreCase(filename)) {
return ctx.getString(R.string.index_name_africa);
} else if (WorldRegion.AUSTRALIA_AND_OCEANIA_REGION_ID.replaceAll("-", "").equalsIgnoreCase(filename)) {
return ctx.getString(R.string.index_name_oceania);
} else if (WorldRegion.ASIA_REGION_ID.equalsIgnoreCase(filename)) {
return ctx.getString(R.string.index_name_asia);
} else if (WorldRegion.CENTRAL_AMERICA_REGION_ID.equalsIgnoreCase(filename)) {
return ctx.getString(R.string.index_name_central_america);
} else if (WorldRegion.EUROPE_REGION_ID.equalsIgnoreCase(filename)) {
return ctx.getString(R.string.index_name_europe);
} else if (WorldRegion.RUSSIA_REGION_ID.equalsIgnoreCase(filename)) {
return ctx.getString(R.string.index_name_russia);
} else if (WorldRegion.NORTH_AMERICA_REGION_ID.equalsIgnoreCase(filename)) {
return ctx.getString(R.string.index_name_north_america);
} else if (WorldRegion.SOUTH_AMERICA_REGION_ID.equalsIgnoreCase(filename)) {
return ctx.getString(R.string.index_name_south_america);
} else if (WorldRegion.ANTARCTICA_REGION_ID.equalsIgnoreCase(filename)) {
return ctx.getString(R.string.index_name_antarctica);
}
return null;
}
} }

View file

@ -42,9 +42,10 @@ import net.osmand.plus.liveupdates.LiveUpdatesHelper.UpdateFrequency;
import net.osmand.plus.resources.IncrementalChangesManager; import net.osmand.plus.resources.IncrementalChangesManager;
import net.osmand.plus.settings.backend.CommonPreference; import net.osmand.plus.settings.backend.CommonPreference;
import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.widgets.MultiStateToggleButton; import net.osmand.plus.widgets.multistatetoggle.RadioItem;
import net.osmand.plus.widgets.MultiStateToggleButton.OnRadioItemClickListener; import net.osmand.plus.widgets.multistatetoggle.RadioItem.OnRadioItemClickListener;
import net.osmand.plus.widgets.MultiStateToggleButton.RadioItem; import net.osmand.plus.widgets.multistatetoggle.TextToggleButton;
import net.osmand.plus.widgets.multistatetoggle.TextToggleButton.TextRadioItem;
import net.osmand.plus.widgets.TextViewEx; import net.osmand.plus.widgets.TextViewEx;
import net.osmand.plus.widgets.style.CustomTypefaceSpan; import net.osmand.plus.widgets.style.CustomTypefaceSpan;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
@ -83,8 +84,8 @@ public class LiveUpdatesSettingsBottomSheet extends MenuBottomSheetDialogFragmen
private BaseBottomSheetItem itemFrequencyHelpMessage; private BaseBottomSheetItem itemFrequencyHelpMessage;
private BaseBottomSheetItem itemClear; private BaseBottomSheetItem itemClear;
private BaseBottomSheetItem itemViaWiFi; private BaseBottomSheetItem itemViaWiFi;
private MultiStateToggleButton frequencyToggleButton; private TextToggleButton frequencyToggleButton;
private MultiStateToggleButton timeOfDayToggleButton; private TextToggleButton timeOfDayToggleButton;
private String fileName; private String fileName;
private OnLiveUpdatesForLocalChange onLiveUpdatesForLocalChange; private OnLiveUpdatesForLocalChange onLiveUpdatesForLocalChange;
@ -195,9 +196,9 @@ public class LiveUpdatesSettingsBottomSheet extends MenuBottomSheetDialogFragmen
String morning = getString(R.string.morning); String morning = getString(R.string.morning);
String night = getString(R.string.night); String night = getString(R.string.night);
RadioItem morningButton = new RadioItem(morning); TextRadioItem morningButton = new TextRadioItem(morning);
RadioItem nightButton = new RadioItem(night); TextRadioItem nightButton = new TextRadioItem(night);
timeOfDayToggleButton = new MultiStateToggleButton(app, itemTimeOfDayButtons, nightMode); timeOfDayToggleButton = new TextToggleButton(app, itemTimeOfDayButtons, nightMode);
timeOfDayToggleButton.setItems(morningButton, nightButton); timeOfDayToggleButton.setItems(morningButton, nightButton);
setSelectedRadioItem(timeOfDayToggleButton, timeOfDayPreference.get(), morningButton, nightButton); setSelectedRadioItem(timeOfDayToggleButton, timeOfDayPreference.get(), morningButton, nightButton);
timeOfDayToggleButton.updateView(localUpdatePreference.get()); timeOfDayToggleButton.updateView(localUpdatePreference.get());
@ -231,10 +232,10 @@ public class LiveUpdatesSettingsBottomSheet extends MenuBottomSheetDialogFragmen
String hourly = getString(R.string.hourly); String hourly = getString(R.string.hourly);
String daily = getString(R.string.daily); String daily = getString(R.string.daily);
String weekly = getString(R.string.weekly); String weekly = getString(R.string.weekly);
RadioItem hourlyButton = new RadioItem(hourly); TextRadioItem hourlyButton = new TextRadioItem(hourly);
RadioItem dailyButton = new RadioItem(daily); TextRadioItem dailyButton = new TextRadioItem(daily);
RadioItem weeklyButton = new RadioItem(weekly); TextRadioItem weeklyButton = new TextRadioItem(weekly);
frequencyToggleButton = new MultiStateToggleButton(app, itemFrequencyButtons, nightMode); frequencyToggleButton = new TextToggleButton(app, itemFrequencyButtons, nightMode);
frequencyToggleButton.setItems(hourlyButton, dailyButton, weeklyButton); frequencyToggleButton.setItems(hourlyButton, dailyButton, weeklyButton);
setSelectedRadioItem(frequencyToggleButton, frequencyPreference.get(), hourlyButton, dailyButton, weeklyButton); setSelectedRadioItem(frequencyToggleButton, frequencyPreference.get(), hourlyButton, dailyButton, weeklyButton);
frequencyToggleButton.updateView(localUpdatePreference.get()); frequencyToggleButton.updateView(localUpdatePreference.get());
@ -467,7 +468,7 @@ public class LiveUpdatesSettingsBottomSheet extends MenuBottomSheetDialogFragmen
return dividerItem; return dividerItem;
} }
private void setSelectedRadioItem(MultiStateToggleButton toggleButton, int position, RadioItem... buttons) { private void setSelectedRadioItem(TextToggleButton toggleButton, int position, TextRadioItem... buttons) {
toggleButton.setSelectedItem(buttons[position]); toggleButton.setSelectedItem(buttons[position]);
} }

View file

@ -24,6 +24,7 @@ import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.GpxUiHelper; import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.plus.helpers.GpxUiHelper.LineGraphType; import net.osmand.plus.helpers.GpxUiHelper.LineGraphType;
import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter; import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter;
@ -109,9 +110,16 @@ public class GraphsCard extends BaseCard implements OnUpdateInfoListener {
GraphAdapterHelper.bindGraphAdapters(commonGraphAdapter, Collections.singletonList((BaseGraphAdapter) customGraphAdapter), (ViewGroup) view); GraphAdapterHelper.bindGraphAdapters(commonGraphAdapter, Collections.singletonList((BaseGraphAdapter) customGraphAdapter), (ViewGroup) view);
refreshMapCallback = GraphAdapterHelper.bindToMap(commonGraphAdapter, mapActivity, trackDetailsMenu); refreshMapCallback = GraphAdapterHelper.bindToMap(commonGraphAdapter, mapActivity, trackDetailsMenu);
updateTopPadding();
fullUpdate(); fullUpdate();
} }
private void updateTopPadding() {
int topPadding = AndroidUiHelper.isOrientationPortrait(mapActivity) ?
0 : app.getResources().getDimensionPixelSize(R.dimen.content_padding_small);
view.setPadding(0, topPadding, 0, 0);
}
@Override @Override
public int getCardLayoutId() { public int getCardLayoutId() {
return R.layout.measurement_tool_graph_card; return R.layout.measurement_tool_graph_card;

View file

@ -11,6 +11,7 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewGroup.MarginLayoutParams;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
@ -82,9 +83,13 @@ import net.osmand.plus.views.layers.MapControlsLayer.MapControlsThemeInfoProvide
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarController; import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarController;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarControllerType; import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarControllerType;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarView; import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarView;
import net.osmand.plus.widgets.MultiStateToggleButton; import net.osmand.plus.widgets.multistatetoggle.IconToggleButton;
import net.osmand.plus.widgets.MultiStateToggleButton.OnRadioItemClickListener; import net.osmand.plus.widgets.multistatetoggle.IconToggleButton.IconRadioItem;
import net.osmand.plus.widgets.MultiStateToggleButton.RadioItem; import net.osmand.plus.widgets.multistatetoggle.MultiStateToggleButton;
import net.osmand.plus.widgets.multistatetoggle.RadioItem;
import net.osmand.plus.widgets.multistatetoggle.RadioItem.OnRadioItemClickListener;
import net.osmand.plus.widgets.multistatetoggle.TextToggleButton;
import net.osmand.plus.widgets.multistatetoggle.TextToggleButton.TextRadioItem;
import net.osmand.router.RoutePlannerFrontEnd.GpxRouteApproximation; import net.osmand.router.RoutePlannerFrontEnd.GpxRouteApproximation;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
@ -130,6 +135,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
private RadioItem graphBtn; private RadioItem graphBtn;
private View mainView; private View mainView;
private View bottomMapControls; private View bottomMapControls;
private View topMapControls;
private ImageView upDownBtn; private ImageView upDownBtn;
private ImageView undoBtn; private ImageView undoBtn;
private ImageView redoBtn; private ImageView redoBtn;
@ -251,7 +257,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
public void showProgressBar() { public void showProgressBar() {
MeasurementToolFragment.this.showProgressBar(); MeasurementToolFragment.this.showProgressBar();
updateInfoView(); updateInfoView();
updateCardContainerSize(); updateInfoViewAppearance();
} }
@Override @Override
@ -261,10 +267,10 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
@Override @Override
public void hideProgressBar() { public void hideProgressBar() {
((ProgressBar) mainView.findViewById(R.id.snap_to_road_progress_bar)).setVisibility(View.GONE); ((ProgressBar) mainView.findViewById(R.id.snap_to_road_progress_bar)).setVisibility(View.INVISIBLE);
progressBarVisible = false; progressBarVisible = false;
updateInfoView(); updateInfoView();
updateCardContainerSize(); updateInfoViewAppearance();
} }
@Override @Override
@ -287,32 +293,38 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
.inflate(R.layout.fragment_measurement_tool, container, false); .inflate(R.layout.fragment_measurement_tool, container, false);
mainView = view.findViewById(R.id.main_view); mainView = view.findViewById(R.id.main_view);
AndroidUtils.setBackground(mapActivity, mainView, nightMode, R.drawable.bg_bottom_menu_light, R.drawable.bg_bottom_menu_dark);
detailsMenu = new GraphDetailsMenu(); detailsMenu = new GraphDetailsMenu();
LinearLayout infoButtonsContainer = mainView.findViewById(R.id.custom_radio_buttons);
if (portrait) { if (portrait) {
cardsContainer = mainView.findViewById(R.id.cards_container); cardsContainer = mainView.findViewById(R.id.cards_container);
infoTypeBtn = new TextToggleButton(app, infoButtonsContainer, nightMode);
String pointsBtnTitle = getString(R.string.shared_string_gpx_points); String pointsBtnTitle = getString(R.string.shared_string_gpx_points);
pointsBtn = new RadioItem(pointsBtnTitle); pointsBtn = new TextRadioItem(pointsBtnTitle);
pointsBtn.setOnClickListener(getInfoTypeBtnListener(InfoType.POINTS));
String graphBtnTitle = getString(R.string.shared_string_graph); String graphBtnTitle = getString(R.string.shared_string_graph);
graphBtn = new RadioItem(graphBtnTitle); graphBtn = new TextRadioItem(graphBtnTitle);
graphBtn.setOnClickListener(getInfoTypeBtnListener(InfoType.GRAPH));
LinearLayout infoButtonsContainer = mainView.findViewById(R.id.custom_radio_buttons);
infoTypeBtn = new MultiStateToggleButton(app, infoButtonsContainer, nightMode);
infoTypeBtn.setItems(pointsBtn, graphBtn);
} else { } else {
cardsContainer = mapActivity.findViewById(R.id.left_side_menu); cardsContainer = mapActivity.findViewById(R.id.left_side_menu);
bottomMapControls = mapActivity.findViewById(R.id.bottom_controls_container); bottomMapControls = mapActivity.findViewById(R.id.bottom_controls_container);
topMapControls = mapActivity.findViewById(R.id.top_controls_container);
infoTypeBtn = new IconToggleButton(app, infoButtonsContainer, nightMode);
pointsBtn = new IconRadioItem(R.drawable.ic_action_plan_route_point_colored, true);
graphBtn = new IconRadioItem(R.drawable.ic_action_analyze_intervals);
ScrollUtils.addOnGlobalLayoutListener(mainView, new Runnable() { ScrollUtils.addOnGlobalLayoutListener(mainView, new Runnable() {
@Override @Override
public void run() { public void run() {
updateCardContainerSize(); updateInfoViewAppearance();
} }
}); });
} }
pointsBtn.setOnClickListener(getInfoTypeBtnListener(InfoType.POINTS));
graphBtn.setOnClickListener(getInfoTypeBtnListener(InfoType.GRAPH));
infoTypeBtn.setItems(pointsBtn, graphBtn);
pointsCard = new PointsCard(mapActivity, this); pointsCard = new PointsCard(mapActivity, this);
graphsCard = new GraphsCard(mapActivity, detailsMenu, this); graphsCard = new GraphsCard(mapActivity, detailsMenu, this);
@ -348,7 +360,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
public void onClick(View v) { public void onClick(View v) {
if (infoExpanded) { if (infoExpanded) {
collapseInfoView(); collapseInfoView();
} else if (setInfoType(InfoType.POINTS) && portrait) { } else if (setInfoType(InfoType.POINTS)) {
infoTypeBtn.setSelectedItem(pointsBtn); infoTypeBtn.setSelectedItem(pointsBtn);
} }
} }
@ -626,7 +638,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
if (portrait) { if (portrait) {
setMapPosition(OsmandSettings.MIDDLE_TOP_CONSTANT); setMapPosition(OsmandSettings.MIDDLE_TOP_CONSTANT);
} else { } else {
shiftBottomMapControls(false); shiftMapControls(false);
setMapPosition(OsmandSettings.LANDSCAPE_MIDDLE_RIGHT_CONSTANT); setMapPosition(OsmandSettings.LANDSCAPE_MIDDLE_RIGHT_CONSTANT);
} }
cardsContainer.setVisibility(View.VISIBLE); cardsContainer.setVisibility(View.VISIBLE);
@ -640,15 +652,14 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
} }
private void collapseInfoView() { private void collapseInfoView() {
cardsContainer.setVisibility(View.GONE);
if (portrait) {
infoTypeBtn.setSelectedItem(null);
} else {
shiftBottomMapControls(true);
}
infoExpanded = false; infoExpanded = false;
currentInfoType = null; currentInfoType = null;
setDefaultMapPosition(); cardsContainer.setVisibility(View.GONE);
if (!portrait) {
shiftMapControls(true);
}
infoTypeBtn.setSelectedItem(null);
moveMapToDefaultPosition();
updateUpDownBtn(); updateUpDownBtn();
} }
@ -676,37 +687,37 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
} }
} }
private void updateCardContainerSize() { private void updateInfoViewAppearance() {
if (portrait) { if (portrait) return;
return;
View toolsPanel = mainView.findViewById(R.id.measure_mode_controls);
View snapToRoadProgress = mainView.findViewById(R.id.snap_to_road_progress_bar);
int infoViewWidth = mainView.getWidth() - toolsPanel.getWidth();
int bottomMargin = toolsPanel.getHeight();
if (progressBarVisible) {
bottomMargin += snapToRoadProgress.getHeight();
} }
View measureModeControls = mainView.findViewById(R.id.measure_mode_controls);
int width = mainView.getWidth() - measureModeControls.getWidth(); ViewGroup.MarginLayoutParams params = null;
int bottomMargin = measureModeControls.getHeight();
bottomMargin = progressBarVisible ? bottomMargin + mainView.findViewById(R.id.snap_to_road_progress_bar).getHeight() : bottomMargin;
if (mainView.getParent() instanceof FrameLayout) { if (mainView.getParent() instanceof FrameLayout) {
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, -1); params = new FrameLayout.LayoutParams(infoViewWidth, -1);
params.setMargins(0, 0, 0, bottomMargin);
cardsContainer.setLayoutParams(params);
} else if (mainView.getParent() instanceof LinearLayout) { } else if (mainView.getParent() instanceof LinearLayout) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(width, -1); params = new LinearLayout.LayoutParams(infoViewWidth, -1);
params.setMargins(0, 0, 0, bottomMargin); }
if (params != null) {
AndroidUtils.setMargins(params, 0, 0, 0, bottomMargin);
cardsContainer.setLayoutParams(params); cardsContainer.setLayoutParams(params);
} }
} }
private void shiftBottomMapControls(boolean toInitialPosition) { private void shiftMapControls(boolean toInitialPosition) {
if (portrait) { boolean isLayoutRtl = AndroidUtils.isLayoutRtl(getContext());
return; int shiftPosition = toInitialPosition ? 0 : cardsContainer.getWidth();
} int start = isLayoutRtl ? 0 : shiftPosition;
int leftMargin = toInitialPosition ? 0 : cardsContainer.getWidth(); int end = isLayoutRtl ? shiftPosition : 0;
if (bottomMapControls.getParent() instanceof LinearLayout) { AndroidUtils.setMargins((MarginLayoutParams) bottomMapControls.getLayoutParams(), start, 0, end, 0);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) bottomMapControls.getLayoutParams(); AndroidUtils.setMargins((MarginLayoutParams) topMapControls.getLayoutParams(), start, 0, end, 0);
params.setMargins(leftMargin, 0, 0, 0);
} else if (bottomMapControls.getParent() instanceof FrameLayout) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) bottomMapControls.getLayoutParams();
params.setMargins(leftMargin, 0, 0, 0);
}
} }
public boolean isInEditMode() { public boolean isInEditMode() {
@ -772,7 +783,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
mapActivity.getMapLayers().getMapControlsLayer().addThemeInfoProviderTag(TAG); mapActivity.getMapLayers().getMapControlsLayer().addThemeInfoProviderTag(TAG);
mapActivity.getMapLayers().getMapControlsLayer().showMapControlsIfHidden(); mapActivity.getMapLayers().getMapControlsLayer().showMapControlsIfHidden();
cachedMapPosition = mapActivity.getMapView().getMapPosition(); cachedMapPosition = mapActivity.getMapView().getMapPosition();
setDefaultMapPosition(); moveMapToDefaultPosition();
addInitialPoint(); addInitialPoint();
} }
} }
@ -1196,7 +1207,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
@Override @Override
public void onCloseMenu() { public void onCloseMenu() {
setDefaultMapPosition(); moveMapToDefaultPosition();
} }
@Override @Override
@ -1390,7 +1401,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
editingCtx.cancelSnapToRoad(); editingCtx.cancelSnapToRoad();
MapActivity mapActivity = getMapActivity(); MapActivity mapActivity = getMapActivity();
if (mapActivity != null) { if (mapActivity != null) {
mainView.findViewById(R.id.snap_to_road_progress_bar).setVisibility(View.GONE); mainView.findViewById(R.id.snap_to_road_progress_bar).setVisibility(View.INVISIBLE);
mapActivity.refreshMap(); mapActivity.refreshMap();
} }
} }
@ -1641,7 +1652,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
updateInfoView(); updateInfoView();
} }
private void setDefaultMapPosition() { private void moveMapToDefaultPosition() {
setMapPosition(OsmandSettings.CENTER_CONSTANT); setMapPosition(OsmandSettings.CENTER_CONSTANT);
} }

View file

@ -1,12 +1,11 @@
package net.osmand.plus.resources; package net.osmand.plus.resources;
import android.view.LayoutInflater;
import net.osmand.IndexConstants; import net.osmand.IndexConstants;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
import net.osmand.binary.BinaryMapIndexReader; import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.osm.io.NetworkUtils; import net.osmand.osm.io.NetworkUtils;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.download.SrtmDownloadItem;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -34,7 +33,6 @@ public class IncrementalChangesManager {
private ResourceManager resourceManager; private ResourceManager resourceManager;
private final Map<String, RegionUpdateFiles> regions = new ConcurrentHashMap<String, IncrementalChangesManager.RegionUpdateFiles>(); private final Map<String, RegionUpdateFiles> regions = new ConcurrentHashMap<String, IncrementalChangesManager.RegionUpdateFiles>();
public IncrementalChangesManager(ResourceManager resourceManager) { public IncrementalChangesManager(ResourceManager resourceManager) {
this.resourceManager = resourceManager; this.resourceManager = resourceManager;
} }
@ -48,7 +46,7 @@ public class IncrementalChangesManager {
Set<String> existingFiles = new HashSet<String>(); Set<String> existingFiles = new HashSet<String>();
for (File f : files) { for (File f : files) {
if (!f.getName().endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT) && if (!f.getName().endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT) &&
!f.getName().endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)) { !SrtmDownloadItem.isSrtmFile(f.getName())) {
existingFiles.add(Algorithms.getFileNameWithoutExtension(f)); existingFiles.add(Algorithms.getFileNameWithoutExtension(f));
} }
} }
@ -186,7 +184,6 @@ public class IncrementalChangesManager {
public String errorMessage; public String errorMessage;
public RegionUpdateFiles updateFiles; public RegionUpdateFiles updateFiles;
public boolean isPreferrableLimitForDayUpdates(String monthYearPart, List<IncrementalUpdate> dayUpdates) { public boolean isPreferrableLimitForDayUpdates(String monthYearPart, List<IncrementalUpdate> dayUpdates) {
List<RegionUpdate> lst = updateFiles.dayUpdates.get(monthYearPart); List<RegionUpdate> lst = updateFiles.dayUpdates.get(monthYearPart);
if (lst == null || lst.size() < 10) { if (lst == null || lst.size() < 10) {
@ -333,8 +330,6 @@ public class IncrementalChangesManager {
return lst; return lst;
} }
public IncrementalUpdateList getUpdatesByMonth(String fileName) { public IncrementalUpdateList getUpdatesByMonth(String fileName) {
IncrementalUpdateList iul = new IncrementalUpdateList(); IncrementalUpdateList iul = new IncrementalUpdateList();
RegionUpdateFiles ruf = regions.get(fileName.toLowerCase()); RegionUpdateFiles ruf = regions.get(fileName.toLowerCase());

View file

@ -41,6 +41,7 @@ import net.osmand.plus.R;
import net.osmand.plus.Version; import net.osmand.plus.Version;
import net.osmand.plus.download.DownloadOsmandIndexesHelper; import net.osmand.plus.download.DownloadOsmandIndexesHelper;
import net.osmand.plus.download.DownloadOsmandIndexesHelper.AssetEntry; import net.osmand.plus.download.DownloadOsmandIndexesHelper.AssetEntry;
import net.osmand.plus.download.SrtmDownloadItem;
import net.osmand.plus.inapp.InAppPurchaseHelper; import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.render.MapRenderRepositories; import net.osmand.plus.render.MapRenderRepositories;
import net.osmand.plus.render.NativeOsmandLibrary; import net.osmand.plus.render.NativeOsmandLibrary;
@ -126,6 +127,7 @@ public class ResourceManager {
private List<BinaryMapIndexReader> readers = new ArrayList<>(BinaryMapReaderResourceType.values().length); private List<BinaryMapIndexReader> readers = new ArrayList<>(BinaryMapReaderResourceType.values().length);
private boolean useForRouting; private boolean useForRouting;
private boolean useForPublicTransport; private boolean useForPublicTransport;
public BinaryMapReaderResource(File f, BinaryMapIndexReader initialReader) { public BinaryMapReaderResource(File f, BinaryMapIndexReader initialReader) {
this.filename = f; this.filename = f;
this.initialReader = initialReader; this.initialReader = initialReader;
@ -205,7 +207,6 @@ public class ResourceManager {
protected final Map<String, BinaryMapReaderResource> fileReaders = new ConcurrentHashMap<String, BinaryMapReaderResource>(); protected final Map<String, BinaryMapReaderResource> fileReaders = new ConcurrentHashMap<String, BinaryMapReaderResource>();
private final Map<String, RegionAddressRepository> addressMap = new ConcurrentHashMap<String, RegionAddressRepository>(); private final Map<String, RegionAddressRepository> addressMap = new ConcurrentHashMap<String, RegionAddressRepository>();
protected final Map<String, AmenityIndexRepository> amenityRepositories = new ConcurrentHashMap<String, AmenityIndexRepository>(); protected final Map<String, AmenityIndexRepository> amenityRepositories = new ConcurrentHashMap<String, AmenityIndexRepository>();
// protected final Map<String, BinaryMapIndexReader> routingMapFiles = new ConcurrentHashMap<String, BinaryMapIndexReader>(); // protected final Map<String, BinaryMapIndexReader> routingMapFiles = new ConcurrentHashMap<String, BinaryMapIndexReader>();
@ -214,7 +215,6 @@ public class ResourceManager {
protected final Map<String, String> indexFileNames = new ConcurrentHashMap<String, String>(); protected final Map<String, String> indexFileNames = new ConcurrentHashMap<String, String>();
protected final Map<String, String> basemapFileNames = new ConcurrentHashMap<String, String>(); protected final Map<String, String> basemapFileNames = new ConcurrentHashMap<String, String>();
protected final IncrementalChangesManager changesManager = new IncrementalChangesManager(this); protected final IncrementalChangesManager changesManager = new IncrementalChangesManager(this);
protected final MapRenderRepositories renderer; protected final MapRenderRepositories renderer;
@ -540,6 +540,7 @@ public class ResourceManager {
private final static String ASSET_COPY_MODE__overwriteOnlyIfExists = "overwriteOnlyIfExists"; private final static String ASSET_COPY_MODE__overwriteOnlyIfExists = "overwriteOnlyIfExists";
private final static String ASSET_COPY_MODE__alwaysOverwriteOrCopy = "alwaysOverwriteOrCopy"; private final static String ASSET_COPY_MODE__alwaysOverwriteOrCopy = "alwaysOverwriteOrCopy";
private final static String ASSET_COPY_MODE__copyOnlyIfDoesNotExist = "copyOnlyIfDoesNotExist"; private final static String ASSET_COPY_MODE__copyOnlyIfDoesNotExist = "copyOnlyIfDoesNotExist";
private void unpackBundledAssets(AssetManager assetManager, File appDataDir, IProgress progress, boolean isFirstInstall) throws IOException, XmlPullParserException { private void unpackBundledAssets(AssetManager assetManager, File appDataDir, IProgress progress, boolean isFirstInstall) throws IOException, XmlPullParserException {
List<AssetEntry> assetEntries = DownloadOsmandIndexesHelper.getBundledAssets(assetManager); List<AssetEntry> assetEntries = DownloadOsmandIndexesHelper.getBundledAssets(assetManager);
for (AssetEntry asset : assetEntries) { for (AssetEntry asset : assetEntries) {
@ -607,8 +608,6 @@ public class ResourceManager {
return files; return files;
} }
private void renameRoadsFiles(ArrayList<File> files, File roadsPath) { private void renameRoadsFiles(ArrayList<File> files, File roadsPath) {
Iterator<File> it = files.iterator(); Iterator<File> it = files.iterator();
while (it.hasNext()) { while (it.hasNext()) {
@ -703,7 +702,7 @@ public class ResourceManager {
log.error(String.format("File %s could not be read", f.getName()), e); log.error(String.format("File %s could not be read", f.getName()), e);
} }
boolean wikiMap = (f.getName().contains("_wiki") || f.getName().contains(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)); boolean wikiMap = (f.getName().contains("_wiki") || f.getName().contains(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT));
boolean srtmMap = f.getName().contains(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT); boolean srtmMap = SrtmDownloadItem.containsSrtmExtension(f.getName());
if (mapReader == null || (!Version.isPaidVersion(context) && wikiMap && !f.getName().equals(DEFAULT_WIKIVOYAGE_TRAVEL_OBF))) { if (mapReader == null || (!Version.isPaidVersion(context) && wikiMap && !f.getName().equals(DEFAULT_WIKIVOYAGE_TRAVEL_OBF))) {
warnings.add(MessageFormat.format(context.getString(R.string.version_index_is_not_supported), f.getName())); //$NON-NLS-1$ warnings.add(MessageFormat.format(context.getString(R.string.version_index_is_not_supported), f.getName())); //$NON-NLS-1$
} else { } else {
@ -944,7 +943,6 @@ public class ResourceManager {
return amenities; return amenities;
} }
public boolean containsAmenityRepositoryToSearch(boolean searchByName) { public boolean containsAmenityRepositoryToSearch(boolean searchByName) {
for (AmenityIndexRepository index : getAmenityRepositories()) { for (AmenityIndexRepository index : getAmenityRepositories()) {
if (searchByName) { if (searchByName) {
@ -1040,7 +1038,6 @@ public class ResourceManager {
return res; return res;
} }
////////////////////////////////////////////// Working with transport //////////////////////////////////////////////// ////////////////////////////////////////////// Working with transport ////////////////////////////////////////////////
private List<BinaryMapIndexReader> getTransportRepositories(double topLat, double leftLon, double bottomLat, double rightLon) { private List<BinaryMapIndexReader> getTransportRepositories(double topLat, double leftLon, double bottomLat, double rightLon) {
@ -1183,7 +1180,6 @@ public class ResourceManager {
return new LinkedHashMap<String, String>(indexFileNames); return new LinkedHashMap<String, String>(indexFileNames);
} }
public boolean containsBasemap() { public boolean containsBasemap() {
return !basemapFileNames.isEmpty(); return !basemapFileNames.isEmpty();
} }

View file

@ -32,9 +32,10 @@ import net.osmand.plus.settings.fragments.HeaderUiAdapter;
import net.osmand.plus.track.AppearanceViewHolder; import net.osmand.plus.track.AppearanceViewHolder;
import net.osmand.plus.track.ColorsCard; import net.osmand.plus.track.ColorsCard;
import net.osmand.plus.track.CustomColorBottomSheet.ColorPickerListener; import net.osmand.plus.track.CustomColorBottomSheet.ColorPickerListener;
import net.osmand.plus.widgets.MultiStateToggleButton; import net.osmand.plus.widgets.multistatetoggle.RadioItem;
import net.osmand.plus.widgets.MultiStateToggleButton.OnRadioItemClickListener; import net.osmand.plus.widgets.multistatetoggle.RadioItem.OnRadioItemClickListener;
import net.osmand.plus.widgets.MultiStateToggleButton.RadioItem; import net.osmand.plus.widgets.multistatetoggle.TextToggleButton;
import net.osmand.plus.widgets.multistatetoggle.TextToggleButton.TextRadioItem;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -134,17 +135,17 @@ public class RouteLineColorCard extends BaseCard implements CardListener, ColorP
} }
private void setupRadioGroup(LinearLayout buttonsContainer) { private void setupRadioGroup(LinearLayout buttonsContainer) {
RadioItem day = createMapThemeButton(false); TextRadioItem day = createMapThemeButton(false);
RadioItem night = createMapThemeButton(true); TextRadioItem night = createMapThemeButton(true);
MultiStateToggleButton radioGroup = new MultiStateToggleButton(app, buttonsContainer, nightMode); TextToggleButton radioGroup = new TextToggleButton(app, buttonsContainer, nightMode);
radioGroup.setItems(day, night); radioGroup.setItems(day, night);
radioGroup.setSelectedItem(!isNightMap() ? day : night); radioGroup.setSelectedItem(!isNightMap() ? day : night);
} }
private RadioItem createMapThemeButton(final boolean isNight) { private TextRadioItem createMapThemeButton(final boolean isNight) {
RadioItem item = new RadioItem(app.getString(!isNight ? DAY_TITLE_ID : NIGHT_TITLE_ID)); TextRadioItem item = new TextRadioItem(app.getString(!isNight ? DAY_TITLE_ID : NIGHT_TITLE_ID));
item.setOnClickListener(new OnRadioItemClickListener() { item.setOnClickListener(new OnRadioItemClickListener() {
@Override @Override
public boolean onRadioItemClick(RadioItem radioItem, View view) { public boolean onRadioItemClick(RadioItem radioItem, View view) {

View file

@ -7,6 +7,7 @@ import androidx.annotation.Nullable;
import net.osmand.IndexConstants; import net.osmand.IndexConstants;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.download.SrtmDownloadItem;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import org.json.JSONException; import org.json.JSONException;
@ -92,7 +93,7 @@ public class FileSettingsItem extends StreamSettingsItem {
case OTHER: case OTHER:
break; break;
case SRTM_MAP: case SRTM_MAP:
if (name.endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)) { if (SrtmDownloadItem.isSrtmFile(name)) {
return subtype; return subtype;
} }
break; break;
@ -257,6 +258,8 @@ public class FileSettingsItem extends StreamSettingsItem {
prefix = oldPath.substring(0, oldPath.lastIndexOf(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)); prefix = oldPath.substring(0, oldPath.lastIndexOf(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT));
} else if (oldPath.endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)) { } else if (oldPath.endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)) {
prefix = oldPath.substring(0, oldPath.lastIndexOf(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)); prefix = oldPath.substring(0, oldPath.lastIndexOf(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT));
} else if (oldPath.endsWith(IndexConstants.BINARY_SRTM_FEET_MAP_INDEX_EXT)) {
prefix = oldPath.substring(0, oldPath.lastIndexOf(IndexConstants.BINARY_SRTM_FEET_MAP_INDEX_EXT));
} else if (oldPath.endsWith(IndexConstants.BINARY_ROAD_MAP_INDEX_EXT)) { } else if (oldPath.endsWith(IndexConstants.BINARY_ROAD_MAP_INDEX_EXT)) {
prefix = oldPath.substring(0, oldPath.lastIndexOf(IndexConstants.BINARY_ROAD_MAP_INDEX_EXT)); prefix = oldPath.substring(0, oldPath.lastIndexOf(IndexConstants.BINARY_ROAD_MAP_INDEX_EXT));
} else { } else {

View file

@ -200,7 +200,7 @@ public class DataStorageHelper {
terrainMemory = MemoryItem.builder() terrainMemory = MemoryItem.builder()
.setKey(TERRAIN_MEMORY) .setKey(TERRAIN_MEMORY)
.setExtensions(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT) .setExtensions(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT, IndexConstants.BINARY_SRTM_FEET_MAP_INDEX_EXT)
.setDirectories( .setDirectories(
createDirectory(SRTM_INDEX_DIR, true, EXTENSIONS, true), createDirectory(SRTM_INDEX_DIR, true, EXTENSIONS, true),
createDirectory(TILES_INDEX_DIR, false, PREFIX, false)) createDirectory(TILES_INDEX_DIR, false, PREFIX, false))

View file

@ -492,8 +492,7 @@ public abstract class BaseSettingsFragment extends PreferenceFragmentCompat impl
} }
}); });
if (closeButton instanceof ImageView) { if (closeButton instanceof ImageView) {
UiUtilities.rotateImageByLayoutDirection( UiUtilities.rotateImageByLayoutDirection((ImageView) closeButton);
(ImageView) closeButton, AndroidUtils.getLayoutDirection(app));
} }
} }

View file

@ -36,6 +36,7 @@ import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithCompoundButton.Bu
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription; import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription;
import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem; import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.SimpleDividerItem; import net.osmand.plus.base.bottomsheetmenu.simpleitems.SimpleDividerItem;
import net.osmand.plus.download.SrtmDownloadItem;
import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo; import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo;
import net.osmand.plus.helpers.FileNameTranslationHelper; import net.osmand.plus.helpers.FileNameTranslationHelper;
import net.osmand.plus.helpers.GpxUiHelper; import net.osmand.plus.helpers.GpxUiHelper;
@ -530,7 +531,7 @@ public class ExportItemsBottomSheet extends MenuBottomSheetDialogFragment {
return getString(R.string.download_roads_only_item); return getString(R.string.download_roads_only_item);
} else if (file.getName().endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) { } else if (file.getName().endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) {
return getString(R.string.download_wikipedia_maps); return getString(R.string.download_wikipedia_maps);
} else if (file.getName().endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)) { } else if (SrtmDownloadItem.isSrtmFile(file.getName())) {
return getString(R.string.download_srtm_maps); return getString(R.string.download_srtm_maps);
} else if (file.getName().endsWith(IndexConstants.BINARY_MAP_INDEX_EXT)) { } else if (file.getName().endsWith(IndexConstants.BINARY_MAP_INDEX_EXT)) {
return getString(R.string.download_regular_maps); return getString(R.string.download_regular_maps);

View file

@ -10,6 +10,11 @@ import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.appbar.AppBarLayout;
import net.osmand.AndroidUtils; import net.osmand.AndroidUtils;
@ -30,11 +35,6 @@ import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
public class PurchasesFragment extends BaseOsmAndFragment implements InAppPurchaseListener, OnFragmentInteractionListener { public class PurchasesFragment extends BaseOsmAndFragment implements InAppPurchaseListener, OnFragmentInteractionListener {
private static final Log log = PlatformUtil.getLog(PurchasesFragment.class); private static final Log log = PlatformUtil.getLog(PurchasesFragment.class);
@ -152,6 +152,7 @@ public class PurchasesFragment extends BaseOsmAndFragment implements InAppPurcha
} }
}); });
ImageButton backButton = toolbar.findViewById(R.id.close_button); ImageButton backButton = toolbar.findViewById(R.id.close_button);
UiUtilities.rotateImageByLayoutDirection(backButton);
backButton.setOnClickListener(new View.OnClickListener() { backButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@ -197,9 +198,7 @@ public class PurchasesFragment extends BaseOsmAndFragment implements InAppPurcha
@Override @Override
public void onSearchResult(CountrySelectionFragment.CountryItem name) { public void onSearchResult(CountrySelectionFragment.CountryItem name) {
if (subscriptionsCard != null) {
subscriptionsCard.onSupportRegionSelected(name);
}
} }
@Override @Override

View file

@ -5,30 +5,26 @@ import android.net.Uri;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import net.osmand.AndroidUtils; import net.osmand.AndroidUtils;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper; import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.liveupdates.CountrySelectionFragment;
import net.osmand.plus.liveupdates.LiveUpdatesFragment; import net.osmand.plus.liveupdates.LiveUpdatesFragment;
import net.osmand.plus.liveupdates.OsmLiveActivity; import net.osmand.plus.liveupdates.OsmLiveActivity;
import net.osmand.plus.routepreparationmenu.cards.BaseCard; import net.osmand.plus.routepreparationmenu.cards.BaseCard;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
public class SubscriptionsCard extends BaseCard { public class SubscriptionsCard extends BaseCard {
private static final String PLAY_STORE_SUBSCRIPTION_URL = "https://play.google.com/store/account/subscriptions"; private static final String PLAY_STORE_SUBSCRIPTION_URL = "https://play.google.com/store/account/subscriptions";
private static final String PLAY_STORE_SUBSCRIPTION_DEEPLINK_URL = "https://play.google.com/store/account/subscriptions?sku=%s&package=%s"; private static final String PLAY_STORE_SUBSCRIPTION_DEEPLINK_URL = "https://play.google.com/store/account/subscriptions?sku=%s&package=%s";
private Fragment target; private Fragment target;
private CountrySelectionFragment countrySelectionFragment = new CountrySelectionFragment();
private SubscriptionsListCard subscriptionsListCard; private SubscriptionsListCard subscriptionsListCard;
private InAppPurchaseHelper purchaseHelper; private InAppPurchaseHelper purchaseHelper;
@ -54,7 +50,6 @@ public class SubscriptionsCard extends BaseCard {
} }
updateSubscriptionsListCard(); updateSubscriptionsListCard();
setupSupportRegion();
LinearLayout reportContainer = view.findViewById(R.id.report_container); LinearLayout reportContainer = view.findViewById(R.id.report_container);
reportContainer.setOnClickListener(new View.OnClickListener() { reportContainer.setOnClickListener(new View.OnClickListener() {
@ -99,26 +94,6 @@ public class SubscriptionsCard extends BaseCard {
} }
} }
private void setupSupportRegion() {
String region = LiveUpdatesFragment.getSupportRegionName(app, purchaseHelper);
String header = LiveUpdatesFragment.getSupportRegionHeader(app, region);
TextView supportRegionHeader = view.findViewById(R.id.support_region_header);
TextView supportRegion = view.findViewById(R.id.support_region);
supportRegionHeader.setText(header);
supportRegion.setText(region);
View supportRegionContainer = view.findViewById(R.id.support_region_container);
supportRegionContainer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CountrySelectionFragment countryCountrySelectionFragment = countrySelectionFragment;
countryCountrySelectionFragment.show(target.getChildFragmentManager(), CountrySelectionFragment.TAG);
}
});
countrySelectionFragment.initCountries(app);
}
private String getSubscriptionUrl() { private String getSubscriptionUrl() {
InAppPurchaseHelper purchaseHelper = app.getInAppPurchaseHelper(); InAppPurchaseHelper purchaseHelper = app.getInAppPurchaseHelper();
if (purchaseHelper != null && purchaseHelper.getFullVersion() != null) { if (purchaseHelper != null && purchaseHelper.getFullVersion() != null) {
@ -129,17 +104,4 @@ public class SubscriptionsCard extends BaseCard {
return PLAY_STORE_SUBSCRIPTION_URL; return PLAY_STORE_SUBSCRIPTION_URL;
} }
} }
public void onSupportRegionSelected(CountrySelectionFragment.CountryItem selectedCountryItem) {
String countryName = selectedCountryItem != null ? selectedCountryItem.getLocalName() : "";
String countryDownloadName = selectedCountryItem != null ?
selectedCountryItem.getDownloadName() : OsmandSettings.BILLING_USER_DONATION_WORLD_PARAMETER;
TextView supportRegionHeader = view.findViewById(R.id.support_region_header);
TextView supportRegion = view.findViewById(R.id.support_region);
supportRegionHeader.setText(LiveUpdatesFragment.getSupportRegionHeader(app, countryName));
supportRegion.setText(countryName);
app.getSettings().BILLING_USER_COUNTRY.set(countryName);
app.getSettings().BILLING_USER_COUNTRY_DOWNLOAD_NAME.set(countryDownloadName);
}
} }

View file

@ -7,20 +7,22 @@ import android.text.Spannable;
import android.text.SpannableString; import android.text.SpannableString;
import android.text.style.StyleSpan; import android.text.style.StyleSpan;
import android.view.View; import android.view.View;
import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.cardview.widget.CardView;
import androidx.core.content.ContextCompat;
import net.osmand.AndroidUtils; import net.osmand.AndroidUtils;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.chooseplan.ChoosePlanDialogFragment; import net.osmand.plus.chooseplan.ChoosePlanDialogFragment;
import net.osmand.plus.inapp.InAppPurchaseHelper; import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.routepreparationmenu.cards.BaseCard; import net.osmand.plus.routepreparationmenu.cards.BaseCard;
import net.osmand.plus.wikipedia.WikipediaDialogFragment; import net.osmand.plus.wikipedia.WikipediaDialogFragment;
import androidx.annotation.NonNull;
import androidx.cardview.widget.CardView;
import androidx.core.content.ContextCompat;
public class TroubleshootingOrPurchasingCard extends BaseCard { public class TroubleshootingOrPurchasingCard extends BaseCard {
private static final String OSMAND_NEW_DEVICE_URL = "https://docs.osmand.net/en/main@latest/osmand/purchases#new-device--new-account"; private static final String OSMAND_NEW_DEVICE_URL = "https://docs.osmand.net/en/main@latest/osmand/purchases#new-device--new-account";
@ -74,6 +76,9 @@ public class TroubleshootingOrPurchasingCard extends BaseCard {
} else { } else {
AndroidUtils.setBackground(mapActivity, getItButton, nightMode, R.drawable.btn_unstroked_light, R.drawable.btn_unstroked_dark); AndroidUtils.setBackground(mapActivity, getItButton, nightMode, R.drawable.btn_unstroked_light, R.drawable.btn_unstroked_dark);
} }
ImageView getItArrow = view.findViewById(R.id.additional_button_icon);
UiUtilities.rotateImageByLayoutDirection(getItArrow);
} }
} }

View file

@ -22,12 +22,12 @@ import net.osmand.plus.R;
import net.osmand.plus.UiUtilities; import net.osmand.plus.UiUtilities;
import net.osmand.plus.base.MenuBottomSheetDialogFragment; import net.osmand.plus.base.MenuBottomSheetDialogFragment;
import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem; import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.LongDescriptionItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem; import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.widgets.MultiStateToggleButton; import net.osmand.plus.widgets.multistatetoggle.RadioItem;
import net.osmand.plus.widgets.MultiStateToggleButton.OnRadioItemClickListener; import net.osmand.plus.widgets.multistatetoggle.RadioItem.OnRadioItemClickListener;
import net.osmand.plus.widgets.MultiStateToggleButton.RadioItem; import net.osmand.plus.widgets.multistatetoggle.TextToggleButton;
import net.osmand.plus.widgets.multistatetoggle.TextToggleButton.TextRadioItem;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -120,11 +120,11 @@ public class SplitIntervalBottomSheet extends MenuBottomSheetDialogFragment {
} }
private void setupTypeRadioGroup(LinearLayout buttonsContainer) { private void setupTypeRadioGroup(LinearLayout buttonsContainer) {
RadioItem none = createRadioButton(GpxSplitType.NO_SPLIT, R.string.shared_string_none); TextRadioItem none = createRadioButton(GpxSplitType.NO_SPLIT, R.string.shared_string_none);
RadioItem time = createRadioButton(GpxSplitType.TIME, R.string.shared_string_time); TextRadioItem time = createRadioButton(GpxSplitType.TIME, R.string.shared_string_time);
RadioItem distance = createRadioButton(GpxSplitType.DISTANCE, R.string.distance); TextRadioItem distance = createRadioButton(GpxSplitType.DISTANCE, R.string.distance);
MultiStateToggleButton radioGroup = new MultiStateToggleButton(app, buttonsContainer, nightMode); TextToggleButton radioGroup = new TextToggleButton(app, buttonsContainer, nightMode);
radioGroup.setItems(none, time, distance); radioGroup.setItems(none, time, distance);
if (selectedSplitType == GpxSplitType.NO_SPLIT) { if (selectedSplitType == GpxSplitType.NO_SPLIT) {
@ -134,9 +134,9 @@ public class SplitIntervalBottomSheet extends MenuBottomSheetDialogFragment {
} }
} }
private RadioItem createRadioButton(final GpxSplitType splitType, int titleId) { private TextRadioItem createRadioButton(final GpxSplitType splitType, int titleId) {
String title = app.getString(titleId); String title = app.getString(titleId);
RadioItem item = new RadioItem(title); TextRadioItem item = new TextRadioItem(title);
item.setOnClickListener(new OnRadioItemClickListener() { item.setOnClickListener(new OnRadioItemClickListener() {
@Override @Override
public boolean onRadioItemClick(RadioItem radioItem, View view) { public boolean onRadioItemClick(RadioItem radioItem, View view) {

View file

@ -0,0 +1,70 @@
package net.osmand.plus.widgets.multistatetoggle;
import android.graphics.drawable.Drawable;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.widgets.multistatetoggle.IconToggleButton.IconRadioItem;
public class IconToggleButton extends MultiStateToggleButton<IconRadioItem> {
public IconToggleButton(@NonNull OsmandApplication app,
@NonNull LinearLayout container,
boolean nightMode) {
super(app, container, nightMode);
}
@Override
protected int getRadioItemLayoutId() {
return R.layout.custom_radio_btn_icon_item;
}
@Override
protected void initItemView(@NonNull ViewGroup view,
@NonNull IconRadioItem item) {
if (item.isUseDefaultColor()) {
ImageView ivIcon = view.findViewById(R.id.icon);
ivIcon.setImageDrawable(uiUtilities.getIcon(item.getIconId()));
}
}
@Override
protected void updateItemView(@NonNull ViewGroup view,
@NonNull IconRadioItem item,
@ColorInt int color) {
if (!item.isUseDefaultColor()) {
ImageView ivIcon = view.findViewById(R.id.icon);
Drawable icon = uiUtilities.getPaintedIcon(item.getIconId(), color);
ivIcon.setImageDrawable(icon);
}
}
public static class IconRadioItem extends RadioItem {
private final int iconId;
private final boolean useDefaultColor;
public IconRadioItem(int iconId) {
this(iconId, false);
}
public IconRadioItem(int iconId, boolean useDefaultColor) {
this.iconId = iconId;
this.useDefaultColor = useDefaultColor;
}
public int getIconId() {
return iconId;
}
public boolean isUseDefaultColor() {
return useDefaultColor;
}
}
}

View file

@ -1,4 +1,4 @@
package net.osmand.plus.widgets; package net.osmand.plus.widgets.multistatetoggle;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.GradientDrawable;
@ -6,38 +6,58 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import net.osmand.AndroidUtils; import net.osmand.AndroidUtils;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.UiUtilities; import net.osmand.plus.UiUtilities;
import net.osmand.plus.widgets.multistatetoggle.RadioItem.OnRadioItemClickListener;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Collection;
import java.util.List; import java.util.List;
public class MultiStateToggleButton { public abstract class MultiStateToggleButton<_Radio extends RadioItem> {
private List<RadioItem> items = new ArrayList<>(); protected final OsmandApplication app;
private OsmandApplication app; protected final UiUtilities uiUtilities;
private List<ViewGroup> buttons = new ArrayList<>();
private List<View> dividers = new ArrayList<>();
private RadioItem selectedItem;
private LinearLayout container; private final LinearLayout container;
private boolean nightMode; private final List<ViewGroup> buttons = new ArrayList<>();
private final List<View> dividers = new ArrayList<>();
public MultiStateToggleButton(OsmandApplication app, LinearLayout container, boolean nightMode) { protected final List<_Radio> items = new ArrayList<>();
protected final boolean nightMode;
protected boolean isEnabled;
protected RadioItem selectedItem;
public MultiStateToggleButton(@NonNull OsmandApplication app,
@NonNull LinearLayout container,
boolean nightMode) {
this.app = app; this.app = app;
this.uiUtilities = app.getUIUtilities();
this.container = container; this.container = container;
this.nightMode = nightMode; this.nightMode = nightMode;
} }
public void setItems(RadioItem firstBtn, RadioItem secondBtn, RadioItem... other) { public void setItems(Collection<_Radio> radioItems) {
if (radioItems == null || radioItems.size() < 2) return;
items.clear();
items.addAll(radioItems);
initView();
}
@SafeVarargs
public final void setItems(@NonNull _Radio firstBtn,
@NonNull _Radio secondBtn,
@Nullable _Radio... other) {
items.clear(); items.clear();
items.add(firstBtn); items.add(firstBtn);
items.add(secondBtn); items.add(secondBtn);
@ -47,6 +67,11 @@ public class MultiStateToggleButton {
initView(); initView();
} }
public final void setSelectedItem(@Nullable RadioItem selectedItem) {
this.selectedItem = selectedItem;
updateView();
}
private void initView() { private void initView() {
buttons.clear(); buttons.clear();
dividers.clear(); dividers.clear();
@ -60,16 +85,10 @@ public class MultiStateToggleButton {
updateView(); updateView();
} }
private boolean isLastItem(int index) { private void createBtn(@NonNull final _Radio item) {
return index == items.size() - 1;
}
private void createBtn(@NonNull final RadioItem item) {
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode); LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
ViewGroup button = (ViewGroup) inflater.inflate( ViewGroup button = (ViewGroup) inflater.inflate(
R.layout.custom_radio_btn_text_item, container, false); getRadioItemLayoutId(), container, false);
TextView title = button.findViewById(R.id.title);
title.setText(item.getTitle());
button.setOnClickListener(new View.OnClickListener() { button.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@ -79,6 +98,7 @@ public class MultiStateToggleButton {
} }
} }
}); });
initItemView(button, item);
buttons.add(button); buttons.add(button);
container.addView(button); container.addView(button);
} }
@ -95,11 +115,6 @@ public class MultiStateToggleButton {
container.addView(divider); container.addView(divider);
} }
public void setSelectedItem(RadioItem selectedItem) {
this.selectedItem = selectedItem;
updateView();
}
private void updateView() { private void updateView() {
updateView(true); updateView(true);
} }
@ -123,15 +138,14 @@ public class MultiStateToggleButton {
showAllDividers(); showAllDividers();
for (int i = 0; i < items.size(); i++) { for (int i = 0; i < items.size(); i++) {
RadioItem item = items.get(i); _Radio item = items.get(i);
ViewGroup container = buttons.get(i); ViewGroup container = buttons.get(i);
container.setEnabled(isEnabled); container.setEnabled(isEnabled);
TextView tvTitle = (TextView) container.findViewById(R.id.title);
if (selectedItem == item) { if (selectedItem == item) {
if (i == 0) { if (i == 0) {
background.setCornerRadii(isLayoutRtl ? rightBtnRadii : leftBtnRadii); background.setCornerRadii(isLayoutRtl ? rightBtnRadii : leftBtnRadii);
hideDividers(0); hideDividers(0);
} else if (i == items.size() - 1) { } else if (isLastItem(i)) {
background.setCornerRadii(isLayoutRtl ? leftBtnRadii : rightBtnRadii); background.setCornerRadii(isLayoutRtl ? leftBtnRadii : rightBtnRadii);
hideDividers(dividers.size() - 1); hideDividers(dividers.size() - 1);
} else { } else {
@ -139,14 +153,21 @@ public class MultiStateToggleButton {
hideDividers(i - 1, i); hideDividers(i - 1, i);
} }
container.setBackgroundDrawable(background); container.setBackgroundDrawable(background);
tvTitle.setTextColor(textColor); updateItemView(container, item, textColor);
} else { } else {
container.setBackgroundColor(Color.TRANSPARENT); container.setBackgroundColor(Color.TRANSPARENT);
tvTitle.setTextColor(activeColor); updateItemView(container, item, activeColor);
} }
} }
} }
protected abstract int getRadioItemLayoutId();
protected abstract void initItemView(@NonNull ViewGroup view, @NonNull _Radio item);
protected abstract void updateItemView(@NonNull ViewGroup view, @NonNull _Radio item,
@ColorInt int color);
private void showAllDividers() { private void showAllDividers() {
for (View divider : dividers) { for (View divider : dividers) {
divider.setVisibility(View.VISIBLE); divider.setVisibility(View.VISIBLE);
@ -161,28 +182,7 @@ public class MultiStateToggleButton {
} }
} }
public static class RadioItem { private boolean isLastItem(int index) {
private String title; return index == items.size() - 1;
private OnRadioItemClickListener listener;
public RadioItem(String title) {
this.title = title;
}
public void setOnClickListener(OnRadioItemClickListener listener) {
this.listener = listener;
}
public String getTitle() {
return title;
}
public OnRadioItemClickListener getListener() {
return listener;
}
}
public interface OnRadioItemClickListener {
boolean onRadioItemClick(RadioItem radioItem, View view);
} }
} }

View file

@ -0,0 +1,20 @@
package net.osmand.plus.widgets.multistatetoggle;
import android.view.View;
public class RadioItem {
private OnRadioItemClickListener listener;
public void setOnClickListener(OnRadioItemClickListener listener) {
this.listener = listener;
}
public OnRadioItemClickListener getListener() {
return listener;
}
public interface OnRadioItemClickListener {
boolean onRadioItemClick(RadioItem radioItem, View view);
}
}

View file

@ -0,0 +1,54 @@
package net.osmand.plus.widgets.multistatetoggle;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.widgets.multistatetoggle.TextToggleButton.TextRadioItem;
public class TextToggleButton extends MultiStateToggleButton<TextRadioItem> {
public TextToggleButton(@NonNull OsmandApplication app,
@NonNull LinearLayout container,
boolean nightMode) {
super(app, container, nightMode);
}
@Override
protected int getRadioItemLayoutId() {
return R.layout.custom_radio_btn_text_item;
}
@Override
protected void initItemView(@NonNull ViewGroup view, @NonNull TextRadioItem item) {
TextView title = view.findViewById(R.id.title);
title.setText(item.getTitle());
}
@Override
protected void updateItemView(@NonNull ViewGroup view,
@NonNull TextRadioItem item,
@ColorInt int color) {
TextView tvTitle = (TextView) view.findViewById(R.id.title);
tvTitle.setTextColor(color);
}
public static class TextRadioItem extends RadioItem {
private final String title;
public TextRadioItem(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
}
}