Merge pull request #8458 from osmandapp/import_screen

Import screen
This commit is contained in:
max-klaus 2020-02-20 19:58:33 +03:00 committed by GitHub
commit 9d26310ca0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 2640 additions and 1091 deletions

View file

@ -29,7 +29,7 @@ public interface ITileSource {
public long getExpirationTimeMillis();
public int getExpirationTimeMinutes();
public String getReferer();
public void deleteTiles(String path);

View file

@ -1,31 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="20dp">
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="@dimen/title_padding">
<android.support.v7.widget.SwitchCompat
android:id="@+id/switchItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:minHeight="48dp"
android:text="@string/shared_string_include_data"
android:textSize="@dimen/default_list_text_size"
tools:text="@string/shared_string_include_data" />
<ExpandableListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null"
android:dividerHeight="0dp"
android:drawSelectorOnTop="false"
android:groupIndicator="@android:color/transparent"
android:visibility="gone"
tools:visibility="visible" />
<ExpandableListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null"
android:headerDividersEnabled="false"
android:dividerHeight="0dp"
android:drawSelectorOnTop="false"
android:groupIndicator="@android:color/transparent"
tools:visibility="visible" />
</LinearLayout>

View file

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/dialog_button_ex_height">
<LinearLayout
android:id="@+id/button_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding_small"
android:layout_marginLeft="@dimen/content_padding_small"
tools:src="@drawable/ic_action_keep_both" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="@dimen/content_padding_small"
android:layout_weight="1"
android:orientation="vertical">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="Main text" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/sub_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:textSize="@dimen/default_sub_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="Long subtext about two lines" />
</LinearLayout>
</LinearLayout>
</FrameLayout>

View file

@ -0,0 +1,136 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/activity_background_basic"
android:orientation="vertical">
<LinearLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height"
android:minHeight="@dimen/toolbar_height" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/content_padding"
android:paddingTop="@dimen/list_header_settings_top_margin"
android:paddingEnd="@dimen/content_padding"
android:paddingBottom="@dimen/list_header_settings_top_margin"
android:text="@string/shared_string_import"
android:textColor="?attr/app_bar_primary_item_color"
android:textSize="@dimen/dialog_header_text_size"
osmand:typeface="@string/font_roboto_medium" />
</LinearLayout>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/bg_color"
android:paddingStart="@dimen/content_padding"
android:paddingTop="@dimen/list_header_settings_top_margin"
android:paddingEnd="@dimen/content_padding"
android:paddingBottom="@dimen/list_header_settings_top_margin"
android:text="@string/select_data_to_import"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_medium" />
<include layout="@layout/card_bottom_divider" />
<ExpandableListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:divider="@null"
android:dividerHeight="0dp"
android:drawSelectorOnTop="false"
android:groupIndicator="@android:color/transparent"
android:listSelector="@android:color/transparent" />
<include layout="@layout/card_top_divider" />
<LinearLayout
android:id="@+id/buttons_container"
android:layout_width="match_parent"
android:layout_height="@dimen/dialog_button_ex_height"
android:background="?attr/bg_color"
android:gravity="center"
android:orientation="horizontal"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding_small"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding_small">
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/select_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:ellipsize="end"
android:gravity="start|center_vertical"
android:maxLines="1"
android:paddingLeft="@dimen/content_padding_small"
android:paddingTop="@dimen/content_padding_half"
android:paddingRight="@dimen/content_padding_small"
android:paddingBottom="@dimen/content_padding_half"
android:text="@string/shared_string_select_all"
android:textColor="?attr/active_color_basic"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="Select all" />
</FrameLayout>
<View
android:layout_width="@dimen/content_padding"
android:layout_height="match_parent" />
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="?attr/dlg_btn_primary">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/continue_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:ellipsize="end"
android:gravity="end|center_vertical"
android:maxLines="1"
android:paddingLeft="@dimen/content_padding_small"
android:paddingTop="@dimen/content_padding_half"
android:paddingRight="@dimen/content_padding_small"
android:paddingBottom="@dimen/content_padding_half"
android:text="@string/shared_string_continue"
android:textColor="?attr/dlg_btn_primary_text"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="Continue" />
</FrameLayout>
</LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/activity_background_basic"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height"
android:minHeight="@dimen/toolbar_height" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/content_padding"
android:paddingTop="@dimen/list_header_settings_top_margin"
android:paddingEnd="@dimen/content_padding"
android:paddingBottom="@dimen/list_header_settings_top_margin"
android:text="@string/import_duplicates_title"
android:textColor="?attr/app_bar_primary_item_color"
android:textSize="@dimen/dialog_header_text_size"
osmand:typeface="@string/font_roboto_medium" />
</LinearLayout>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/bg_color"
android:paddingStart="@dimen/content_padding"
android:paddingTop="@dimen/list_header_settings_top_margin"
android:paddingEnd="@dimen/content_padding"
android:paddingBottom="@dimen/list_header_settings_top_margin"
android:text="@string/import_duplicates_description"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_medium" />
<include
android:id="@+id/description_divider"
layout="@layout/card_bottom_divider" />
<android.support.v7.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<include
layout="@layout/card_top_divider" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/bg_color"
android:orientation="vertical"
android:padding="@dimen/content_padding">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/content_padding_half"
android:background="?attr/dlg_btn_secondary">
<net.osmand.view.ComplexButton
android:id="@+id/keep_both_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
osmand:setSubText="@string/keep_both_desc"
osmand:setSubTextColor="?android:textColorSecondary"
osmand:setText="@string/keep_both"
osmand:setTextColor="?attr/active_color_basic" />
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/dlg_btn_primary">
<net.osmand.view.ComplexButton
android:id="@+id/replace_all_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
osmand:setSubText="@string/replace_all_desc"
osmand:setSubTextColor="?android:textColorTertiaryInverse"
osmand:setText="@string/replace_all"
osmand:setTextColor="?attr/dlg_btn_primary_text" />
</FrameLayout>
</LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:background="?attr/activity_background_basic"
android:orientation="vertical">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/bg_color"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:minHeight="@dimen/bottom_sheet_list_item_height"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding"
android:text="@string/export_profile_dialog_description"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
app:typeface="@string/font_roboto_regular" />
<include
android:id="@+id/topSwitchDivider"
layout="@layout/card_bottom_divider"
android:visibility="gone" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/bg_color">
<android.support.v7.widget.SwitchCompat
android:id="@+id/switchItem"
android:layout_width="match_parent"
android:focusable="false"
android:focusableInTouchMode="false"
android:layout_height="wrap_content"
android:background="?attr/activity_background_basic"
android:minHeight="48dp"
android:text="@string/shared_string_include_data"
android:textSize="@dimen/default_list_text_size"
tools:text="@string/shared_string_include_data" />
</FrameLayout>
<include
android:id="@+id/bottomSwitchDivider"
layout="@layout/divider"
android:visibility="gone" />
</LinearLayout>

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include
android:id="@+id/top_divider"
layout="@layout/card_top_divider"
android:visibility="gone"
tools:visibility="visible" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/bg_color"
android:gravity="center_vertical"
android:minHeight="66dp"
android:orientation="vertical"
android:paddingStart="@dimen/content_padding"
android:paddingTop="@dimen/list_header_settings_top_margin"
android:paddingEnd="@dimen/content_padding"
android:paddingBottom="@dimen/list_header_settings_top_margin">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/preference_category_title"
android:textSize="@dimen/default_list_text_size"
tools:text="Quick actions" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/sub_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
tools:text="Listed quick actions, already exist in OsmAnd." />
</LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/bg_color"
android:gravity="center_vertical"
android:minHeight="66dp">
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/content_padding"
tools:src="@drawable/ic_action_offroad" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
tools:text="OffRoad" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/sub_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
tools:text="Navigation type: Car" />
</LinearLayout>
</LinearLayout>
<include
android:id="@+id/bottom_divider"
layout="@layout/card_bottom_divider"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout>

View file

@ -1,49 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="vertical">
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:minHeight="66dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/bg_color">
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/content_padding"
tools:src="@drawable/ic_action_info_dark" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="66dp">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title_tv"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
tools:text="Quick actions" />
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/content_padding"
tools:src="@drawable/ic_action_info_dark" />
<android.support.v7.widget.AppCompatCheckBox
android:id="@+id/check_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:focusable="false" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="vertical">
</LinearLayout>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
tools:text="Quick actions" />
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/list_divider"
android:visibility="gone"
tools:visibility="visible" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/sub_title_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
android:visibility="gone"
tools:text="description"
tools:visibility="visible" />
</LinearLayout>
<android.support.v7.widget.AppCompatCheckBox
android:id="@+id/check_box"
android:layout_width="wrap_content"
android:focusableInTouchMode="false"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:focusable="false" />
</LinearLayout>
</FrameLayout>
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/list_divider"
android:visibility="gone"
tools:visibility="visible" />
<include
android:id="@+id/card_bottom_divider"
layout="@layout/card_bottom_divider"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout>

View file

@ -1,72 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:minHeight="66dp"
android:orientation="horizontal">
<include
android:id="@+id/card_top_divider"
layout="@layout/card_top_divider"
android:visibility="gone"
tools:visibility="visible" />
<ImageView
android:id="@+id/explist_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/content_padding"
android:src="@drawable/ic_action_arrow_down" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/bg_color">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="66dp"
android:orientation="horizontal">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
tools:text="Quick actions" />
<ImageView
android:id="@+id/explist_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/content_padding"
android:src="@drawable/ic_action_arrow_down" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/sub_text_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
tools:text="8 of 4" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="vertical">
</LinearLayout>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
tools:text="Quick actions" />
<View
android:id="@+id/vertical_divider"
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/content_padding"
android:layout_marginBottom="@dimen/content_padding"
android:background="?attr/list_divider" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/sub_text_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
tools:text="8 of 4" />
<android.support.v7.widget.AppCompatCheckBox
android:id="@+id/check_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/content_padding"
android:focusable="false" />
</LinearLayout>
</LinearLayout>
<View
android:id="@+id/vertical_divider"
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/content_padding"
android:layout_marginBottom="@dimen/content_padding"
android:background="?attr/list_divider" />
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/list_divider"
android:visibility="gone"
tools:visibility="visible" />
<net.osmand.view.ThreeStateCheckbox
android:id="@+id/check_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/content_padding"
android:focusable="false" />
</LinearLayout>
</FrameLayout>
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/list_divider"
android:visibility="gone"
tools:visibility="visible" />
<include
android:id="@+id/card_bottom_divider"
layout="@layout/card_bottom_divider"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout>

View file

@ -163,6 +163,15 @@
<attr name="typeface" format="string|reference"/>
<attr name="textAllCapsCompat" format="reference|boolean" />
</declare-styleable>
<!--<declare-styleable name="ButtonEx" parent="TextViewEx" />
<declare-styleable name="SwitchEx" parent="ButtonEx" />-->
<declare-styleable name="ComplexButton">
<attr name="setText" format="string" />
<attr name="setTextColor" format="color" />
<attr name="setSubText" format="string" />
<attr name="setSubTextColor" format="color" />
<attr name="setIcon" format="reference" />
</declare-styleable>
<!--<declare-styleable name="ButtonEx" parent="TextViewEx" />
<declare-styleable name="SwitchEx" parent="ButtonEx" />-->
</resources>

View file

@ -17,6 +17,19 @@
<string name="recalc_angle_dialog_descr">Extra straight segment between my location and calculated route will be displayed until the route is recalculated</string>
<string name="recalc_angle_dialog_title">Minimum angle between my location and route</string>
<string name="shared_string_app_default_w_val">App Default (%s)</string>
<string name="shared_string_preparing">Preparing</string>
<string name="shared_string_poi_types">POI types</string>
<string name="shared_string_nothing_selected">Nothing selected</string>
<string name="shared_string_quick_actions">Quick actions</string>
<string name="shared_string_profiles">Profiles</string>
<string name="listed_exist">Listed %1$s, already exist in OsmAnd.</string>
<string name="replace_all_desc">Current items will be replaced with items from the file</string>
<string name="replace_all">Replace all</string>
<string name="keep_both">Keep both</string>
<string name="keep_both_desc">Imported items will be added with prexif</string>
<string name="import_duplicates_description">OsmAnd already has elements with the same names as those imported.\n\nSelect an action.</string>
<string name="import_duplicates_title">Some items already exist</string>
<string name="select_data_to_import">Select the data to be imported.</string>
<string name="please_provide_profile_name_message">Please provide a name for the profile</string>
<string name="no_recalculation_setting">Disable recalculation</string>
<string name="open_settings">Open settings</string>

View file

@ -40,6 +40,7 @@ import net.osmand.plus.mapmarkers.MapMarkersDbHelper;
import net.osmand.plus.monitoring.LiveMonitoringHelper;
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
import net.osmand.plus.poi.PoiFiltersHelper;
import net.osmand.plus.quickaction.QuickActionRegistry;
import net.osmand.plus.render.MapRenderRepositories;
import net.osmand.plus.render.NativeOsmandLibrary;
import net.osmand.plus.render.RendererRegistry;
@ -527,6 +528,7 @@ public class AppInitializer implements IProgress {
app.travelDbHelper = startupInit(app.travelDbHelper, TravelDbHelper.class);
app.lockHelper = startupInit(new LockHelper(app), LockHelper.class);
app.settingsHelper = startupInit(new SettingsHelper(app), SettingsHelper.class);
app.quickActionRegistry = startupInit(new QuickActionRegistry(app.getSettings()), QuickActionRegistry.class);
initOpeningHoursParser();

View file

@ -609,6 +609,11 @@ public class ApplicationMode {
}
public String toJson() {
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
return gson.toJson(toModeBean());
}
public ApplicationModeBean toModeBean(){
ApplicationModeBean mb = new ApplicationModeBean();
mb.stringKey = stringKey;
mb.userProfileName = getUserProfileName();
@ -620,8 +625,7 @@ public class ApplicationMode {
mb.locIcon = getLocationIcon();
mb.navIcon = getNavigationIcon();
mb.order = getOrder();
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
return gson.toJson(mb);
return mb;
}
public static void deleteCustomModes(List<ApplicationMode> modes, OsmandApplication app) {
@ -797,25 +801,25 @@ public class ApplicationMode {
}
}
static class ApplicationModeBean {
public static class ApplicationModeBean {
@Expose
String stringKey;
public String stringKey;
@Expose
String userProfileName;
public String userProfileName;
@Expose
String parent;
public String parent;
@Expose
String iconName = "map_world_globe_dark";
public String iconName = "map_world_globe_dark";
@Expose
ProfileIconColors iconColor = ProfileIconColors.DEFAULT;
public ProfileIconColors iconColor = ProfileIconColors.DEFAULT;
@Expose
String routingProfile = null;
public String routingProfile = null;
@Expose
RouteService routeService = RouteService.OSMAND;
public RouteService routeService = RouteService.OSMAND;
@Expose
LocationIcon locIcon = null;
public LocationIcon locIcon = null;
@Expose
NavigationIcon navIcon = null;
public NavigationIcon navIcon = null;
@Expose
int order = -1;
}

View file

@ -59,6 +59,7 @@ import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.mapmarkers.MapMarkersDbHelper;
import net.osmand.plus.monitoring.LiveMonitoringHelper;
import net.osmand.plus.poi.PoiFiltersHelper;
import net.osmand.plus.quickaction.QuickActionRegistry;
import net.osmand.plus.render.RendererRegistry;
import net.osmand.plus.resources.ResourceManager;
import net.osmand.plus.routepreparationmenu.RoutingOptionsHelper;
@ -142,6 +143,7 @@ public class OsmandApplication extends MultiDexApplication {
LockHelper lockHelper;
SettingsHelper settingsHelper;
GpxDbHelper gpxDbHelper;
QuickActionRegistry quickActionRegistry;
private Resources localizedResources;
@ -271,7 +273,10 @@ public class OsmandApplication extends MultiDexApplication {
public OsmAndAppCustomization getAppCustomization() {
return appCustomization;
}
public QuickActionRegistry getQuickActionRegistry() {
return quickActionRegistry;
}
public void setAppCustomization(OsmAndAppCustomization appCustomization) {
this.appCustomization = appCustomization;

View file

@ -107,6 +107,21 @@ public class SQLiteTileSource implements ITileSource {
this.inversiveZoom = inversiveZoom;
}
public SQLiteTileSource(SQLiteTileSource tileSource, String name, OsmandApplication ctx) {
this.ctx = ctx;
this.name = name;
this.urlTemplate = tileSource.getUrlTemplate();
this.maxZoom = tileSource.getMaximumZoomSupported();
this.minZoom = tileSource.getMinimumZoomSupported();
this.isEllipsoid = tileSource.isEllipticYTile();
this.expirationTimeMillis = tileSource.getExpirationTimeMillis();
this.randoms = tileSource.getRandoms();
this.referer = tileSource.getReferer();
this.invertedY = tileSource.isInvertedYTile();
this.timeSupported = tileSource.isTimeSupported();
this.inversiveZoom = tileSource.getInversiveZoom();
}
public void createDataBase() {
db = ctx.getSQLiteAPI().getOrCreateDatabase(
ctx.getAppPath(TILES_INDEX_DIR).getAbsolutePath() + "/" + name + SQLITE_EXT, true);
@ -114,7 +129,6 @@ public class SQLiteTileSource implements ITileSource {
db.execSQL("CREATE TABLE tiles (x int, y int, z int, s int, image blob, time long, PRIMARY KEY (x,y,z,s))");
db.execSQL("CREATE INDEX IND on tiles (x,y,z,s)");
db.execSQL("CREATE TABLE info(tilenumbering,minzoom,maxzoom)");
db.execSQL("CREATE TABLE android_metadata (locale TEXT)");
db.execSQL("INSERT INTO info (tilenumbering,minzoom,maxzoom) VALUES ('simple','" + minZoom + "','" + maxZoom + "');");
addInfoColumn(URL, urlTemplate);
@ -128,7 +142,7 @@ public class SQLiteTileSource implements ITileSource {
db.close();
}
@Override
public int getBitDensity() {
return base != null ? base.getBitDensity() : 16;

View file

@ -2,8 +2,8 @@ package net.osmand.plus;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@ -12,6 +12,7 @@ import android.support.v7.app.AlertDialog;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.map.ITileSource;
import net.osmand.map.TileSourceManager;
@ -20,10 +21,9 @@ import net.osmand.osm.PoiCategory;
import net.osmand.plus.ApplicationMode.ApplicationModeBean;
import net.osmand.plus.ApplicationMode.ApplicationModeBuilder;
import net.osmand.plus.OsmandSettings.OsmandPreference;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.quickaction.QuickAction;
import net.osmand.plus.quickaction.QuickActionFactory;
import net.osmand.plus.quickaction.QuickActionRegistry;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
@ -47,6 +47,7 @@ import java.io.OutputStream;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@ -60,7 +61,6 @@ import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import static net.osmand.IndexConstants.OSMAND_SETTINGS_FILE_EXT;
import static net.osmand.IndexConstants.TILES_INDEX_DIR;
/*
Usage:
@ -153,6 +153,8 @@ public class SettingsHelper {
private SettingsItemType type;
boolean shouldReplace = false;
SettingsItem(@NonNull SettingsItemType type) {
this.type = type;
}
@ -176,10 +178,14 @@ public class SettingsHelper {
@NonNull
public abstract String getFileName();
public Boolean shouldReadOnCollecting() {
public boolean shouldReadOnCollecting() {
return false;
}
public void setShouldReplace(boolean shouldReplace) {
this.shouldReplace = shouldReplace;
}
static SettingsItemType parseItemType(@NonNull JSONObject json) throws IllegalArgumentException, JSONException {
return SettingsItemType.valueOf(json.getString("type"));
}
@ -231,6 +237,35 @@ public class SettingsHelper {
}
}
public abstract static class CollectionSettingsItem<T> extends SettingsItem {
protected List<T> items;
protected List<T> duplicateItems;
protected List<T> existingItems;
CollectionSettingsItem(@NonNull SettingsItemType type, @NonNull List<T> items) {
super(type);
this.items = items;
}
CollectionSettingsItem(@NonNull SettingsItemType type, @NonNull JSONObject json) throws JSONException {
super(type, json);
}
@NonNull
public List<T> getItems() {
return items;
}
@NonNull
public abstract List<T> excludeDuplicateItems();
public abstract boolean isDuplicate(@NonNull T item);
@NonNull
public abstract T renameItem(@NonNull T item);
}
public abstract static class SettingsItemReader<T extends SettingsItem> {
private T item;
@ -423,28 +458,43 @@ public class SettingsHelper {
public static class ProfileSettingsItem extends OsmandSettingsItem {
private OsmandApplication app;
private ApplicationMode appMode;
private ApplicationModeBuilder builder;
private ApplicationModeBean modeBean;
private Set<String> appModeBeanPrefsIds;
public ProfileSettingsItem(@NonNull OsmandSettings settings, @NonNull ApplicationMode appMode) {
super(SettingsItemType.PROFILE, settings);
public ProfileSettingsItem(@NonNull OsmandApplication app, @NonNull ApplicationMode appMode) {
super(SettingsItemType.PROFILE, app.getSettings());
this.app = app;
this.appMode = appMode;
appModeBeanPrefsIds = new HashSet<>(Arrays.asList(settings.appModeBeanPrefsIds));
appModeBeanPrefsIds = new HashSet<>(Arrays.asList(app.getSettings().appModeBeanPrefsIds));
}
public ProfileSettingsItem(@NonNull OsmandSettings settings, @NonNull JSONObject json) throws JSONException {
super(SettingsItemType.PROFILE, settings, json);
readFromJson(settings.getContext(), json);
appModeBeanPrefsIds = new HashSet<>(Arrays.asList(settings.appModeBeanPrefsIds));
public ProfileSettingsItem(@NonNull OsmandApplication app, @NonNull ApplicationModeBean modeBean) {
super(SettingsItemType.PROFILE, app.getSettings());
this.app = app;
this.modeBean = modeBean;
builder = ApplicationMode.fromModeBean(app, modeBean);
appMode = builder.getApplicationMode();
appModeBeanPrefsIds = new HashSet<>(Arrays.asList(app.getSettings().appModeBeanPrefsIds));
}
public ProfileSettingsItem(@NonNull OsmandApplication app, @NonNull JSONObject json) throws JSONException {
super(SettingsItemType.PROFILE, app.getSettings(), json);
this.app = app;
readFromJson(app.getSettings().getContext(), json);
appModeBeanPrefsIds = new HashSet<>(Arrays.asList(app.getSettings().appModeBeanPrefsIds));
}
public ApplicationMode getAppMode() {
return appMode;
}
public ApplicationModeBean getModeBean() {
return modeBean;
}
@NonNull
@Override
public String getName() {
@ -485,11 +535,44 @@ public class SettingsHelper {
return builder != null && ApplicationMode.valueOfStringKey(getName(), null) != null;
}
private void renameProfile() {
int number = 0;
while (true) {
number++;
String key = modeBean.stringKey + "_" + number;
if (ApplicationMode.valueOfStringKey(key, null) == null) {
modeBean.stringKey = key;
modeBean.userProfileName = modeBean.userProfileName + "_" + number;
break;
}
}
}
@Override
public void apply() {
if (appMode.isCustomProfile()) {
appMode = ApplicationMode.saveProfile(builder, getSettings().getContext());
if (!appMode.isCustomProfile() && !shouldReplace) {
ApplicationMode parent = ApplicationMode.valueOfStringKey(modeBean.stringKey, null);
renameProfile();
ApplicationMode.ApplicationModeBuilder builder = ApplicationMode
.createCustomMode(parent, modeBean.stringKey, app)
.setIconResName(modeBean.iconName)
.setUserProfileName(modeBean.userProfileName)
.setRoutingProfile(modeBean.routingProfile)
.setRouteService(modeBean.routeService)
.setIconColor(modeBean.iconColor)
.setLocationIcon(modeBean.locIcon)
.setNavigationIcon(modeBean.navIcon);
app.getSettings().copyPreferencesFromProfile(parent, builder.getApplicationMode());
appMode = ApplicationMode.saveProfile(builder, app);
} else if (!shouldReplace && exists()) {
renameProfile();
builder = ApplicationMode.fromModeBean(app, modeBean);
appMode = ApplicationMode.saveProfile(builder, app);
} else {
builder = ApplicationMode.fromModeBean(app, modeBean);
appMode = ApplicationMode.saveProfile(builder, app);
}
ApplicationMode.changeProfileAvailability(appMode, true, app);
}
@Override
@ -698,13 +781,31 @@ public class SettingsHelper {
return file.exists();
}
private File renameFile(File file) {
int number = 0;
String path = file.getAbsolutePath();
while (true) {
number++;
String copyName = path.replaceAll(file.getName(), file.getName().replaceFirst("[.]", "_" + number + "."));
File copyFile = new File(copyName);
if (!copyFile.exists()) {
return copyFile;
}
}
}
@NonNull
@Override
SettingsItemReader getReader() {
return new StreamSettingsItemReader(this) {
@Override
public void readFromStream(@NonNull InputStream inputStream) throws IOException, IllegalArgumentException {
OutputStream output = new FileOutputStream(file);
OutputStream output;
if (shouldReplace || !file.exists()) {
output = new FileOutputStream(file);
} else {
output = new FileOutputStream(renameFile(file));
}
byte[] buffer = new byte[BUFFER];
int count;
try {
@ -731,49 +832,78 @@ public class SettingsHelper {
}
}
public static class QuickActionSettingsItem extends OsmandSettingsItem {
private List<QuickAction> quickActions;
public static class QuickActionSettingsItem extends CollectionSettingsItem<QuickAction> {
private OsmandApplication app;
private QuickActionRegistry actionRegistry;
public QuickActionSettingsItem(@NonNull OsmandApplication app,
@NonNull List<QuickAction> quickActions) {
super(SettingsItemType.QUICK_ACTION, app.getSettings());
@NonNull List<QuickAction> items) {
super(SettingsItemType.QUICK_ACTION, items);
this.app = app;
this.quickActions = quickActions;
actionRegistry = app.getQuickActionRegistry();
existingItems = actionRegistry.getQuickActions();
}
public QuickActionSettingsItem(@NonNull OsmandApplication app,
@NonNull JSONObject jsonObject) throws JSONException {
super(SettingsItemType.QUICK_ACTION, app.getSettings(), jsonObject);
QuickActionSettingsItem(@NonNull OsmandApplication app,
@NonNull JSONObject json) throws JSONException {
super(SettingsItemType.QUICK_ACTION, json);
this.app = app;
actionRegistry = app.getQuickActionRegistry();
existingItems = actionRegistry.getQuickActions();
}
public List<QuickAction> getQuickActions() {
return quickActions;
@Override
public boolean isDuplicate(@NonNull QuickAction item) {
return !actionRegistry.isNameUnique(item, app);
}
@NonNull
@Override
public QuickAction renameItem(@NonNull QuickAction item) {
return actionRegistry.generateUniqueName(item, app);
}
@NonNull
@Override
public List<QuickAction> excludeDuplicateItems() {
duplicateItems = new ArrayList<>();
for (QuickAction item : items) {
if (isDuplicate(item)) {
duplicateItems.add(item);
}
}
items.removeAll(duplicateItems);
return duplicateItems;
}
@Override
public void apply() {
if (!quickActions.isEmpty()) {
QuickActionFactory factory = new QuickActionFactory();
List<QuickAction> savedActions = factory.parseActiveActionsList(getSettings().QUICK_ACTION_LIST.get());
List<QuickAction> newActions = new ArrayList<>(savedActions);
for (QuickAction action : quickActions) {
for (QuickAction savedAction : savedActions) {
if (action.getName(app).equals(savedAction.getName(app))) {
newActions.remove(savedAction);
if (!items.isEmpty() || !duplicateItems.isEmpty()) {
List<QuickAction> newActions = new ArrayList<>(existingItems);
if (!duplicateItems.isEmpty()) {
if (shouldReplace) {
for (QuickAction duplicateItem : duplicateItems) {
for (QuickAction savedAction : existingItems) {
if (duplicateItem.getName(app).equals(savedAction.getName(app))) {
newActions.remove(savedAction);
}
}
}
} else {
for (QuickAction duplicateItem : duplicateItems) {
renameItem(duplicateItem);
}
}
newActions.addAll(duplicateItems);
}
newActions.addAll(quickActions);
((MapActivity) app.getSettingsHelper().getActivity()).getMapLayers().getQuickActionRegistry().updateQuickActions(newActions);
newActions.addAll(items);
actionRegistry.updateQuickActions(newActions);
}
}
@Override
public Boolean shouldReadOnCollecting() {
public boolean shouldReadOnCollecting() {
return true;
}
@ -798,13 +928,7 @@ public class SettingsHelper {
@NonNull
@Override
SettingsItemReader getReader() {
return new OsmandSettingsItemReader(this, getSettings()) {
@Override
protected void readPreferenceFromJson(@NonNull OsmandPreference<?> preference, @NonNull JSONObject json) throws JSONException {
}
return new SettingsItemReader(this) {
@Override
public void readFromStream(@NonNull InputStream inputStream) throws IOException, IllegalArgumentException {
StringBuilder buf = new StringBuilder();
@ -823,22 +947,24 @@ public class SettingsHelper {
}
final JSONObject json;
try {
quickActions = new ArrayList<>();
items = new ArrayList<>();
Gson gson = new Gson();
Type type = new TypeToken<HashMap<String, String>>() {
}.getType();
json = new JSONObject(jsonStr);
JSONArray items = json.getJSONArray("items");
for (int i = 0; i < items.length(); i++) {
JSONObject object = items.getJSONObject(i);
JSONArray itemsJson = json.getJSONArray("items");
for (int i = 0; i < itemsJson.length(); i++) {
JSONObject object = itemsJson.getJSONObject(i);
String name = object.getString("name");
int actionType = object.getInt("type");
String paramsString = object.getString("params");
HashMap<String, String> params = gson.fromJson(paramsString, type);
QuickAction quickAction = new QuickAction(actionType);
quickAction.setName(name);
if (!name.isEmpty()) {
quickAction.setName(name);
}
quickAction.setParams(params);
quickActions.add(quickAction);
items.add(quickAction);
}
} catch (JSONException e) {
throw new IllegalArgumentException("Json parse error", e);
@ -850,59 +976,115 @@ public class SettingsHelper {
@NonNull
@Override
SettingsItemWriter getWriter() {
return new OsmandSettingsItemWriter(this, getSettings()) {
return new SettingsItemWriter(this) {
@Override
protected void writePreferenceToJson(@NonNull OsmandPreference<?> preference, @NonNull JSONObject json) throws JSONException {
JSONArray items = new JSONArray();
public boolean writeToStream(@NonNull OutputStream outputStream) throws IOException {
JSONObject json = new JSONObject();
JSONArray jsonArray = new JSONArray();
Gson gson = new Gson();
Type type = new TypeToken<HashMap<String, String>>() {
}.getType();
if (!quickActions.isEmpty()) {
for (QuickAction action : quickActions) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", action.getName(app));
jsonObject.put("type", action.getType());
jsonObject.put("params", gson.toJson(action.getParams(), type));
items.put(jsonObject);
if (!items.isEmpty()) {
try {
for (QuickAction action : items) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", action.hasCustomName(app)
? action.getName(app) : "");
jsonObject.put("type", action.getType());
jsonObject.put("params", gson.toJson(action.getParams(), type));
jsonArray.put(jsonObject);
}
json.put("items", jsonArray);
} catch (JSONException e) {
LOG.error("Failed write to json", e);
}
json.put("items", items);
}
if (json.length() > 0) {
try {
String s = json.toString(2);
outputStream.write(s.getBytes("UTF-8"));
} catch (JSONException e) {
LOG.error("Failed to write json to stream", e);
}
return true;
}
return false;
}
};
}
}
public static class PoiUiFilterSettingsItem extends OsmandSettingsItem {
private List<PoiUIFilter> poiUIFilters;
public static class PoiUiFilterSettingsItem extends CollectionSettingsItem<PoiUIFilter> {
private OsmandApplication app;
public PoiUiFilterSettingsItem(OsmandApplication app, List<PoiUIFilter> poiUIFilters) {
super(SettingsItemType.POI_UI_FILTERS, app.getSettings());
public PoiUiFilterSettingsItem(@NonNull OsmandApplication app, @NonNull List<PoiUIFilter> items) {
super(SettingsItemType.POI_UI_FILTERS, items);
this.app = app;
this.poiUIFilters = poiUIFilters;
existingItems = app.getPoiFilters().getUserDefinedPoiFilters(false);
}
public PoiUiFilterSettingsItem(OsmandApplication app, JSONObject jsonObject) throws JSONException {
super(SettingsItemType.POI_UI_FILTERS, app.getSettings(), jsonObject);
PoiUiFilterSettingsItem(@NonNull OsmandApplication app, @NonNull JSONObject json) throws JSONException {
super(SettingsItemType.POI_UI_FILTERS, json);
this.app = app;
}
public List<PoiUIFilter> getPoiUIFilters() {
return this.poiUIFilters != null ? this.poiUIFilters : new ArrayList<PoiUIFilter>();
existingItems = app.getPoiFilters().getUserDefinedPoiFilters(false);
}
@Override
public void apply() {
if (!poiUIFilters.isEmpty()) {
for (PoiUIFilter filter : poiUIFilters) {
if (!items.isEmpty() || !duplicateItems.isEmpty()) {
for (PoiUIFilter duplicate : duplicateItems) {
items.add(shouldReplace ? duplicate : renameItem(duplicate));
}
for (PoiUIFilter filter : items) {
app.getPoiFilters().createPoiFilter(filter, false);
}
app.getSearchUICore().refreshCustomPoiFilters();
}
}
@Override
public boolean isDuplicate(@NonNull PoiUIFilter item) {
String savedName = item.getName();
for (PoiUIFilter filter : existingItems) {
if (filter.getName().equals(savedName)) {
return true;
}
}
return false;
}
@NonNull
@Override
public List<PoiUIFilter> excludeDuplicateItems() {
duplicateItems = new ArrayList<>();
if (!items.isEmpty()) {
for (PoiUIFilter item : items) {
if (isDuplicate(item)) {
duplicateItems.add(item);
}
}
}
items.removeAll(duplicateItems);
return duplicateItems;
}
@NonNull
@Override
public PoiUIFilter renameItem(@NonNull PoiUIFilter item) {
int number = 0;
while (true) {
number++;
PoiUIFilter renamedItem = new PoiUIFilter(item,
item.getName() + "_" + number,
item.getFilterId() + "_" + number);
if (!isDuplicate(renamedItem)) {
return renamedItem;
}
}
}
@NonNull
@Override
public String getName() {
@ -912,11 +1094,11 @@ public class SettingsHelper {
@NonNull
@Override
public String getPublicName(@NonNull Context ctx) {
return null;
return "poi_ui_filters";
}
@Override
public Boolean shouldReadOnCollecting() {
public boolean shouldReadOnCollecting() {
return true;
}
@ -929,12 +1111,7 @@ public class SettingsHelper {
@NonNull
@Override
SettingsItemReader getReader() {
return new OsmandSettingsItemReader(this, getSettings()) {
@Override
protected void readPreferenceFromJson(@NonNull OsmandPreference<?> preference, @NonNull JSONObject json) throws JSONException {
}
return new SettingsItemReader(this) {
@Override
public void readFromStream(@NonNull InputStream inputStream) throws IOException, IllegalArgumentException {
StringBuilder buf = new StringBuilder();
@ -953,15 +1130,15 @@ public class SettingsHelper {
}
final JSONObject json;
try {
poiUIFilters = new ArrayList<>();
items = new ArrayList<>();
json = new JSONObject(jsonStr);
JSONArray items = json.getJSONArray("items");
JSONArray jsonArray = json.getJSONArray("items");
Gson gson = new Gson();
Type type = new TypeToken<HashMap<String, LinkedHashSet<String>>>() {
}.getType();
MapPoiTypes poiTypes = app.getPoiTypes();
for (int i = 0; i < items.length(); i++) {
JSONObject object = items.getJSONObject(i);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject object = jsonArray.getJSONObject(i);
String name = object.getString("name");
String filterId = object.getString("filterId");
String acceptedTypesString = object.getString("acceptedTypes");
@ -972,7 +1149,7 @@ public class SettingsHelper {
acceptedTypesDone.put(a, mapItem.getValue());
}
PoiUIFilter filter = new PoiUIFilter(name, filterId, acceptedTypesDone, app);
poiUIFilters.add(filter);
items.add(filter);
}
} catch (JSONException e) {
throw new IllegalArgumentException("Json parse error", e);
@ -984,62 +1161,149 @@ public class SettingsHelper {
@NonNull
@Override
SettingsItemWriter getWriter() {
return new OsmandSettingsItemWriter(this, getSettings()) {
return new SettingsItemWriter(this) {
@Override
protected void writePreferenceToJson(@NonNull OsmandPreference<?> preference, @NonNull JSONObject json) throws JSONException {
JSONArray items = new JSONArray();
public boolean writeToStream(@NonNull OutputStream outputStream) throws IOException {
JSONObject json = new JSONObject();
JSONArray jsonArray = new JSONArray();
Gson gson = new Gson();
Type type = new TypeToken<HashMap<PoiCategory, LinkedHashSet<String>>>() {
}.getType();
if (!poiUIFilters.isEmpty()) {
for (PoiUIFilter filter : poiUIFilters) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", filter.getName());
jsonObject.put("filterId", filter.getFilterId());
jsonObject.put("acceptedTypes", gson.toJson(filter.getAcceptedTypes(), type));
items.put(jsonObject);
if (!items.isEmpty()) {
try {
for (PoiUIFilter filter : items) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", filter.getName());
jsonObject.put("filterId", filter.getFilterId());
jsonObject.put("acceptedTypes", gson.toJson(filter.getAcceptedTypes(), type));
jsonArray.put(jsonObject);
}
json.put("items", jsonArray);
} catch (JSONException e) {
LOG.error("Failed write to json", e);
}
json.put("items", items);
}
if (json.length() > 0) {
try {
String s = json.toString(2);
outputStream.write(s.getBytes("UTF-8"));
} catch (JSONException e) {
LOG.error("Failed to write json to stream", e);
}
return true;
}
return false;
}
};
}
}
public static class MapSourcesSettingsItem extends OsmandSettingsItem {
public static class MapSourcesSettingsItem extends CollectionSettingsItem<ITileSource> {
private OsmandApplication app;
private List<String> existingItemsNames;
private List<ITileSource> mapSources;
public MapSourcesSettingsItem(OsmandApplication app, List<ITileSource> mapSources) {
super(SettingsItemType.MAP_SOURCES, app.getSettings());
public MapSourcesSettingsItem(@NonNull OsmandApplication app, @NonNull List<ITileSource> items) {
super(SettingsItemType.MAP_SOURCES, items);
this.app = app;
this.mapSources = mapSources;
Collection values = new LinkedHashMap<>(app.getSettings().getTileSourceEntries(true)).values();
existingItemsNames = new ArrayList(values);
}
public MapSourcesSettingsItem(OsmandApplication app, JSONObject jsonObject) throws JSONException {
super(SettingsItemType.MAP_SOURCES, app.getSettings(), jsonObject);
MapSourcesSettingsItem(@NonNull OsmandApplication app, @NonNull JSONObject json) throws JSONException {
super(SettingsItemType.MAP_SOURCES, json);
this.app = app;
}
public List<ITileSource> getMapSources() {
return this.mapSources;
Collection values = new LinkedHashMap<>(app.getSettings().getTileSourceEntries(true)).values();
existingItemsNames = new ArrayList(values);
}
@Override
public void apply() {
if (!mapSources.isEmpty()) {
for (ITileSource template : mapSources) {
if (template instanceof TileSourceManager.TileSourceTemplate) {
getSettings().installTileSource((TileSourceManager.TileSourceTemplate) template);
} else {
((SQLiteTileSource) template).createDataBase();
if (!items.isEmpty() || !duplicateItems.isEmpty()) {
if (shouldReplace) {
for (ITileSource tileSource : duplicateItems) {
if (tileSource instanceof SQLiteTileSource) {
File f = app.getAppPath(IndexConstants.TILES_INDEX_DIR + tileSource.getName() + IndexConstants.SQLITE_EXT);
if (f != null && f.exists()) {
if (f.delete()) {
items.add(tileSource);
}
}
} else if (tileSource instanceof TileSourceManager.TileSourceTemplate) {
File f = app.getAppPath(IndexConstants.TILES_INDEX_DIR + tileSource.getName());
if (f != null && f.exists() && f.isDirectory()) {
if (f.delete()) {
items.add(tileSource);
}
}
}
}
} else {
for (ITileSource tileSource : duplicateItems) {
items.add(renameItem(tileSource));
}
}
for (ITileSource tileSource : items) {
if (tileSource instanceof TileSourceManager.TileSourceTemplate) {
app.getSettings().installTileSource((TileSourceManager.TileSourceTemplate) tileSource);
} else if (tileSource instanceof SQLiteTileSource) {
((SQLiteTileSource) tileSource).createDataBase();
}
}
}
}
@NonNull
@Override
public List<ITileSource> excludeDuplicateItems() {
duplicateItems = new ArrayList<>();
for (String name : existingItemsNames) {
for (ITileSource tileSource : items) {
if (name.equals(tileSource.getName())) {
duplicateItems.add(tileSource);
}
}
}
items.removeAll(duplicateItems);
return duplicateItems;
}
@NonNull
@Override
public ITileSource renameItem(@NonNull ITileSource item) {
int number = 0;
while (true) {
number++;
if (item instanceof SQLiteTileSource) {
SQLiteTileSource oldItem = (SQLiteTileSource) item;
SQLiteTileSource renamedItem = new SQLiteTileSource(
oldItem,
oldItem.getName() + "_" + number,
app);
if (!isDuplicate(renamedItem)) {
return renamedItem;
}
} else if (item instanceof TileSourceManager.TileSourceTemplate) {
TileSourceManager.TileSourceTemplate oldItem = (TileSourceManager.TileSourceTemplate) item;
oldItem.setName(oldItem.getName() + "_" + number);
if (!isDuplicate(oldItem)) {
return oldItem;
}
}
}
}
@Override
public boolean isDuplicate(@NonNull ITileSource item) {
for (String name : existingItemsNames) {
if (name.equals(item.getName())) {
return true;
}
}
return false;
}
@NonNull
@Override
public String getName() {
@ -1049,11 +1313,11 @@ public class SettingsHelper {
@NonNull
@Override
public String getPublicName(@NonNull Context ctx) {
return null;
return "map_sources";
}
@Override
public Boolean shouldReadOnCollecting() {
public boolean shouldReadOnCollecting() {
return true;
}
@ -1066,12 +1330,7 @@ public class SettingsHelper {
@NonNull
@Override
SettingsItemReader getReader() {
return new OsmandSettingsItemReader(this, getSettings()) {
@Override
protected void readPreferenceFromJson(@NonNull OsmandPreference<?> preference, @NonNull JSONObject json) throws JSONException {
}
return new SettingsItemReader(this) {
@Override
public void readFromStream(@NonNull InputStream inputStream) throws IOException, IllegalArgumentException {
StringBuilder buf = new StringBuilder();
@ -1090,11 +1349,11 @@ public class SettingsHelper {
}
final JSONObject json;
try {
mapSources = new ArrayList<>();
items = new ArrayList<>();
json = new JSONObject(jsonStr);
JSONArray items = json.getJSONArray("items");
for (int i = 0; i < items.length(); i++) {
JSONObject object = items.getJSONObject(i);
JSONArray jsonArray = json.getJSONArray("items");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject object = jsonArray.getJSONObject(i);
boolean sql = object.optBoolean("sql");
String name = object.optString("name");
int minZoom = object.optInt("minZoom");
@ -1107,7 +1366,6 @@ public class SettingsHelper {
boolean timesupported = object.optBoolean("timesupported", false);
long expire = object.optLong("expire");
boolean inversiveZoom = object.optBoolean("inversiveZoom", false);
String ext = object.optString("ext");
int tileSize = object.optInt("tileSize");
int bitDensity = object.optInt("bitDensity");
@ -1120,7 +1378,7 @@ public class SettingsHelper {
} else {
template = new SQLiteTileSource(app, name, minZoom, maxZoom, url, randoms, ellipsoid, invertedY, referer, timesupported, expire, inversiveZoom);
}
mapSources.add(template);
items.add(template);
}
} catch (JSONException e) {
throw new IllegalArgumentException("Json parse error", e);
@ -1132,37 +1390,51 @@ public class SettingsHelper {
@NonNull
@Override
SettingsItemWriter getWriter() {
return new OsmandSettingsItemWriter(this, getSettings()) {
return new SettingsItemWriter(this) {
@Override
protected void writePreferenceToJson(@NonNull OsmandPreference<?> preference, @NonNull JSONObject json) throws JSONException {
JSONArray items = new JSONArray();
if (!mapSources.isEmpty()) {
for (ITileSource template : mapSources) {
JSONObject jsonObject = new JSONObject();
boolean sql = template instanceof SQLiteTileSource;
jsonObject.put("sql", sql);
jsonObject.put("name", template.getName());
jsonObject.put("minZoom", template.getMinimumZoomSupported());
jsonObject.put("maxZoom", template.getMaximumZoomSupported());
jsonObject.put("url", template.getUrlTemplate());
jsonObject.put("randoms", template.getRandoms());
jsonObject.put("ellipsoid", template.isEllipticYTile());
jsonObject.put("inverted_y", template.isInvertedYTile());
jsonObject.put("referer", template.getReferer());
jsonObject.put("timesupported", template.isTimeSupported());
jsonObject.put("expire", template.getExpirationTimeMillis());
jsonObject.put("inversiveZoom", template.getInversiveZoom());
public boolean writeToStream(@NonNull OutputStream outputStream) throws IOException {
JSONObject json = new JSONObject();
JSONArray jsonArray = new JSONArray();
if (!items.isEmpty()) {
try {
for (ITileSource template : items) {
JSONObject jsonObject = new JSONObject();
boolean sql = template instanceof SQLiteTileSource;
jsonObject.put("sql", sql);
jsonObject.put("name", template.getName());
jsonObject.put("minZoom", template.getMinimumZoomSupported());
jsonObject.put("maxZoom", template.getMaximumZoomSupported());
jsonObject.put("url", template.getUrlTemplate());
jsonObject.put("randoms", template.getRandoms());
jsonObject.put("ellipsoid", template.isEllipticYTile());
jsonObject.put("inverted_y", template.isInvertedYTile());
jsonObject.put("referer", template.getReferer());
jsonObject.put("timesupported", template.isTimeSupported());
jsonObject.put("expire", template.getExpirationTimeMillis());
jsonObject.put("inversiveZoom", template.getInversiveZoom());
jsonObject.put("ext", template.getTileFormat());
jsonObject.put("tileSize", template.getTileSize());
jsonObject.put("bitDensity", template.getBitDensity());
jsonObject.put("avgSize", template.getAvgSize());
jsonObject.put("rule", template.getRule());
jsonArray.put(jsonObject);
}
json.put("items", jsonArray);
jsonObject.put("ext", template.getTileFormat());
jsonObject.put("tileSize", template.getTileSize());
jsonObject.put("bitDensity", template.getBitDensity());
jsonObject.put("avgSize", template.getAvgSize());
jsonObject.put("rule", template.getRule());
items.put(jsonObject);
} catch (JSONException e) {
LOG.error("Failed write to json", e);
}
json.put("items", items);
}
if (json.length() > 0) {
try {
String s = json.toString(2);
outputStream.write(s.getBytes("UTF-8"));
} catch (JSONException e) {
LOG.error("Failed to write json to stream", e);
}
return true;
}
return false;
}
};
}
@ -1214,7 +1486,7 @@ public class SettingsHelper {
item = new GlobalSettingsItem(settings);
break;
case PROFILE:
item = new ProfileSettingsItem(settings, json);
item = new ProfileSettingsItem(app, json);
break;
case PLUGIN:
break;
@ -1470,60 +1742,12 @@ public class SettingsHelper {
}
importSuspended = false;
if (item != null) {
if (item.exists()) {
switch (item.getType()) {
case PROFILE: {
String title = activity.getString(R.string.overwrite_profile_q, item.getPublicName(app));
dialog = showConfirmDialog(item, title, latestChanges);
break;
}
case FILE:
// overwrite now
acceptItem(item);
break;
default:
acceptItem(item);
break;
}
} else {
if (item.getType() == SettingsItemType.PROFILE && askBeforeImport) {
String title = activity.getString(R.string.add_new_profile_q, item.getPublicName(app));
dialog = showConfirmDialog(item, title, latestChanges);
} else {
acceptItem(item);
}
}
acceptItem(item);
} else {
processNextItem();
}
}
private AlertDialog showConfirmDialog(final SettingsItem item, String title, String message) {
AlertDialog.Builder b = new AlertDialog.Builder(activity);
b.setTitle(title);
b.setMessage(message);
b.setPositiveButton(R.string.shared_string_yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
acceptItem(item);
}
});
b.setNegativeButton(R.string.shared_string_no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
processNextItem();
}
});
b.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
ImportAsyncTask.this.dialog = null;
}
});
b.setCancelable(false);
return b.show();
}
private void suspendImport() {
if (dialog != null) {
dialog.dismiss();
@ -1607,6 +1831,7 @@ public class SettingsHelper {
private SettingsExporter exporter;
private File file;
private SettingsExportListener listener;
private ProgressDialog progress;
ExportAsyncTask(@NonNull File settingsFile,
@Nullable SettingsExportListener listener,
@ -1619,6 +1844,14 @@ public class SettingsHelper {
}
}
@Override
protected void onPreExecute() {
super.onPreExecute();
if (activity != null) {
progress = ProgressDialog.show(activity, app.getString(R.string.export_profile), app.getString(R.string.shared_string_preparing));
}
}
@Override
protected Boolean doInBackground(Void... voids) {
try {
@ -1634,8 +1867,11 @@ public class SettingsHelper {
@Override
protected void onPostExecute(Boolean success) {
if (listener != null) {
listener.onSettingsExportFinished(file, success);
if (activity != null) {
progress.dismiss();
if (listener != null) {
listener.onSettingsExportFinished(file, success);
}
}
}
}

View file

@ -25,6 +25,7 @@ import android.support.v7.view.ContextThemeWrapper;
import android.support.v7.widget.SwitchCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.CompoundButton;
import android.widget.ImageView;
@ -537,4 +538,12 @@ public class UiUtilities {
public static Context getThemedContext(Context context, boolean nightMode, int lightStyle, int darkStyle) {
return new ContextThemeWrapper(context, nightMode ? darkStyle : lightStyle);
}
public static void setMargins(View v, int l, int t, int r, int b) {
if (v.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
p.setMargins(l, t, r, b);
v.requestLayout();
}
}
}

View file

@ -35,7 +35,6 @@ import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.plus.measurementtool.MeasurementToolLayer;
import net.osmand.plus.poi.PoiFiltersHelper;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.quickaction.QuickActionRegistry;
import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin;
import net.osmand.plus.render.MapVectorLayer;
import net.osmand.plus.render.RenderingIcons;
@ -92,7 +91,6 @@ public class MapActivityLayers {
private MapQuickActionLayer mapQuickActionLayer;
private DownloadedRegionsLayer downloadedRegionsLayer;
private MapWidgetRegistry mapWidgetRegistry;
private QuickActionRegistry quickActionRegistry;
private MeasurementToolLayer measurementToolLayer;
private StateChangedListener<Integer> transparencyListener;
@ -100,11 +98,6 @@ public class MapActivityLayers {
public MapActivityLayers(MapActivity activity) {
this.activity = activity;
this.mapWidgetRegistry = new MapWidgetRegistry(activity.getMyApplication());
this.quickActionRegistry = new QuickActionRegistry(activity.getMyApplication().getSettings());
}
public QuickActionRegistry getQuickActionRegistry() {
return quickActionRegistry;
}
public MapWidgetRegistry getMapWidgetRegistry() {

View file

@ -192,7 +192,7 @@ public abstract class MenuBottomSheetDialogFragment extends BottomSheetDialogFra
final View contentView = useScrollableItemsContainer() ? mainView.findViewById(R.id.scroll_view) : itemsContainer;
if (contentView.getHeight() > contentHeight) {
if (useScrollableItemsContainer()) {
if (useScrollableItemsContainer() || useExpandableList()) {
contentView.getLayoutParams().height = contentHeight;
} else {
contentView.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
@ -231,6 +231,10 @@ public abstract class MenuBottomSheetDialogFragment extends BottomSheetDialogFra
return true;
}
protected boolean useExpandableList() {
return false;
}
protected boolean hideButtonsContainer() {
return false;
}

View file

@ -68,7 +68,7 @@ public class SelectMapViewQuickActionsBottomSheet extends MenuBottomSheetDialogF
long id = args.getLong(SwitchableAction.KEY_ID);
OsmandApplication app = mapActivity.getMyApplication();
QuickActionRegistry quickActionRegistry = mapActivity.getMapLayers().getQuickActionRegistry();
QuickActionRegistry quickActionRegistry = app.getQuickActionRegistry();
action = quickActionRegistry.getQuickAction(id);
action = QuickActionFactory.produceAction(action);
if (action == null) {

View file

@ -50,8 +50,8 @@ import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerHalfItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.ShortDescriptionItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
import net.osmand.plus.profiles.ExportImportProfileBottomSheet;
import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin;
import net.osmand.plus.settings.ImportSettingsFragment;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.router.RoutingConfiguration;
import net.osmand.util.Algorithms;
@ -780,11 +780,7 @@ public class ImportHelper {
if (succeed) {
FragmentManager fragmentManager = activity.getSupportFragmentManager();
if (fragmentManager != null) {
ExportImportProfileBottomSheet.showInstance(
fragmentManager,
ExportImportProfileBottomSheet.State.IMPORT,
file,
items);
ImportSettingsFragment.showInstance(fragmentManager, items, file);
}
} else {
app.showShortToastMessage(app.getString(R.string.file_import_error, name, app.getString(R.string.shared_string_unexpected_error)));

View file

@ -125,6 +125,18 @@ public class PoiUIFilter implements SearchPoiTypeFilter, Comparable<PoiUIFilter>
name = app.getPoiFilters().getFiltersName(filtersToMerge);
}
public PoiUIFilter(PoiUIFilter filter, String name, String filterId) {
this.app = filter.app;
this.name = name;
this.filterId = filterId;
isStandardFilter = false;
poiTypes = filter.poiTypes;
acceptedTypes = filter.getAcceptedTypes();
poiAdditionals = filter.getPoiAdditionals();
filterByName = filter.filterByName;
savedFilterByName = filter.savedFilterByName;
}
public boolean isDeleted() {
return deleted;
}

View file

@ -26,6 +26,7 @@ public class AdditionalDataWrapper {
}
public enum Type {
PROFILE,
QUICK_ACTIONS,
POI_TYPES,
MAP_SOURCES,

View file

@ -1,711 +0,0 @@
package net.osmand.plus.profiles;
import android.content.Context;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.CompoundButtonCompat;
import android.support.v7.widget.SwitchCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ExpandableListView;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import net.osmand.AndroidUtils;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.map.ITileSource;
import net.osmand.map.TileSourceManager;
import net.osmand.plus.ApplicationMode;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.SQLiteTileSource;
import net.osmand.plus.SettingsHelper;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.OsmandBaseExpandableListAdapter;
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithCompoundButton;
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription;
import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.quickaction.QuickAction;
import net.osmand.plus.quickaction.QuickActionFactory;
import net.osmand.plus.render.RenderingIcons;
import net.osmand.plus.settings.BaseSettingsFragment;
import net.osmand.plus.settings.bottomsheets.BasePreferenceBottomSheet;
import org.apache.commons.logging.Log;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class ExportImportProfileBottomSheet extends BasePreferenceBottomSheet {
private static final Log LOG = PlatformUtil.getLog(ExportImportProfileBottomSheet.class);
public static final String TAG = ExportImportProfileBottomSheet.class.getSimpleName();
private static final String STATE_KEY = "EXPORT_IMPORT_DIALOG_STATE_KEY";
private static final String INCLUDE_ADDITIONAL_DATA_KEY = "INCLUDE_ADDITIONAL_DATA_KEY";
private boolean includeAdditionalData = false;
private boolean containsAdditionalData = false;
private OsmandApplication app;
private ApplicationMode profile;
private State state;
private List<AdditionalDataWrapper> dataList = new ArrayList<>();
private List<? super Object> dataToOperate = new ArrayList<>();
private List<SettingsHelper.SettingsItem> settingsItems;
private ExpandableListView listView;
private ProfileAdditionalDataAdapter adapter;
private SettingsHelper.ProfileSettingsItem profileSettingsItem;
private File file;
@Override
public void onCreate(Bundle savedInstanceState) {
if (savedInstanceState != null) {
includeAdditionalData = savedInstanceState.getBoolean(INCLUDE_ADDITIONAL_DATA_KEY);
}
super.onCreate(savedInstanceState);
app = requiredMyApplication();
Bundle bundle = getArguments();
if (bundle != null) {
this.state = (State) getArguments().getSerializable(STATE_KEY);
}
if (state == State.IMPORT) {
if (settingsItems == null) {
settingsItems = app.getSettingsHelper().getSettingsItems();
}
if (file == null) {
file = app.getSettingsHelper().getSettingsFile();
}
containsAdditionalData = checkAdditionalDataContains();
} else {
dataList = getAdditionalData();
for (AdditionalDataWrapper dataWrapper : dataList) {
dataToOperate.addAll(dataWrapper.getItems());
}
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(INCLUDE_ADDITIONAL_DATA_KEY, includeAdditionalData);
}
@Override
public void createMenuItems(Bundle savedInstanceState) {
final Context context = getContext();
if (context == null) {
return;
}
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
profile = state == State.IMPORT ? getAppModeFromSettingsItems() : getAppMode();
int profileColor = profile.getIconColorInfo().getColor(nightMode);
int colorNoAlpha = ContextCompat.getColor(context, profileColor);
Drawable backgroundIcon = UiUtilities.getColoredSelectableDrawable(context, colorNoAlpha, 0.3f);
Drawable[] layers = {new ColorDrawable(UiUtilities.getColorWithAlpha(colorNoAlpha, 0.10f)), backgroundIcon};
items.add(new TitleItem(state == State.EXPORT ?
getString(R.string.export_profile)
: getString(R.string.import_profile)));
BaseBottomSheetItem profileItem = new BottomSheetItemWithCompoundButton.Builder()
.setChecked(true)
.setCompoundButtonColorId(profileColor)
.setButtonTintList(ColorStateList.valueOf(getResolvedColor(profileColor)))
.setDescription(BaseSettingsFragment.getAppModeDescription(context, profile))
.setIcon(getIcon(profile.getIconRes(), profileColor))
.setTitle(profile.toHumanString())
.setBackground(new LayerDrawable(layers))
.setLayoutId(R.layout.preference_profile_item_with_radio_btn)
.create();
items.add(profileItem);
if (state == State.IMPORT && containsAdditionalData || state == State.EXPORT && !dataList.isEmpty()) {
BaseBottomSheetItem descriptionItem = new BottomSheetItemWithDescription.Builder()
.setDescription(state == State.EXPORT ?
getString(R.string.export_profile_dialog_description)
: getString(R.string.import_profile_dialog_description))
.setLayoutId(R.layout.bottom_sheet_item_pref_info)
.create();
items.add(descriptionItem);
final View additionalDataView = inflater.inflate(R.layout.bottom_sheet_item_additional_data, null);
listView = additionalDataView.findViewById(R.id.list);
SwitchCompat switchItem = additionalDataView.findViewById(R.id.switchItem);
switchItem.setTextColor(getResources().getColor(nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light));
switchItem.setChecked(includeAdditionalData);
switchItem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
includeAdditionalData = !includeAdditionalData;
listView.setVisibility(includeAdditionalData ?
View.VISIBLE : View.GONE);
if (includeAdditionalData && state == State.IMPORT) {
updateDataToOperateFromSettingsItems();
}
setupHeightAndBackground(getView());
}
});
listView.setVisibility(includeAdditionalData ? View.VISIBLE : View.GONE);
adapter = new ProfileAdditionalDataAdapter(app, dataList, profileColor);
listView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
@Override
public void onGroupExpand(int i) {
setupHeightAndBackground(getView());
}
});
listView.setAdapter(adapter);
final SimpleBottomSheetItem titleItem = (SimpleBottomSheetItem) new SimpleBottomSheetItem.Builder()
.setCustomView(additionalDataView)
.create();
items.add(titleItem);
}
}
@Override
protected int getRightBottomButtonTextId() {
return state == State.EXPORT ? R.string.shared_string_export : R.string.shared_string_import;
}
@Override
protected void onRightBottomButtonClick() {
super.onRightBottomButtonClick();
if (state == State.EXPORT) {
prepareFile();
} else {
importSettings();
}
}
@Override
protected int getDismissButtonTextId() {
return R.string.shared_string_cancel;
}
@Override
protected boolean useScrollableItemsContainer() {
return false;
}
private ApplicationMode getAppModeFromSettingsItems() {
for (SettingsHelper.SettingsItem item : settingsItems) {
if (item.getType().equals(SettingsHelper.SettingsItemType.PROFILE)) {
profileSettingsItem = ((SettingsHelper.ProfileSettingsItem) item);
return ((SettingsHelper.ProfileSettingsItem) item).getAppMode();
}
}
return getAppMode();
}
private List<AdditionalDataWrapper> getAdditionalData() {
List<AdditionalDataWrapper> dataList = new ArrayList<>();
QuickActionFactory factory = new QuickActionFactory();
List<QuickAction> actionsList = factory.parseActiveActionsList(app.getSettings().QUICK_ACTION_LIST.get());
if (!actionsList.isEmpty()) {
dataList.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.QUICK_ACTIONS, actionsList));
}
List<PoiUIFilter> poiList = app.getPoiFilters().getUserDefinedPoiFilters(false);
if (!poiList.isEmpty()) {
dataList.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.POI_TYPES,
poiList
));
}
List<ITileSource> iTileSources = new ArrayList<>();
final LinkedHashMap<String, String> tileSourceEntries = new LinkedHashMap<>(app.getSettings().getTileSourceEntries(true));
for (Map.Entry<String, String> entry : tileSourceEntries.entrySet()) {
File f = app.getAppPath(IndexConstants.TILES_INDEX_DIR + entry.getKey());
if (f != null) {
ITileSource template;
if (f.getName().endsWith(SQLiteTileSource.EXT)) {
template = new SQLiteTileSource(app, f, TileSourceManager.getKnownSourceTemplates());
} else {
template = TileSourceManager.createTileSourceTemplate(f);
}
if (template != null && template.getUrlTemplate() != null) {
iTileSources.add(template);
}
}
}
if (!iTileSources.isEmpty()) {
dataList.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.MAP_SOURCES,
iTileSources
));
}
Map<String, File> externalRenderers = app.getRendererRegistry().getExternalRenderers();
if (!externalRenderers.isEmpty()) {
dataList.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.CUSTOM_RENDER_STYLE,
new ArrayList<>(externalRenderers.values())
));
}
File routingProfilesFolder = app.getAppPath(IndexConstants.ROUTING_PROFILES_DIR);
if (routingProfilesFolder.exists() && routingProfilesFolder.isDirectory()) {
File[] fl = routingProfilesFolder.listFiles();
if (fl != null && fl.length > 0) {
dataList.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.CUSTOM_ROUTING,
Arrays.asList(fl)
));
}
}
return dataList;
}
private List<SettingsHelper.SettingsItem> prepareSettingsItemsForExport() {
List<SettingsHelper.SettingsItem> settingsItems = new ArrayList<>();
settingsItems.add(new SettingsHelper.ProfileSettingsItem(app.getSettings(), profile));
if (includeAdditionalData) {
settingsItems.addAll(prepareAdditionalSettingsItems());
}
return settingsItems;
}
private List<SettingsHelper.SettingsItem> prepareAdditionalSettingsItems() {
List<SettingsHelper.SettingsItem> settingsItems = new ArrayList<>();
List<QuickAction> quickActions = new ArrayList<>();
List<PoiUIFilter> poiUIFilters = new ArrayList<>();
List<ITileSource> tileSourceTemplates = new ArrayList<>();
for (Object object : dataToOperate) {
if (object instanceof QuickAction) {
quickActions.add((QuickAction) object);
} else if (object instanceof PoiUIFilter) {
poiUIFilters.add((PoiUIFilter) object);
} else if (object instanceof TileSourceManager.TileSourceTemplate
|| object instanceof SQLiteTileSource) {
tileSourceTemplates.add((ITileSource) object);
} else if (object instanceof File) {
settingsItems.add(new SettingsHelper.FileSettingsItem(app, (File) object));
}
}
if (!quickActions.isEmpty()) {
settingsItems.add(new SettingsHelper.QuickActionSettingsItem(app, quickActions));
}
if (!poiUIFilters.isEmpty()) {
settingsItems.add(new SettingsHelper.PoiUiFilterSettingsItem(app, poiUIFilters));
}
if (!tileSourceTemplates.isEmpty()) {
settingsItems.add(new SettingsHelper.MapSourcesSettingsItem(app, tileSourceTemplates));
}
return settingsItems;
}
private Boolean checkAdditionalDataContains() {
boolean containsData = false;
for (SettingsHelper.SettingsItem item : settingsItems) {
containsData = item.getType().equals(SettingsHelper.SettingsItemType.QUICK_ACTION)
|| item.getType().equals(SettingsHelper.SettingsItemType.POI_UI_FILTERS)
|| item.getType().equals(SettingsHelper.SettingsItemType.MAP_SOURCES)
|| item.getType().equals(SettingsHelper.SettingsItemType.FILE);
if (containsData) {
break;
}
}
return containsData;
}
private void updateDataToOperateFromSettingsItems() {
List<AdditionalDataWrapper> dataList = new ArrayList<>();
List<QuickAction> quickActions = new ArrayList<>();
List<PoiUIFilter> poiUIFilters = new ArrayList<>();
List<ITileSource> tileSourceTemplates = new ArrayList<>();
List<File> routingFilesList = new ArrayList<>();
List<File> renderFilesList = new ArrayList<>();
for (SettingsHelper.SettingsItem item : settingsItems) {
if (item.getType().equals(SettingsHelper.SettingsItemType.QUICK_ACTION)) {
quickActions.addAll(((SettingsHelper.QuickActionSettingsItem) item).getQuickActions());
} else if (item.getType().equals(SettingsHelper.SettingsItemType.POI_UI_FILTERS)) {
poiUIFilters.addAll(((SettingsHelper.PoiUiFilterSettingsItem) item).getPoiUIFilters());
} else if (item.getType().equals(SettingsHelper.SettingsItemType.MAP_SOURCES)) {
tileSourceTemplates.addAll(((SettingsHelper.MapSourcesSettingsItem) item).getMapSources());
} else if (item.getType().equals(SettingsHelper.SettingsItemType.FILE)) {
if (item.getName().startsWith("/rendering/")) {
renderFilesList.add(((SettingsHelper.FileSettingsItem) item).getFile());
} else if (item.getName().startsWith("/routing/")) {
routingFilesList.add(((SettingsHelper.FileSettingsItem) item).getFile());
}
}
}
if (!quickActions.isEmpty()) {
dataList.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.QUICK_ACTIONS,
quickActions));
dataToOperate.addAll(quickActions);
}
if (!poiUIFilters.isEmpty()) {
dataList.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.POI_TYPES,
poiUIFilters));
dataToOperate.addAll(poiUIFilters);
}
if (!tileSourceTemplates.isEmpty()) {
dataList.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.MAP_SOURCES,
tileSourceTemplates
));
dataToOperate.addAll(tileSourceTemplates);
}
if (!renderFilesList.isEmpty()) {
dataList.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.CUSTOM_RENDER_STYLE,
renderFilesList
));
dataToOperate.addAll(renderFilesList);
}
if (!routingFilesList.isEmpty()) {
dataList.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.CUSTOM_ROUTING,
routingFilesList
));
dataToOperate.addAll(routingFilesList);
}
adapter.updateList(dataList);
}
private void importSettings() {
List<SettingsHelper.SettingsItem> list = new ArrayList<>();
list.add(profileSettingsItem);
if (includeAdditionalData) {
list.addAll(prepareAdditionalSettingsItems());
}
app.getSettingsHelper().importSettings(file, list, "", 1, new SettingsHelper.SettingsImportListener() {
@Override
public void onSettingsImportFinished(boolean succeed, boolean empty, @NonNull List<SettingsHelper.SettingsItem> items) {
if (succeed) {
app.showShortToastMessage(app.getString(R.string.file_imported_successfully, file.getName()));
} else if (empty) {
app.showShortToastMessage(app.getString(R.string.file_import_error, file.getName(), app.getString(R.string.shared_string_unexpected_error)));
}
}
});
dismiss();
}
private void prepareFile() {
if (app != null) {
File tempDir = app.getAppPath(IndexConstants.TEMP_DIR);
if (!tempDir.exists()) {
tempDir.mkdirs();
}
String fileName = profile.toHumanString();
app.getSettingsHelper().exportSettings(tempDir, fileName, new SettingsHelper.SettingsExportListener() {
@Override
public void onSettingsExportFinished(@NonNull File file, boolean succeed) {
if (succeed) {
shareProfile(file, profile);
} else {
app.showToastMessage(R.string.export_profile_failed);
}
}
}, prepareSettingsItemsForExport());
}
}
private void shareProfile(@NonNull File file, @NonNull ApplicationMode profile) {
try {
final Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.exported_osmand_profile, profile.toHumanString()));
sendIntent.putExtra(Intent.EXTRA_STREAM, AndroidUtils.getUriForFile(getMyApplication(), file));
sendIntent.setType("*/*");
sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(sendIntent);
dismiss();
} catch (Exception e) {
Toast.makeText(requireContext(), R.string.export_profile_failed, Toast.LENGTH_SHORT).show();
LOG.error("Share profile error", e);
}
}
public static boolean showInstance(@NonNull FragmentManager fragmentManager,
State state,
Fragment target,
@NonNull ApplicationMode appMode) {
try {
Bundle bundle = new Bundle();
bundle.putSerializable(STATE_KEY, state);
ExportImportProfileBottomSheet fragment = new ExportImportProfileBottomSheet();
fragment.setArguments(bundle);
fragment.setAppMode(appMode);
fragment.setTargetFragment(target, 0);
fragment.show(fragmentManager, TAG);
return true;
} catch (RuntimeException e) {
return false;
}
}
public static boolean showInstance(@NonNull FragmentManager fragmentManager,
State state,
File file,
List<SettingsHelper.SettingsItem> items) {
try {
Bundle bundle = new Bundle();
bundle.putSerializable(STATE_KEY, state);
ExportImportProfileBottomSheet fragment = new ExportImportProfileBottomSheet();
fragment.setArguments(bundle);
fragment.setSettingsItems(items);
fragment.setFile(file);
fragment.show(fragmentManager, TAG);
return true;
} catch (RuntimeException e) {
return false;
}
}
public void setSettingsItems(List<SettingsHelper.SettingsItem> settingsItems) {
this.settingsItems = settingsItems;
}
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
public enum State {
EXPORT,
IMPORT
}
class ProfileAdditionalDataAdapter extends OsmandBaseExpandableListAdapter {
private OsmandApplication app;
private List<AdditionalDataWrapper> list;
private int profileColor;
ProfileAdditionalDataAdapter(OsmandApplication app, List<AdditionalDataWrapper> list, int profileColor) {
this.app = app;
this.list = list;
this.profileColor = profileColor;
}
public void updateList(List<AdditionalDataWrapper> list) {
this.list = list;
notifyDataSetChanged();
}
@Override
public int getGroupCount() {
return list.size();
}
@Override
public int getChildrenCount(int i) {
return list.get(i).getItems().size();
}
@Override
public Object getGroup(int i) {
return list.get(i);
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return list.get(groupPosition).getItems().get(childPosition);
}
@Override
public long getGroupId(int i) {
return i;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return groupPosition * 10000 + childPosition;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
View group = convertView;
if (group == null) {
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
group = inflater.inflate(R.layout.profile_data_list_item_group, parent, false);
}
boolean isLastGroup = groupPosition == getGroupCount() - 1;
final AdditionalDataWrapper.Type type = list.get(groupPosition).getType();
TextView titleTv = group.findViewById(R.id.title_tv);
TextView subTextTv = group.findViewById(R.id.sub_text_tv);
final CheckBox checkBox = group.findViewById(R.id.check_box);
ImageView expandIv = group.findViewById(R.id.explist_indicator);
View divider = group.findViewById(R.id.divider);
titleTv.setText(getGroupTitle(type));
divider.setVisibility(isExpanded || isLastGroup ? View.GONE : View.VISIBLE);
CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, profileColor)));
final List<?> listItems = list.get(groupPosition).getItems();
subTextTv.setText(String.valueOf(listItems.size()));
checkBox.setChecked(dataToOperate.containsAll(listItems));
checkBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (checkBox.isChecked()) {
for (Object object : listItems) {
if (!dataToOperate.contains(object)) {
dataToOperate.add(object);
}
}
} else {
dataToOperate.removeAll(listItems);
}
notifyDataSetInvalidated();
}
});
adjustIndicator(app, groupPosition, isExpanded, group, true);
return group;
}
@Override
public View getChildView(int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
View child = convertView;
if (child == null) {
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
child = inflater.inflate(R.layout.profile_data_list_item_child, parent, false);
}
final Object currentItem = list.get(groupPosition).getItems().get(childPosition);
boolean isLastGroup = groupPosition == getGroupCount() - 1;
final AdditionalDataWrapper.Type type = list.get(groupPosition).getType();
TextView title = child.findViewById(R.id.title_tv);
final CheckBox checkBox = child.findViewById(R.id.check_box);
ImageView icon = child.findViewById(R.id.icon);
View divider = child.findViewById(R.id.divider);
divider.setVisibility(isLastChild && !isLastGroup ? View.VISIBLE : View.GONE);
CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, profileColor)));
checkBox.setChecked(dataToOperate.contains(currentItem));
checkBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (checkBox.isChecked()) {
dataToOperate.add(currentItem);
} else {
dataToOperate.remove(currentItem);
}
notifyDataSetInvalidated();
}
});
switch (type) {
case QUICK_ACTIONS:
title.setText(((QuickAction) currentItem).getName(app.getApplicationContext()));
icon.setVisibility(View.INVISIBLE);
icon.setImageResource(R.drawable.ic_action_info_dark);
break;
case POI_TYPES:
title.setText(((PoiUIFilter) currentItem).getName());
icon.setVisibility(View.VISIBLE);
int iconRes = RenderingIcons.getBigIconResourceId(((PoiUIFilter) currentItem).getIconId());
icon.setImageDrawable(app.getUIUtilities().getIcon(iconRes != 0 ? iconRes : R.drawable.ic_person, profileColor));
break;
case MAP_SOURCES:
title.setText(((ITileSource) currentItem).getName());
icon.setVisibility(View.INVISIBLE);
icon.setImageResource(R.drawable.ic_action_info_dark);
break;
case CUSTOM_RENDER_STYLE:
String renderName = ((File) currentItem).getName();
renderName = renderName.replace('_', ' ').replaceAll(".render.xml", "");
title.setText(renderName);
icon.setVisibility(View.INVISIBLE);
icon.setImageResource(R.drawable.ic_action_info_dark);
break;
case CUSTOM_ROUTING:
String routingName = ((File) currentItem).getName();
routingName = routingName.replace('_', ' ').replaceAll(".xml", "");
title.setText(routingName);
icon.setVisibility(View.INVISIBLE);
icon.setImageResource(R.drawable.ic_action_info_dark);
break;
default:
return child;
}
return child;
}
@Override
public boolean isChildSelectable(int i, int i1) {
return false;
}
private int getGroupTitle(AdditionalDataWrapper.Type type) {
switch (type) {
case QUICK_ACTIONS:
return R.string.configure_screen_quick_action;
case POI_TYPES:
return R.string.poi_dialog_poi_type;
case MAP_SOURCES:
return R.string.quick_action_map_source_title;
case CUSTOM_RENDER_STYLE:
return R.string.shared_string_custom_rendering_style;
case CUSTOM_ROUTING:
return R.string.shared_string_routing;
default:
return R.string.access_empty_list;
}
}
}
}

View file

@ -49,7 +49,7 @@ public class AddQuickActionDialog extends DialogFragment {
getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
List<QuickAction> active = ((MapActivity) getActivity())
.getMapLayers()
.getMyApplication()
.getQuickActionRegistry()
.getQuickActions();

View file

@ -106,7 +106,7 @@ public class CreateEditActionDialog extends DialogFragment {
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
quickActionRegistry = ((MapActivity) getActivity()).getMapLayers().getQuickActionRegistry();
quickActionRegistry = getApplication().getQuickActionRegistry();
long actionId = savedInstanceState == null
? getArguments().getLong(KEY_ACTION_ID)

View file

@ -157,5 +157,8 @@ public class QuickAction {
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
}
public boolean hasCustomName(Context context) {
return !getName(context).equals(context.getString(nameRes));
}
}

View file

@ -86,7 +86,7 @@ public class QuickActionListFragment extends BaseOsmAndFragment implements Quick
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
quickActionRegistry = getMapActivity().getMapLayers().getQuickActionRegistry();
quickActionRegistry = getMyApplication().getQuickActionRegistry();
setUpToolbar(view);
setUpQuickActionRV();

View file

@ -28,20 +28,16 @@ import android.widget.TextView;
import android.widget.Toast;
import net.osmand.AndroidUtils;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.plus.ApplicationMode;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.SettingsHelper;
import net.osmand.plus.SettingsHelper.ProfileSettingsItem;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.FontCache;
import net.osmand.plus.openseamapsplugin.NauticalMapsPlugin;
import net.osmand.plus.profiles.ExportImportProfileBottomSheet;
import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet;
import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet.CopyAppModePrefsListener;
import net.osmand.plus.settings.bottomsheets.ResetProfilePrefsBottomSheet;
@ -403,9 +399,8 @@ public class ConfigureProfileFragment extends BaseSettingsFragment implements Co
} else if (EXPORT_PROFILE.equals(prefId)) {
FragmentManager fragmentManager = getFragmentManager();
if (fragmentManager != null) {
ExportImportProfileBottomSheet.showInstance(
ExportProfileBottomSheet.showInstance(
fragmentManager,
ExportImportProfileBottomSheet.State.EXPORT,
this,
getSelectedAppMode());
}

View file

@ -0,0 +1,177 @@
package net.osmand.plus.settings;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import net.osmand.AndroidUtils;
import net.osmand.map.ITileSource;
import net.osmand.plus.ApplicationMode;
import net.osmand.plus.ApplicationMode.ApplicationModeBean;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.profiles.ProfileIconColors;
import net.osmand.plus.quickaction.QuickAction;
import net.osmand.plus.render.RenderingIcons;
import net.osmand.util.Algorithms;
import java.io.File;
import java.util.List;
public class DuplicatesSettingsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int HEADER_TYPE = 0;
private static final int ITEM_TYPE = 1;
private boolean nightMode;
private OsmandApplication app;
private UiUtilities uiUtilities;
private List<? super Object> items;
DuplicatesSettingsAdapter(OsmandApplication app, List<? super Object> items, boolean nightMode) {
this.app = app;
this.items = items;
this.nightMode = nightMode;
this.uiUtilities = app.getUIUtilities();
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(app);
if (viewType == HEADER_TYPE) {
View view = inflater.inflate(R.layout.list_item_header_import, parent, false);
return new HeaderViewHolder(view);
} else {
View view = inflater.inflate(R.layout.list_item_import, parent, false);
return new ItemViewHolder(view);
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
Object currentItem = items.get(position);
if (holder instanceof HeaderViewHolder) {
HeaderViewHolder headerHolder = (HeaderViewHolder) holder;
headerHolder.title.setText((String) currentItem);
headerHolder.subTitle.setText(String.format(
app.getString(R.string.listed_exist),
(String) currentItem));
headerHolder.divider.setVisibility(View.VISIBLE);
} else if (holder instanceof ItemViewHolder) {
ItemViewHolder itemHolder = (ItemViewHolder) holder;
if (currentItem instanceof ApplicationModeBean) {
ApplicationModeBean modeBean = (ApplicationModeBean) currentItem;
String profileName = modeBean.userProfileName;
if (Algorithms.isEmpty(profileName)) {
ApplicationMode appMode = ApplicationMode.valueOfStringKey(modeBean.stringKey, null);
profileName = app.getString(appMode.getNameKeyResource());
}
itemHolder.title.setText(profileName);
String routingProfile = modeBean.routingProfile;
if (Algorithms.isEmpty(routingProfile)) {
itemHolder.subTitle.setVisibility(View.GONE);
} else {
itemHolder.subTitle.setText(String.format(
app.getString(R.string.ltr_or_rtl_combine_via_colon),
app.getString(R.string.nav_type_hint),
routingProfile));
itemHolder.subTitle.setVisibility(View.VISIBLE);
}
int profileIconRes = AndroidUtils.getDrawableId(app, modeBean.iconName);
ProfileIconColors iconColor = modeBean.iconColor;
itemHolder.icon.setImageDrawable(uiUtilities.getIcon(profileIconRes, iconColor.getColor(nightMode)));
itemHolder.icon.setVisibility(View.VISIBLE);
} else if (currentItem instanceof QuickAction) {
QuickAction action = (QuickAction) currentItem;
itemHolder.title.setText(action.getName(app));
itemHolder.icon.setImageDrawable(uiUtilities.getIcon(action.getIconRes(), nightMode));
itemHolder.subTitle.setVisibility(View.GONE);
itemHolder.icon.setVisibility(View.VISIBLE);
} else if (currentItem instanceof PoiUIFilter) {
PoiUIFilter filter = (PoiUIFilter) currentItem;
itemHolder.title.setText(filter.getName());
int iconRes = RenderingIcons.getBigIconResourceId(filter.getIconId());
itemHolder.icon.setImageDrawable(uiUtilities.getIcon(iconRes != 0 ? iconRes : R.drawable.ic_person, nightMode));
itemHolder.subTitle.setVisibility(View.GONE);
itemHolder.icon.setVisibility(View.VISIBLE);
} else if (currentItem instanceof ITileSource) {
itemHolder.title.setText(((ITileSource) currentItem).getName());
itemHolder.icon.setImageResource(R.drawable.ic_action_info_dark);
itemHolder.subTitle.setVisibility(View.GONE);
itemHolder.icon.setVisibility(View.INVISIBLE);
} else if (currentItem instanceof File) {
File file = (File) currentItem;
itemHolder.title.setText(file.getName());
if (file.getName().contains("/rendering/")) {
itemHolder.icon.setImageDrawable(uiUtilities.getIcon(R.drawable.ic_action_map_style, nightMode));
itemHolder.icon.setVisibility(View.VISIBLE);
} else {
itemHolder.icon.setImageResource(R.drawable.ic_action_info_dark);
itemHolder.icon.setVisibility(View.INVISIBLE);
}
itemHolder.subTitle.setVisibility(View.GONE);
}
itemHolder.divider.setVisibility(shouldShowDivider(position) ? View.VISIBLE : View.GONE);
}
}
@Override
public int getItemCount() {
return items.size();
}
@Override
public int getItemViewType(int position) {
if (items.get(position) instanceof String) {
return HEADER_TYPE;
} else {
return ITEM_TYPE;
}
}
private class HeaderViewHolder extends RecyclerView.ViewHolder {
TextView title;
TextView subTitle;
View divider;
HeaderViewHolder(View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
subTitle = itemView.findViewById(R.id.sub_title);
divider = itemView.findViewById(R.id.top_divider);
}
}
private class ItemViewHolder extends RecyclerView.ViewHolder {
TextView title;
TextView subTitle;
ImageView icon;
View divider;
ItemViewHolder(View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
subTitle = itemView.findViewById(R.id.sub_title);
icon = itemView.findViewById(R.id.icon);
divider = itemView.findViewById(R.id.bottom_divider);
}
}
private boolean shouldShowDivider(int position) {
boolean isLast = position == items.size() - 1;
if (isLast) {
return true;
} else {
Object next = items.get(position + 1);
return next instanceof String;
}
}
}

View file

@ -0,0 +1,304 @@
package net.osmand.plus.settings;
import android.content.res.ColorStateList;
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.CompoundButtonCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import net.osmand.AndroidUtils;
import net.osmand.map.ITileSource;
import net.osmand.plus.ApplicationMode;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.OsmandBaseExpandableListAdapter;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.profiles.AdditionalDataWrapper;
import net.osmand.plus.profiles.ProfileIconColors;
import net.osmand.plus.quickaction.QuickAction;
import net.osmand.plus.render.RenderingIcons;
import net.osmand.util.Algorithms;
import net.osmand.view.ThreeStateCheckbox;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import static net.osmand.view.ThreeStateCheckbox.State.CHECKED;
import static net.osmand.view.ThreeStateCheckbox.State.UNCHECKED;
import static net.osmand.view.ThreeStateCheckbox.State.MISC;
class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter {
private OsmandApplication app;
private List<? super Object> dataToOperate;
private List<AdditionalDataWrapper> dataList;
private boolean nightMode;
private boolean importState;
private int profileColor;
ExportImportSettingsAdapter(OsmandApplication app, List<AdditionalDataWrapper> dataList, boolean nightMode, boolean importState) {
this.app = app;
this.dataList = dataList;
this.nightMode = nightMode;
this.importState = importState;
this.dataToOperate = new ArrayList<>();
this.profileColor = app.getSettings().getApplicationMode().getIconColorInfo().getColor(nightMode);
}
ExportImportSettingsAdapter(OsmandApplication app, boolean nightMode) {
this.app = app;
this.nightMode = nightMode;
this.dataList = new ArrayList<>();
this.dataToOperate = new ArrayList<>();
this.profileColor = app.getSettings().getApplicationMode().getIconColorInfo().getColor(nightMode);
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
View group = convertView;
if (group == null) {
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
group = inflater.inflate(R.layout.profile_data_list_item_group, parent, false);
}
boolean isLastGroup = groupPosition == getGroupCount() - 1;
final AdditionalDataWrapper.Type type = dataList.get(groupPosition).getType();
TextView titleTv = group.findViewById(R.id.title_tv);
TextView subTextTv = group.findViewById(R.id.sub_text_tv);
final ThreeStateCheckbox checkBox = group.findViewById(R.id.check_box);
ImageView expandIv = group.findViewById(R.id.explist_indicator);
View lineDivider = group.findViewById(R.id.divider);
View cardTopDivider = group.findViewById(R.id.card_top_divider);
View cardBottomDivider = group.findViewById(R.id.card_bottom_divider);
titleTv.setText(getGroupTitle(type));
lineDivider.setVisibility(importState || isExpanded || isLastGroup ? View.GONE : View.VISIBLE);
cardTopDivider.setVisibility(importState ? View.VISIBLE : View.GONE);
cardBottomDivider.setVisibility(importState && !isExpanded ? View.VISIBLE : View.GONE);
CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, profileColor)));
final List<?> listItems = dataList.get(groupPosition).getItems();
subTextTv.setText(String.valueOf(listItems.size()));
if (dataToOperate.containsAll(listItems)) {
checkBox.setState(CHECKED);
} else {
boolean contains = false;
for (Object object : listItems) {
if (dataToOperate.contains(object)) {
contains = true;
break;
}
}
checkBox.setState(contains ? MISC : UNCHECKED);
}
checkBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (checkBox.getState() == CHECKED) {
for (Object object : listItems) {
if (!dataToOperate.contains(object)) {
dataToOperate.add(object);
}
}
} else {
dataToOperate.removeAll(listItems);
}
notifyDataSetChanged();
}
});
adjustIndicator(app, groupPosition, isExpanded, group, true);
return group;
}
@Override
public View getChildView(int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
View child = convertView;
if (child == null) {
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
child = inflater.inflate(R.layout.profile_data_list_item_child, parent, false);
}
final Object currentItem = dataList.get(groupPosition).getItems().get(childPosition);
boolean isLastGroup = groupPosition == getGroupCount() - 1;
final AdditionalDataWrapper.Type type = dataList.get(groupPosition).getType();
TextView title = child.findViewById(R.id.title_tv);
TextView subText = child.findViewById(R.id.sub_title_tv);
final CheckBox checkBox = child.findViewById(R.id.check_box);
ImageView icon = child.findViewById(R.id.icon);
View lineDivider = child.findViewById(R.id.divider);
View cardBottomDivider = child.findViewById(R.id.card_bottom_divider);
lineDivider.setVisibility(!importState && isLastChild && !isLastGroup ? View.VISIBLE : View.GONE);
cardBottomDivider.setVisibility(importState && isLastChild ? View.VISIBLE : View.GONE);
CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, profileColor)));
checkBox.setChecked(dataToOperate.contains(currentItem));
checkBox.setClickable(false);
child.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (dataToOperate.contains(currentItem)) {
dataToOperate.remove(currentItem);
} else {
dataToOperate.add(currentItem);
}
notifyDataSetChanged();
}
});
switch (type) {
case PROFILE:
String profileName = ((ApplicationMode.ApplicationModeBean) currentItem).userProfileName;
if (Algorithms.isEmpty(profileName)) {
ApplicationMode appMode = ApplicationMode.valueOfStringKey(((ApplicationMode.ApplicationModeBean) currentItem).stringKey, null);
profileName = app.getString(appMode.getNameKeyResource());
}
title.setText(profileName);
String routingProfile = (((ApplicationMode.ApplicationModeBean) currentItem).routingProfile);
if (Algorithms.isEmpty(routingProfile)) {
subText.setVisibility(View.GONE);
} else {
subText.setText(String.format(
app.getString(R.string.ltr_or_rtl_combine_via_colon),
app.getString(R.string.nav_type_hint),
routingProfile));
subText.setVisibility(View.VISIBLE);
}
int profileIconRes = AndroidUtils.getDrawableId(app, ((ApplicationMode.ApplicationModeBean) currentItem).iconName);
ProfileIconColors iconColor = ((ApplicationMode.ApplicationModeBean) currentItem).iconColor;
icon.setImageDrawable(app.getUIUtilities().getIcon(profileIconRes, iconColor.getColor(nightMode)));
icon.setVisibility(View.VISIBLE);
break;
case QUICK_ACTIONS:
title.setText(((QuickAction) currentItem).getName(app.getApplicationContext()));
icon.setImageDrawable(app.getUIUtilities().getIcon(((QuickAction) currentItem).getIconRes(), nightMode));
subText.setVisibility(View.GONE);
icon.setVisibility(View.VISIBLE);
break;
case POI_TYPES:
title.setText(((PoiUIFilter) currentItem).getName());
int iconRes = RenderingIcons.getBigIconResourceId(((PoiUIFilter) currentItem).getIconId());
icon.setImageDrawable(app.getUIUtilities().getIcon(iconRes != 0 ? iconRes : R.drawable.ic_person, profileColor));
subText.setVisibility(View.GONE);
icon.setVisibility(View.VISIBLE);
break;
case MAP_SOURCES:
title.setText(((ITileSource) currentItem).getName());
icon.setImageResource(R.drawable.ic_action_info_dark);
subText.setVisibility(View.GONE);
icon.setVisibility(View.INVISIBLE);
break;
case CUSTOM_RENDER_STYLE:
String renderName = ((File) currentItem).getName();
renderName = renderName.replace('_', ' ').replaceAll(".render.xml", "");
title.setText(renderName);
icon.setImageResource(R.drawable.ic_action_info_dark);
icon.setVisibility(View.INVISIBLE);
subText.setVisibility(View.GONE);
break;
case CUSTOM_ROUTING:
String routingName = ((File) currentItem).getName();
routingName = routingName.replace('_', ' ').replaceAll(".xml", "");
title.setText(routingName);
icon.setImageResource(R.drawable.ic_action_map_style);
icon.setVisibility(View.VISIBLE);
subText.setVisibility(View.GONE);
break;
default:
return child;
}
return child;
}
@Override
public int getGroupCount() {
return dataList.size();
}
@Override
public int getChildrenCount(int i) {
return dataList.get(i).getItems().size();
}
@Override
public Object getGroup(int i) {
return dataList.get(i);
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return dataList.get(groupPosition).getItems().get(childPosition);
}
@Override
public long getGroupId(int i) {
return i;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return groupPosition * 10000 + childPosition;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public boolean isChildSelectable(int i, int i1) {
return true;
}
private int getGroupTitle(AdditionalDataWrapper.Type type) {
switch (type) {
case PROFILE:
return R.string.shared_string_profiles;
case QUICK_ACTIONS:
return R.string.configure_screen_quick_action;
case POI_TYPES:
return R.string.poi_dialog_poi_type;
case MAP_SOURCES:
return R.string.quick_action_map_source_title;
case CUSTOM_RENDER_STYLE:
return R.string.shared_string_custom_rendering_style;
case CUSTOM_ROUTING:
return R.string.shared_string_routing;
default:
return R.string.access_empty_list;
}
}
public void updateSettingsList(List<AdditionalDataWrapper> settingsList) {
this.dataList = settingsList;
notifyDataSetChanged();
}
public void clearSettingsList() {
this.dataList.clear();
notifyDataSetChanged();
}
public void selectAll(boolean selectAll) {
dataToOperate.clear();
if (selectAll) {
for (AdditionalDataWrapper item : dataList) {
dataToOperate.addAll(item.getItems());
}
}
notifyDataSetChanged();
}
List<? super Object> getDataToOperate() {
return this.dataToOperate;
}
}

View file

@ -0,0 +1,338 @@
package net.osmand.plus.settings;
import android.content.Context;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.SwitchCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ExpandableListView;
import android.widget.LinearLayout.LayoutParams;
import android.widget.Toast;
import net.osmand.AndroidUtils;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.map.ITileSource;
import net.osmand.map.TileSourceManager;
import net.osmand.plus.ApplicationMode;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.SQLiteTileSource;
import net.osmand.plus.SettingsHelper;
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.SimpleBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.profiles.AdditionalDataWrapper;
import net.osmand.plus.quickaction.QuickAction;
import net.osmand.plus.quickaction.QuickActionFactory;
import net.osmand.plus.settings.bottomsheets.BasePreferenceBottomSheet;
import org.apache.commons.logging.Log;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class ExportProfileBottomSheet extends BasePreferenceBottomSheet {
private static final Log LOG = PlatformUtil.getLog(ExportProfileBottomSheet.class);
public static final String TAG = ExportProfileBottomSheet.class.getSimpleName();
private static final String INCLUDE_ADDITIONAL_DATA_KEY = "INCLUDE_ADDITIONAL_DATA_KEY";
private boolean includeAdditionalData = false;
private OsmandApplication app;
private ApplicationMode profile;
private List<AdditionalDataWrapper> dataList = new ArrayList<>();
private ExportImportSettingsAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
if (savedInstanceState != null) {
includeAdditionalData = savedInstanceState.getBoolean(INCLUDE_ADDITIONAL_DATA_KEY);
}
super.onCreate(savedInstanceState);
app = requiredMyApplication();
dataList = getAdditionalData();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(INCLUDE_ADDITIONAL_DATA_KEY, includeAdditionalData);
}
@Override
public void createMenuItems(Bundle savedInstanceState) {
final Context context = getContext();
if (context == null) {
return;
}
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
profile = getAppMode();
int profileColor = profile.getIconColorInfo().getColor(nightMode);
int colorNoAlpha = ContextCompat.getColor(context, profileColor);
Drawable backgroundIcon = UiUtilities.getColoredSelectableDrawable(context, colorNoAlpha, 0.3f);
Drawable[] layers = {new ColorDrawable(UiUtilities.getColorWithAlpha(colorNoAlpha, 0.10f)), backgroundIcon};
items.add(new TitleItem(getString(R.string.export_profile)));
BaseBottomSheetItem profileItem = new BottomSheetItemWithCompoundButton.Builder()
.setChecked(true)
.setCompoundButtonColorId(profileColor)
.setButtonTintList(ColorStateList.valueOf(getResolvedColor(profileColor)))
.setDescription(BaseSettingsFragment.getAppModeDescription(context, profile))
.setIcon(getIcon(profile.getIconRes(), profileColor))
.setTitle(profile.toHumanString())
.setBackground(new LayerDrawable(layers))
.setLayoutId(R.layout.preference_profile_item_with_radio_btn)
.create();
items.add(profileItem);
if (!dataList.isEmpty()) {
final View additionalDataView = inflater.inflate(R.layout.bottom_sheet_item_additional_data, null);
ExpandableListView listView = additionalDataView.findViewById(R.id.list);
adapter = new ExportImportSettingsAdapter(app, nightMode);
View listHeader = inflater.inflate(R.layout.item_header_export_expand_list, null);
final View topSwitchDivider = listHeader.findViewById(R.id.topSwitchDivider);
final View bottomSwitchDivider = listHeader.findViewById(R.id.bottomSwitchDivider);
final SwitchCompat switchItem = listHeader.findViewById(R.id.switchItem);
switchItem.setTextColor(getResources().getColor(nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light));
switchItem.setChecked(includeAdditionalData);
switchItem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
includeAdditionalData = !includeAdditionalData;
topSwitchDivider.setVisibility(includeAdditionalData ? View.VISIBLE : View.GONE);
bottomSwitchDivider.setVisibility(includeAdditionalData ? View.VISIBLE : View.GONE);
if (includeAdditionalData) {
adapter.updateSettingsList(getAdditionalData());
adapter.selectAll(true);
} else {
adapter.selectAll(false);
adapter.clearSettingsList();
}
updateSwitch(switchItem);
setupHeightAndBackground(getView());
}
});
listView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
@Override
public void onGroupExpand(int i) {
setupHeightAndBackground(getView());
}
});
updateSwitch(switchItem);
listView.addHeaderView(listHeader);
listView.setAdapter(adapter);
final SimpleBottomSheetItem titleItem = (SimpleBottomSheetItem) new SimpleBottomSheetItem.Builder()
.setCustomView(additionalDataView)
.create();
items.add(titleItem);
}
}
private void updateSwitch(View view) {
if (includeAdditionalData) {
UiUtilities.setMargins(view, 0, 0, 0, 0);
view.setPadding(AndroidUtils.dpToPx(app, 32), 0, AndroidUtils.dpToPx(app, 32), 0);
} else {
UiUtilities.setMargins(view, AndroidUtils.dpToPx(app, 16), 0, AndroidUtils.dpToPx(app, 16), 0);
view.setPadding(AndroidUtils.dpToPx(app, 16), 0, AndroidUtils.dpToPx(app, 16), 0);
}
}
@Override
protected int getRightBottomButtonTextId() {
return R.string.shared_string_export;
}
@Override
protected void onRightBottomButtonClick() {
super.onRightBottomButtonClick();
prepareFile();
}
@Override
protected int getDismissButtonTextId() {
return R.string.shared_string_cancel;
}
@Override
protected boolean useScrollableItemsContainer() {
return false;
}
@Override
protected boolean useExpandableList() {
return true;
}
private List<AdditionalDataWrapper> getAdditionalData() {
List<AdditionalDataWrapper> dataList = new ArrayList<>();
QuickActionFactory factory = new QuickActionFactory();
List<QuickAction> actionsList = factory.parseActiveActionsList(app.getSettings().QUICK_ACTION_LIST.get());
if (!actionsList.isEmpty()) {
dataList.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.QUICK_ACTIONS, actionsList));
}
List<PoiUIFilter> poiList = app.getPoiFilters().getUserDefinedPoiFilters(false);
if (!poiList.isEmpty()) {
dataList.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.POI_TYPES,
poiList
));
}
List<ITileSource> iTileSources = new ArrayList<>();
final LinkedHashMap<String, String> tileSourceEntries = new LinkedHashMap<>(app.getSettings().getTileSourceEntries(true));
for (Map.Entry<String, String> entry : tileSourceEntries.entrySet()) {
File f = app.getAppPath(IndexConstants.TILES_INDEX_DIR + entry.getKey());
if (f != null) {
ITileSource template;
if (f.getName().endsWith(SQLiteTileSource.EXT)) {
template = new SQLiteTileSource(app, f, TileSourceManager.getKnownSourceTemplates());
} else {
template = TileSourceManager.createTileSourceTemplate(f);
}
if (template != null && template.getUrlTemplate() != null) {
iTileSources.add(template);
}
}
}
if (!iTileSources.isEmpty()) {
dataList.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.MAP_SOURCES,
iTileSources
));
}
Map<String, File> externalRenderers = app.getRendererRegistry().getExternalRenderers();
if (!externalRenderers.isEmpty()) {
dataList.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.CUSTOM_RENDER_STYLE,
new ArrayList<>(externalRenderers.values())
));
}
File routingProfilesFolder = app.getAppPath(IndexConstants.ROUTING_PROFILES_DIR);
if (routingProfilesFolder.exists() && routingProfilesFolder.isDirectory()) {
File[] fl = routingProfilesFolder.listFiles();
if (fl != null && fl.length > 0) {
dataList.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.CUSTOM_ROUTING,
Arrays.asList(fl)
));
}
}
return dataList;
}
private List<SettingsHelper.SettingsItem> prepareSettingsItemsForExport() {
List<SettingsHelper.SettingsItem> settingsItems = new ArrayList<>();
settingsItems.add(new SettingsHelper.ProfileSettingsItem(app, profile));
if (includeAdditionalData) {
settingsItems.addAll(prepareAdditionalSettingsItems());
}
return settingsItems;
}
private List<SettingsHelper.SettingsItem> prepareAdditionalSettingsItems() {
List<SettingsHelper.SettingsItem> settingsItems = new ArrayList<>();
List<QuickAction> quickActions = new ArrayList<>();
List<PoiUIFilter> poiUIFilters = new ArrayList<>();
List<ITileSource> tileSourceTemplates = new ArrayList<>();
for (Object object : adapter.getDataToOperate()) {
if (object instanceof QuickAction) {
quickActions.add((QuickAction) object);
} else if (object instanceof PoiUIFilter) {
poiUIFilters.add((PoiUIFilter) object);
} else if (object instanceof TileSourceManager.TileSourceTemplate
|| object instanceof SQLiteTileSource) {
tileSourceTemplates.add((ITileSource) object);
} else if (object instanceof File) {
settingsItems.add(new SettingsHelper.FileSettingsItem(app, (File) object));
}
}
if (!quickActions.isEmpty()) {
settingsItems.add(new SettingsHelper.QuickActionSettingsItem(app, quickActions));
}
if (!poiUIFilters.isEmpty()) {
settingsItems.add(new SettingsHelper.PoiUiFilterSettingsItem(app, poiUIFilters));
}
if (!tileSourceTemplates.isEmpty()) {
settingsItems.add(new SettingsHelper.MapSourcesSettingsItem(app, tileSourceTemplates));
}
return settingsItems;
}
private void prepareFile() {
if (app != null) {
File tempDir = app.getAppPath(IndexConstants.TEMP_DIR);
if (!tempDir.exists()) {
tempDir.mkdirs();
}
String fileName = profile.toHumanString();
app.getSettingsHelper().exportSettings(tempDir, fileName, new SettingsHelper.SettingsExportListener() {
@Override
public void onSettingsExportFinished(@NonNull File file, boolean succeed) {
if (succeed) {
shareProfile(file, profile);
} else {
app.showToastMessage(R.string.export_profile_failed);
}
}
}, prepareSettingsItemsForExport());
}
}
private void shareProfile(@NonNull File file, @NonNull ApplicationMode profile) {
try {
final Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.exported_osmand_profile, profile.toHumanString()));
sendIntent.putExtra(Intent.EXTRA_STREAM, AndroidUtils.getUriForFile(getMyApplication(), file));
sendIntent.setType("*/*");
sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(sendIntent);
dismiss();
} catch (Exception e) {
Toast.makeText(requireContext(), R.string.export_profile_failed, Toast.LENGTH_SHORT).show();
LOG.error("Share profile error", e);
}
}
public static boolean showInstance(@NonNull FragmentManager fragmentManager,
Fragment target,
@NonNull ApplicationMode appMode) {
try {
ExportProfileBottomSheet fragment = new ExportProfileBottomSheet();
fragment.setAppMode(appMode);
fragment.setTargetFragment(target, 0);
fragment.show(fragmentManager, TAG);
return true;
} catch (RuntimeException e) {
return false;
}
}
}

View file

@ -0,0 +1,202 @@
package net.osmand.plus.settings;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import net.osmand.map.ITileSource;
import net.osmand.plus.ApplicationMode;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.SettingsHelper;
import net.osmand.plus.SettingsHelper.SettingsItem;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.base.BaseOsmAndDialogFragment;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.quickaction.QuickAction;
import net.osmand.view.ComplexButton;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class ImportDuplicatesFragment extends BaseOsmAndDialogFragment implements View.OnClickListener {
public static final String TAG = ImportSettingsFragment.class.getSimpleName();
private OsmandApplication app;
private RecyclerView list;
private List<? super Object> duplicatesList;
private List<SettingsItem> settingsItems;
private DuplicatesSettingsAdapter adapter;
private File file;
private boolean nightMode;
public static void showInstance(@NonNull FragmentManager fm, List<? super Object> duplicatesList,
List<SettingsItem> settingsItems, File file) {
ImportDuplicatesFragment fragment = new ImportDuplicatesFragment();
fragment.setDuplicatesList(duplicatesList);
fragment.setSettingsItems(settingsItems);
fragment.setFile(file);
fragment.setRetainInstance(true);
fragment.show(fm, TAG);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = getMyApplication();
nightMode = !getSettings().isLightContent();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
inflater = UiUtilities.getInflater(app, nightMode);
View root = inflater.inflate(R.layout.fragment_import_duplicates, container, false);
setupToolbar((Toolbar) root.findViewById(R.id.toolbar));
ComplexButton replaceAllBtn = root.findViewById(R.id.replace_all_btn);
ComplexButton keepBothBtn = root.findViewById(R.id.keep_both_btn);
keepBothBtn.setIcon(getPaintedContentIcon(R.drawable.ic_action_keep_both,
nightMode
? getResources().getColor(R.color.icon_color_active_dark)
: getResources().getColor(R.color.icon_color_active_light))
);
replaceAllBtn.setIcon(getPaintedContentIcon(R.drawable.ic_action_replace,
nightMode
? getResources().getColor(R.color.active_buttons_and_links_text_dark)
: getResources().getColor(R.color.active_buttons_and_links_text_light))
);
keepBothBtn.setOnClickListener(this);
replaceAllBtn.setOnClickListener(this);
list = root.findViewById(R.id.list);
return root;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
adapter = new DuplicatesSettingsAdapter(getMyApplication(), prepareDuplicates(), nightMode);
list.setLayoutManager(new LinearLayoutManager(getMyApplication()));
list.setAdapter(adapter);
}
private List<Object> prepareDuplicates() {
List<? super Object> duplicates = new ArrayList<>();
List<ApplicationMode.ApplicationModeBean> profiles = new ArrayList<>();
List<QuickAction> actions = new ArrayList<>();
List<PoiUIFilter> filters = new ArrayList<>();
List<ITileSource> tileSources = new ArrayList<>();
List<File> renderFilesList = new ArrayList<>();
List<File> routingFilesList = new ArrayList<>();
for (Object object : duplicatesList) {
if (object instanceof ApplicationMode.ApplicationModeBean) {
profiles.add((ApplicationMode.ApplicationModeBean) object);
} else if (object instanceof QuickAction) {
actions.add((QuickAction) object);
} else if (object instanceof PoiUIFilter) {
filters.add((PoiUIFilter) object);
} else if (object instanceof ITileSource) {
tileSources.add((ITileSource) object);
} else if (object instanceof File) {
File file = (File) object;
if (file.getAbsolutePath().contains("files/rendering")) {
renderFilesList.add(file);
} else if (file.getAbsolutePath().contains("files/routing")) {
routingFilesList.add(file);
}
}
}
if (!profiles.isEmpty()) {
duplicates.add(getString(R.string.shared_string_profiles));
duplicates.addAll(profiles);
}
if (!actions.isEmpty()) {
duplicates.add(getString(R.string.shared_string_quick_actions));
duplicates.addAll(actions);
}
if (!filters.isEmpty()) {
duplicates.add(getString(R.string.shared_string_poi_types));
duplicates.addAll(filters);
}
if (!tileSources.isEmpty()) {
duplicates.add(getString(R.string.quick_action_map_source_title));
duplicates.addAll(tileSources);
}
if (!routingFilesList.isEmpty()) {
duplicates.add(getString(R.string.shared_string_routing));
duplicates.addAll(routingFilesList);
}
if (!renderFilesList.isEmpty()) {
duplicates.add(getString(R.string.shared_string_custom_rendering_style));
duplicates.addAll(renderFilesList);
}
return duplicates;
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.keep_both_btn: {
importItems(false);
break;
}
case R.id.replace_all_btn: {
importItems(true);
break;
}
}
}
private void importItems(boolean shouldReplace) {
for (SettingsItem item : settingsItems) {
item.setShouldReplace(shouldReplace);
}
app.getSettingsHelper().importSettings(file, settingsItems, "", 1, new SettingsHelper.SettingsImportListener() {
@Override
public void onSettingsImportFinished(boolean succeed, boolean empty, @NonNull List<SettingsHelper.SettingsItem> items) {
if (succeed) {
app.showShortToastMessage(app.getString(R.string.file_imported_successfully, file.getName()));
} else if (empty) {
app.showShortToastMessage(app.getString(R.string.file_import_error, file.getName(), app.getString(R.string.shared_string_unexpected_error)));
}
}
});
dismiss();
}
private void setupToolbar(Toolbar toolbar) {
toolbar.setNavigationIcon(getPaintedContentIcon(R.drawable.ic_arrow_back,
nightMode
? getResources().getColor(R.color.active_buttons_and_links_text_dark)
: getResources().getColor(R.color.active_buttons_and_links_text_light)));
toolbar.setNavigationContentDescription(R.string.access_shared_string_navigate_up);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
}
public void setDuplicatesList(List<? super Object> duplicatesList) {
this.duplicatesList = duplicatesList;
}
public void setSettingsItems(List<SettingsItem> settingsItems) {
this.settingsItems = settingsItems;
}
public void setFile(File file) {
this.file = file;
}
}

View file

@ -0,0 +1,275 @@
package net.osmand.plus.settings;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentManager;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ExpandableListView;
import net.osmand.map.ITileSource;
import net.osmand.map.TileSourceManager;
import net.osmand.plus.ApplicationMode;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.SQLiteTileSource;
import net.osmand.plus.SettingsHelper;
import net.osmand.plus.SettingsHelper.SettingsItem;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.base.BaseOsmAndDialogFragment;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.profiles.AdditionalDataWrapper;
import net.osmand.plus.quickaction.QuickAction;
import net.osmand.plus.widgets.TextViewEx;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class ImportSettingsFragment extends BaseOsmAndDialogFragment
implements View.OnClickListener {
public static final String TAG = ImportSettingsFragment.class.getSimpleName();
private OsmandApplication app;
private ExportImportSettingsAdapter adapter;
private ExpandableListView expandableList;
private TextViewEx selectBtn;
private List<SettingsItem> settingsItems;
private File file;
private boolean allSelected;
private boolean nightMode;
public static void showInstance(@NonNull FragmentManager fm, @NonNull List<SettingsItem> settingsItems, @NonNull File file) {
ImportSettingsFragment fragment = new ImportSettingsFragment();
fragment.setSettingsItems(settingsItems);
fragment.setFile(file);
fragment.show(fm, TAG);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = getMyApplication();
nightMode = !getSettings().isLightContent();
if (settingsItems == null) {
settingsItems = app.getSettingsHelper().getSettingsItems();
}
if (file == null) {
file = app.getSettingsHelper().getSettingsFile();
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
inflater = UiUtilities.getInflater(app, nightMode);
View root = inflater.inflate(R.layout.fragment_import, container, false);
setupToolbar((Toolbar) root.findViewById(R.id.toolbar));
TextViewEx continueBtn = root.findViewById(R.id.continue_button);
selectBtn = root.findViewById(R.id.select_button);
expandableList = root.findViewById(R.id.list);
continueBtn.setOnClickListener(this);
selectBtn.setOnClickListener(this);
return root;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
adapter = new ExportImportSettingsAdapter(getMyApplication(), getSettingsToOperate(), nightMode, true);
expandableList.setAdapter(adapter);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.select_button: {
allSelected = !allSelected;
selectBtn.setText(allSelected ? R.string.shared_string_deselect_all : R.string.shared_string_select_all);
adapter.selectAll(allSelected);
break;
}
case R.id.continue_button: {
if (adapter.getDataToOperate().isEmpty()) {
app.showShortToastMessage(getString(R.string.shared_string_nothing_selected));
} else {
importItems();
}
break;
}
}
}
private void importItems() {
List<SettingsItem> settingsItems = getSettingsItemsFromData(adapter.getDataToOperate());
List<Object> duplicateItems = getDuplicatesData(settingsItems);
if (duplicateItems.isEmpty()) {
app.getSettingsHelper().importSettings(file, settingsItems, "", 1, new SettingsHelper.SettingsImportListener() {
@Override
public void onSettingsImportFinished(boolean succeed, boolean empty, @NonNull List<SettingsHelper.SettingsItem> items) {
if (succeed) {
app.showShortToastMessage(app.getString(R.string.file_imported_successfully, file.getName()));
} else if (empty) {
app.showShortToastMessage(app.getString(R.string.file_import_error, file.getName(), app.getString(R.string.shared_string_unexpected_error)));
}
}
});
dismiss();
} else {
ImportDuplicatesFragment.showInstance(getFragmentManager(), duplicateItems, settingsItems, file);
dismiss();
}
}
@SuppressWarnings("unchecked")
private List<Object> getDuplicatesData(List<SettingsItem> items) {
List<Object> duplicateItems = new ArrayList<>();
for (SettingsItem item : items) {
if (item instanceof SettingsHelper.ProfileSettingsItem) {
if (item.exists()) {
duplicateItems.add(((SettingsHelper.ProfileSettingsItem) item).getModeBean());
}
} else if (item instanceof SettingsHelper.QuickActionSettingsItem) {
List<QuickAction> duplicates = ((SettingsHelper.QuickActionSettingsItem) item).excludeDuplicateItems();
if (!duplicates.isEmpty()) {
duplicateItems.addAll(duplicates);
}
} else if (item instanceof SettingsHelper.PoiUiFilterSettingsItem) {
List<PoiUIFilter> duplicates = ((SettingsHelper.PoiUiFilterSettingsItem) item).excludeDuplicateItems();
if (!duplicates.isEmpty()) {
duplicateItems.addAll(duplicates);
}
} else if (item instanceof SettingsHelper.MapSourcesSettingsItem) {
List<ITileSource> duplicates = ((SettingsHelper.MapSourcesSettingsItem) item).excludeDuplicateItems();
if (!duplicates.isEmpty()) {
duplicateItems.addAll(duplicates);
}
} else if (item instanceof SettingsHelper.FileSettingsItem) {
if (item.exists()) {
duplicateItems.add(((SettingsHelper.FileSettingsItem) item).getFile());
}
}
}
return duplicateItems;
}
public void setSettingsItems(List<SettingsItem> settingsItems) {
this.settingsItems = settingsItems;
}
private List<SettingsItem> getSettingsItemsFromData(List<Object> dataToOperate) {
List<SettingsItem> settingsItems = new ArrayList<>();
List<QuickAction> quickActions = new ArrayList<>();
List<PoiUIFilter> poiUIFilters = new ArrayList<>();
List<ITileSource> tileSourceTemplates = new ArrayList<>();
for (Object object : dataToOperate) {
if (object instanceof ApplicationMode.ApplicationModeBean) {
settingsItems.add(new SettingsHelper.ProfileSettingsItem(app, (ApplicationMode.ApplicationModeBean) object));
}
if (object instanceof QuickAction) {
quickActions.add((QuickAction) object);
} else if (object instanceof PoiUIFilter) {
poiUIFilters.add((PoiUIFilter) object);
} else if (object instanceof TileSourceManager.TileSourceTemplate
|| object instanceof SQLiteTileSource) {
tileSourceTemplates.add((ITileSource) object);
} else if (object instanceof File) {
settingsItems.add(new SettingsHelper.FileSettingsItem(getMyApplication(), (File) object));
}
}
if (!quickActions.isEmpty()) {
settingsItems.add(new SettingsHelper.QuickActionSettingsItem(getMyApplication(), quickActions));
}
if (!poiUIFilters.isEmpty()) {
settingsItems.add(new SettingsHelper.PoiUiFilterSettingsItem(getMyApplication(), poiUIFilters));
}
if (!tileSourceTemplates.isEmpty()) {
settingsItems.add(new SettingsHelper.MapSourcesSettingsItem(getMyApplication(), tileSourceTemplates));
}
return settingsItems;
}
@SuppressWarnings("unchecked")
private List<AdditionalDataWrapper> getSettingsToOperate() {
List<AdditionalDataWrapper> settingsToOperate = new ArrayList<>();
List<ApplicationMode.ApplicationModeBean> profiles = new ArrayList<>();
List<QuickAction> quickActions = new ArrayList<>();
List<PoiUIFilter> poiUIFilters = new ArrayList<>();
List<ITileSource> tileSourceTemplates = new ArrayList<>();
List<File> routingFilesList = new ArrayList<>();
List<File> renderFilesList = new ArrayList<>();
for (SettingsHelper.SettingsItem item : settingsItems) {
if (item.getType().equals(SettingsHelper.SettingsItemType.PROFILE)) {
profiles.add(((SettingsHelper.ProfileSettingsItem) item).getModeBean());
} else if (item.getType().equals(SettingsHelper.SettingsItemType.QUICK_ACTION)) {
quickActions.addAll(((SettingsHelper.QuickActionSettingsItem) item).getItems());
} else if (item.getType().equals(SettingsHelper.SettingsItemType.POI_UI_FILTERS)) {
poiUIFilters.addAll(((SettingsHelper.PoiUiFilterSettingsItem) item).getItems());
} else if (item.getType().equals(SettingsHelper.SettingsItemType.MAP_SOURCES)) {
tileSourceTemplates.addAll(((SettingsHelper.MapSourcesSettingsItem) item).getItems());
} else if (item.getType().equals(SettingsHelper.SettingsItemType.FILE)) {
if (item.getName().startsWith("/rendering/")) {
renderFilesList.add(((SettingsHelper.FileSettingsItem) item).getFile());
} else if (item.getName().startsWith("/routing/")) {
routingFilesList.add(((SettingsHelper.FileSettingsItem) item).getFile());
}
}
}
if (!profiles.isEmpty()) {
settingsToOperate.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.PROFILE,
profiles));
}
if (!quickActions.isEmpty()) {
settingsToOperate.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.QUICK_ACTIONS,
quickActions));
}
if (!poiUIFilters.isEmpty()) {
settingsToOperate.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.POI_TYPES,
poiUIFilters));
}
if (!tileSourceTemplates.isEmpty()) {
settingsToOperate.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.MAP_SOURCES,
tileSourceTemplates
));
}
if (!renderFilesList.isEmpty()) {
settingsToOperate.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.CUSTOM_RENDER_STYLE,
renderFilesList
));
}
if (!routingFilesList.isEmpty()) {
settingsToOperate.add(new AdditionalDataWrapper(
AdditionalDataWrapper.Type.CUSTOM_ROUTING,
routingFilesList
));
}
return settingsToOperate;
}
private void setupToolbar(Toolbar toolbar) {
toolbar.setNavigationIcon(getPaintedContentIcon(R.drawable.headline_close_button, nightMode
? getResources().getColor(R.color.active_buttons_and_links_text_dark)
: getResources().getColor(R.color.active_buttons_and_links_text_light)));
toolbar.setNavigationContentDescription(R.string.shared_string_close);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
}
public void setFile(File file) {
this.file = file;
}
}

View file

@ -81,7 +81,7 @@ public class MapQuickActionLayer extends OsmandMapLayer implements QuickActionRe
this.contextMenuLayer = contextMenuLayer;
app = activity.getMyApplication();
settings = activity.getMyApplication().getSettings();
quickActionRegistry = activity.getMapLayers().getQuickActionRegistry();
quickActionRegistry = app.getQuickActionRegistry();
measurementToolLayer = mapActivity.getMapLayers().getMeasurementToolLayer();
mapMarkersLayer = mapActivity.getMapLayers().getMapMarkersLayer();
}

View file

@ -451,7 +451,7 @@ public class MapWidgetRegistry {
contextMenuAdapter.addItem(new ContextMenuItem.ItemBuilder().setTitleId(R.string.map_widget_right, mapActivity)
.setCategory(true).setLayout(R.layout.list_group_empty_title_with_switch).createItem());
boolean selected = mapActivity.getMapLayers().getQuickActionRegistry().isQuickActionOn();
boolean selected = app.getQuickActionRegistry().isQuickActionOn();
contextMenuAdapter.addItem(new ContextMenuItem.ItemBuilder()
.setTitleId(R.string.configure_screen_quick_action, mapActivity)
.setIcon(R.drawable.map_quick_action)
@ -482,7 +482,7 @@ public class MapWidgetRegistry {
int position,
boolean visible) {
mapActivity.getMapLayers().getQuickActionRegistry().setQuickActionFabState(visible);
app.getQuickActionRegistry().setQuickActionFabState(visible);
MapQuickActionLayer mil = mapActivity.getMapLayers().getMapQuickActionLayer();
if (mil != null) {

View file

@ -0,0 +1,95 @@
package net.osmand.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import net.osmand.plus.R;
import net.osmand.plus.widgets.TextViewEx;
public class ComplexButton extends FrameLayout {
private TextViewEx textTv;
private TextViewEx subTextTv;
private ImageView iconIv;
public ComplexButton(@NonNull Context context) {
super(context);
inflateView();
}
public ComplexButton(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
inflateView();
initView(attrs);
}
public ComplexButton(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
inflateView();
initView(attrs);
}
private void inflateView() {
View view = LayoutInflater.from(getContext()).inflate(R.layout.button_with_icon_and_subtext, this);
textTv = view.findViewById(R.id.text);
subTextTv = view.findViewById(R.id.sub_text);
iconIv = view.findViewById(R.id.icon);
}
private void initView(@Nullable AttributeSet attrs) {
TypedArray a = getContext().getTheme().obtainStyledAttributes(
attrs,
R.styleable.ComplexButton,
0, 0);
try {
textTv.setText(a.getString(R.styleable.ComplexButton_setText));
textTv.setTextColor(a.getColor(R.styleable.ComplexButton_setTextColor, Color.WHITE));
subTextTv.setText(a.getString(R.styleable.ComplexButton_setSubText));
subTextTv.setTextColor(a.getColor(R.styleable.ComplexButton_setSubTextColor, Color.WHITE));
iconIv.setImageResource(a.getResourceId(R.styleable.ComplexButton_setIcon, 0));
} finally {
a.recycle();
}
}
public void setText(String text) {
textTv.setText(text);
}
public void setText(int textRes) {
textTv.setText(textRes);
}
public void setTextColor(int color) {
textTv.setTextColor(color);
}
public void setSubText(String subText) {
subTextTv.setText(subText);
}
public void setSubText(int subTextRes) {
subTextTv.setText(subTextRes);
}
public void setSubTextColor(int color) {
subTextTv.setTextColor(color);
}
public void setIcon(int iconRes) {
iconIv.setImageResource(iconRes);
}
public void setIcon(Drawable drawable) {
iconIv.setImageDrawable(drawable);
}
}

View file

@ -0,0 +1,78 @@
package net.osmand.view;
import android.content.Context;
import android.support.v7.widget.AppCompatCheckBox;
import android.util.AttributeSet;
import android.widget.CompoundButton;
import net.osmand.plus.R;
public class ThreeStateCheckbox extends AppCompatCheckBox {
private State state;
public ThreeStateCheckbox(Context context) {
super(context);
init();
}
public ThreeStateCheckbox(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ThreeStateCheckbox(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
state = State.MISC;
updateBtn();
setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
switch (state) {
case MISC:
case CHECKED:
state = State.UNCHECKED;
break;
case UNCHECKED:
state = State.CHECKED;
break;
}
updateBtn();
}
});
}
private void updateBtn() {
int btnDrawable = R.drawable.ic_checkbox_indeterminate;
switch (state) {
default:
case MISC:
break;
case UNCHECKED:
btnDrawable = R.drawable.ic_check_box_outline_light;
break;
case CHECKED:
btnDrawable = R.drawable.ic_check_box_light;
break;
}
setButtonDrawable(btnDrawable);
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
updateBtn();
}
public enum State {
UNCHECKED,
CHECKED,
MISC
}
}