Merge pull request #8779 from osmandapp/configure_menu_items

Configure menu items
This commit is contained in:
max-klaus 2020-04-15 17:16:01 +03:00 committed by GitHub
commit d4f0bde126
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 2075 additions and 247 deletions

View file

@ -72,6 +72,10 @@ public interface OsmAndCustomizationConstants {
//Map Context Menu Actions:
String MAP_CONTEXT_MENU_ACTIONS = "point.actions.";
String MAP_CONTEXT_MENU_ADD_ID = MAP_CONTEXT_MENU_ACTIONS + "add";
String MAP_CONTEXT_MENU_MARKER_ID = MAP_CONTEXT_MENU_ACTIONS + "marker";
String MAP_CONTEXT_MENU_SHARE_ID = MAP_CONTEXT_MENU_ACTIONS + "share";
String MAP_CONTEXT_MENU_MORE_ID = MAP_CONTEXT_MENU_ACTIONS + "more";
String MAP_CONTEXT_MENU_DIRECTIONS_FROM_ID = MAP_CONTEXT_MENU_ACTIONS + "directions_from";
String MAP_CONTEXT_MENU_SEARCH_NEARBY = MAP_CONTEXT_MENU_ACTIONS + "search_nearby";
String MAP_CONTEXT_MENU_CHANGE_MARKER_POSITION = MAP_CONTEXT_MENU_ACTIONS + "change_m_position";

View file

@ -0,0 +1,14 @@
{
"categories" : {
"special" : {
"icons" : [
"special_star", "special_star_stroked", "special_marker", "special_flag_stroke", "special_house", "special_building"
]
},
"amenity" : {
"icons": [
"amenity_bar", "amenity_cafe", "amenity_atm", "amenity_biergarten", "amenity_cinema", "amenity_fire_station", "amenity_parking"
]
}
}
}

View file

@ -0,0 +1,31 @@
<?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:id="@+id/item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:gravity="center"
android:orientation="vertical"
android:paddingTop="@dimen/context_menu_main_actions_padding_top"
android:paddingBottom="@dimen/context_menu_main_actions_padding_bottom">
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/context_menu_main_actions_icon_margin"
android:scaleType="center" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/ctx_menu_buttons_text_color"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_regular" />
</LinearLayout>

View file

@ -0,0 +1,26 @@
<?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="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="?attr/activity_background_color"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="@layout/global_preference_toolbar" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/list_background_color"
tools:listitem="@layout/list_item_ui_customization" />
</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">
<FrameLayout
android:id="@+id/image_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/activity_background_basic"
tools:paddingEnd="56dp"
tools:paddingStart="56dp"
tools:paddingTop="16dp">
<ImageView
android:id="@+id/device_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
tools:src="@drawable/img_settings_device_top_dark" />
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
tools:src="@drawable/img_settings_customize_configure_map_night" />
</FrameLayout>
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/content_padding"
android:letterSpacing="0.02"
android:lineSpacingExtra="@dimen/line_spacing_extra_description"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
tools:text="@string/ui_customization_description" />
</LinearLayout>

View file

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/list_background_color"
android:minHeight="@dimen/list_item_move_header_min_height"
android:orientation="vertical">
<View
android:id="@+id/divider"
android:background="?attr/dashboard_divider"
android:layout_width="match_parent"
android:layout_height="1dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/bottom_sheet_icon_margin"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/bottom_sheet_icon_margin"
android:visibility="gone"
tools:visibility="visible"
android:src="@drawable/ic_action_item_move"
android:tint="?attr/secondary_icon_color" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="vertical"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:letterSpacing="@dimen/description_letter_spacing"
android:paddingTop="@dimen/list_header_settings_top_margin"
android:singleLine="true"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="@string/plugin_settings" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:letterSpacing="@dimen/description_letter_spacing"
android:paddingBottom="@dimen/list_header_settings_top_margin"
android:lineSpacingExtra="@dimen/line_spacing_extra_description"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_regular"
tools:text="@string/list_of_installed_plugins" />
</LinearLayout>
<ImageView
android:id="@+id/move_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/bottom_sheet_icon_margin"
android:paddingEnd="@dimen/content_padding"
android:visibility="gone"
tools:visibility="visible"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/bottom_sheet_icon_margin"
android:src="@drawable/ic_action_item_move"
android:tint="?attr/secondary_icon_color" />
</LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,50 @@
<?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:minHeight="@dimen/setting_list_item_large_height"
android:orientation="horizontal">
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginEnd="@dimen/list_content_padding_large"
android:layout_marginRight="@dimen/list_content_padding_large"
tools:src="@drawable/ic_action_layers" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
tools:text="Configure Map" />
<TextView
android:id="@+id/sub_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
tools:text="Items: 15 of 16" />
</LinearLayout>
</LinearLayout>

View file

@ -419,136 +419,7 @@
android:paddingStart="@dimen/map_widget_icon_margin"
android:paddingEnd="@dimen/map_widget_icon_margin">
<LinearLayout
android:id="@+id/context_menu_fav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?selectableItemBackground"
android:gravity="center"
android:orientation="vertical"
android:paddingBottom="@dimen/context_menu_main_actions_padding_bottom"
android:paddingTop="@dimen/context_menu_main_actions_padding_top">
<ImageView
android:id="@+id/context_menu_fav_image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/context_menu_main_actions_icon_margin"
android:scaleType="center"
android:src="@drawable/map_action_fav_dark"/>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/context_menu_fav_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/ctx_menu_buttons_text_color"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_regular"
tools:text="@string/shared_string_add"/>
</LinearLayout>
<LinearLayout
android:id="@+id/context_menu_route_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?selectableItemBackground"
android:clickable="true"
android:gravity="center"
android:orientation="vertical"
android:paddingBottom="@dimen/context_menu_main_actions_padding_bottom"
android:paddingTop="@dimen/context_menu_main_actions_padding_top">
<ImageView
android:id="@+id/context_menu_route_image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/context_menu_main_actions_icon_margin"
android:scaleType="center"
android:src="@drawable/map_action_flag_dark"/>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/context_menu_route_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/ctx_menu_buttons_text_color"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_regular"
tools:text="@string/shared_string_marker"/>
</LinearLayout>
<LinearLayout
android:id="@+id/context_menu_share_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?selectableItemBackground"
android:clickable="true"
android:gravity="center"
android:orientation="vertical"
android:paddingBottom="@dimen/context_menu_main_actions_padding_bottom"
android:paddingTop="@dimen/context_menu_main_actions_padding_top">
<ImageView
android:id="@+id/context_menu_share_image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/context_menu_main_actions_icon_margin"
android:scaleType="center"
android:src="@drawable/map_action_gshare_dark"/>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/context_menu_share_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:text="@string/shared_string_share"
android:textColor="@color/ctx_menu_buttons_text_color"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_regular"/>
</LinearLayout>
<LinearLayout
android:id="@+id/context_menu_more_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?selectableItemBackground"
android:clickable="true"
android:gravity="center"
android:orientation="vertical"
android:paddingBottom="@dimen/context_menu_main_actions_padding_bottom"
android:paddingTop="@dimen/context_menu_main_actions_padding_top">
<ImageView
android:id="@+id/context_menu_more_image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/context_menu_main_actions_icon_margin"
android:scaleType="center"
android:src="@drawable/map_overflow_menu_white"/>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/context_menu_more_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:text="@string/shared_string_actions"
android:textColor="@color/ctx_menu_buttons_text_color"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_regular"/>
</LinearLayout>
<!--Filled programmatically-->
</LinearLayout>

View file

@ -4,9 +4,19 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="?attr/list_background_color"
android:gravity="center_vertical">
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginBottom="@dimen/content_padding_small"
android:background="?attr/dashboard_divider"
android:visibility="gone"
tools:visibility="visible" />
<LinearLayout
android:id="@+id/selectable_list_item"
android:layout_width="match_parent"
@ -70,6 +80,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:letterSpacing="@dimen/description_letter_spacing"
android:lineSpacingExtra="@dimen/line_spacing_extra_description"
android:maxLines="4"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"

View file

@ -364,4 +364,5 @@
<dimen name="slider_thumb_halo_size">12dp</dimen>
<dimen name="slider_track_height">2dp</dimen>
<dimen name="list_item_move_header_min_height">65dp</dimen>
</resources>

View file

@ -21,10 +21,27 @@
<string name="settings_item_write_error">Could not write %1$s.</string>
<string name="settings_item_read_error">Could not read %1$s.</string>
<string name="changes_applied_to_profile">Changes applied to %1$s profile.</string>
<string name="shared_string_items">Items</string>
<string name="custom_osmand_plugin">Custom OsmAnd plugin</string>
<string name="app_mode_ski_snowmobile">Snowmobile</string>
<string name="app_mode_ski_touring">Ski touring</string>
<string name="replace_point_descr">Replace another point with this</string>
<string name="developer_plugin">Developer Plugin</string>
<string name="move_inside_category">You can move items only inside this category.</string>
<string name="additional_actions_descr">You can acsess this actions by taping “Actions” button.</string>
<string name="main_actions">Main actions</string>
<string name="main_actions_descr">Main actions containt only 4 buttons.</string>
<string name="reset_items_descr">Settings will be reset to the original state after hiding.</string>
<string name="hidden_items_descr">These items are hidden from the menu, but the represented options or plugins still be working.</string>
<string name="shared_string_hidden">Hidden</string>
<string name="divider_descr">Elements below this point separated by a divider.</string>
<string name="shared_string_divider">Divider</string>
<string name="reorder_or_hide_from">Reorder or hide items from the %1$s.</string>
<string name="context_menu_actions">Context menu actions</string>
<string name="shared_string_drawer">Drawer</string>
<string name="ui_customization">UI Customization</string>
<string name="ui_customization_short_descr">Drawer items, context menu</string>
<string name="ui_customization_description">Customize the quantity of items in Drawer, Configure map and context menu.\n\nYou can disable unused plugins, to hide all its controls from the application %1$s.</string>
<string name="shared_string_min">Min</string>
<string name="shared_string_square">Square</string>
<string name="shared_string_octagon">Octagon</string>

View file

@ -52,6 +52,14 @@
android:title="@string/profile_appearance"
tools:icon="@drawable/ic_action_offroad" />
<Preference
android:key="ui_customization"
android:layout="@layout/preference_with_descr"
android:persistent="false"
android:summary="@string/ui_customization_short_descr"
android:title="@string/ui_customization"
tools:icon="@drawable/ic_action_ui_customization" />
<Preference
android:layout="@layout/simple_divider_item"
android:selectable="false" />

View file

@ -23,6 +23,7 @@ import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentActivity;
@ -34,6 +35,8 @@ import net.osmand.plus.activities.actions.AppModeDialog;
import net.osmand.plus.dialogs.ConfigureMapMenu;
import net.osmand.plus.dialogs.HelpArticleDialogFragment;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.OsmandSettings.ContextMenuItemsPreference;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
@ -41,11 +44,12 @@ import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.APP_PROFILES_ID;
public class ContextMenuAdapter {
private static final Log LOG = PlatformUtil.getLog(ContextMenuAdapter.class);
@ -60,6 +64,11 @@ public class ContextMenuAdapter {
private boolean profileDependent = false;
private boolean nightMode;
private ConfigureMapMenu.OnClickListener changeAppModeListener = null;
private OsmandApplication app;
public ContextMenuAdapter(OsmandApplication app) {
this.app = app;
}
public int length() {
return items.size();
@ -75,7 +84,13 @@ public class ContextMenuAdapter {
public void addItem(ContextMenuItem item) {
try {
String id = item.getId();
if (id != null) {
item.setHidden(isItemHidden(id));
item.setOrder(getItemOrder(id, item.getOrder()));
}
items.add(item.getPos(), item);
sortItemsByOrder();
} catch (IndexOutOfBoundsException ex) {
items.add(item);
}
@ -85,6 +100,10 @@ public class ContextMenuAdapter {
return items.get(position);
}
public List<ContextMenuItem> getItems() {
return items;
}
public void removeItem(int position) {
items.remove(position);
}
@ -107,7 +126,6 @@ public class ContextMenuAdapter {
this.DEFAULT_LAYOUT_ID = defaultLayoutId;
}
public void setChangeAppModeListener(ConfigureMapMenu.OnClickListener changeAppModeListener) {
this.changeAppModeListener = changeAppModeListener;
}
@ -128,16 +146,45 @@ public class ContextMenuAdapter {
});
}
private boolean isItemHidden(@NonNull String id) {
ContextMenuItemsPreference contextMenuItemsPreference = app.getSettings().getContextMenuItemsPreference(id);
if (contextMenuItemsPreference == null) {
return false;
}
List<String> hiddenIds = contextMenuItemsPreference.get().getHiddenIds();
if (!Algorithms.isEmpty(hiddenIds)) {
return hiddenIds.contains(id);
}
return false;
}
private int getItemOrder(@NonNull String id, int defaultOrder) {
ContextMenuItemsPreference contextMenuItemsPreference = app.getSettings().getContextMenuItemsPreference(id);
if (contextMenuItemsPreference == null) {
return defaultOrder;
}
List<String> orderIds = contextMenuItemsPreference.get().getOrderIds();
if (!Algorithms.isEmpty(orderIds)) {
int order = orderIds.indexOf(id);
if (order != -1) {
return order;
}
}
return defaultOrder;
}
public ArrayAdapter<ContextMenuItem> createListAdapter(final Activity activity, final boolean lightTheme) {
final int layoutId = DEFAULT_LAYOUT_ID;
final OsmandApplication app = ((OsmandApplication) activity.getApplication());
final OsmAndAppCustomization customization = app.getAppCustomization();
for (Iterator<ContextMenuItem> iterator = items.iterator(); iterator.hasNext(); ) {
String id = iterator.next().getId();
if (!TextUtils.isEmpty(id) && !customization.isFeatureEnabled(id)) {
iterator.remove();
List<ContextMenuItem> itemsToRemove = new ArrayList<>();
for (ContextMenuItem item : items) {
String id = item.getId();
if (item.isHidden() || !TextUtils.isEmpty(id) && !customization.isFeatureEnabled(id)) {
itemsToRemove.add(item);
}
}
items.removeAll(itemsToRemove);
return new ContextMenuArrayAdapter(activity, layoutId, R.id.title,
items.toArray(new ContextMenuItem[items.size()]), app, lightTheme, changeAppModeListener);
}
@ -532,4 +579,30 @@ public class ContextMenuAdapter {
}
}
}
public List<ContextMenuItem> getDefaultItems() {
String idScheme = getIdScheme();
List<ContextMenuItem> items = new ArrayList<>();
for (ContextMenuItem item : this.items) {
String id = item.getId();
if (id != null && id.startsWith(idScheme) && !APP_PROFILES_ID.equals(id)) {
items.add(item);
}
}
return items;
}
private String getIdScheme() {
String idScheme = "";
for (ContextMenuItem item : items) {
String id = item.getId();
if (id != null) {
ContextMenuItemsPreference pref = app.getSettings().getContextMenuItemsPreference(id);
if (pref != null) {
return pref.getIdScheme();
}
}
}
return idScheme;
}
}

View file

@ -30,8 +30,9 @@ public class ContextMenuItem {
private final boolean category;
private final boolean clickable;
private final boolean skipPaintingWithoutColor;
private boolean hidden;
private final int pos;
private final int order;
private int order;
private String description;
private final ContextMenuAdapter.ItemClickListener itemClickListener;
private final ContextMenuAdapter.OnIntegerValueChangedListener integerListener;
@ -153,6 +154,10 @@ public class ContextMenuItem {
return clickable;
}
public boolean isHidden() {
return hidden;
}
public int getPos() {
return pos;
}
@ -185,6 +190,10 @@ public class ContextMenuItem {
return hideDivider;
}
public void setHidden(boolean hidden) {
this.hidden = hidden;
}
public boolean shouldHideCompoundButton() {
return hideCompoundButton;
}
@ -213,6 +222,10 @@ public class ContextMenuItem {
this.progress = progress;
}
public void setOrder(int order) {
this.order = order;
}
public void setLoading(boolean loading) {
this.loading = loading;
}

View file

@ -25,6 +25,7 @@ import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.StateChangedListener;
import net.osmand.ValueHolder;
import net.osmand.aidl.OsmandAidlApi;
@ -56,11 +57,14 @@ import net.osmand.plus.voice.CommandPlayer;
import net.osmand.render.RenderingRulesStorage;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.lang.reflect.Type;
import java.util.ArrayList;
@ -77,8 +81,14 @@ import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.CONFIGURE_MAP_ITEM_ID_SCHEME;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_ITEM_ID_SCHEME;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_ACTIONS;
public class OsmandSettings {
private static final Log LOG = PlatformUtil.getLog(OsmandSettings.class.getName());
public static final int VERSION = 1;
public interface OsmandPreference<T> {
@ -442,6 +452,10 @@ public class OsmandSettings {
}
return false;
}
} else if (preference instanceof ContextMenuItemsPreference) {
if (value instanceof ContextMenuItemsSettings) {
((ContextMenuItemsPreference) preference).setModeValue(mode, (ContextMenuItemsSettings) value);
}
}
}
return false;
@ -1102,6 +1116,131 @@ public class OsmandSettings {
addModeValue(appMode, value);
}
}
public boolean setModeValues(ApplicationMode mode, List<String> values) {
if (values == null || values.size() == 0) {
setModeValue(mode,null);
return false;
}
clearAll();
String vl = get();
for (String value : values) {
addValue(value);
if (vl == null || vl.isEmpty()) {
vl = value + delimiter;
} else {
vl = vl + value + delimiter;
}
}
return setModeValue(mode, vl);
}
}
public class ContextMenuItemsPreference extends CommonPreference<ContextMenuItemsSettings> {
@NonNull
private String idScheme;
private ContextMenuItemsPreference(String id, @NonNull String idScheme) {
super(id, new ContextMenuItemsSettings());
this.idScheme = idScheme;
}
@Override
protected ContextMenuItemsSettings getValue(Object prefs, ContextMenuItemsSettings defaultValue) {
String s = settingsAPI.getString(prefs, getId(), "");
return readValue(s);
}
@Override
protected boolean setValue(Object prefs, ContextMenuItemsSettings val) {
return settingsAPI.edit(prefs).putString(getId(), val.writeToJsonString(idScheme)).commit();
}
@Override
public ContextMenuItemsSettings parseString(String s) {
return readValue(s);
}
private ContextMenuItemsSettings readValue(String s) {
ContextMenuItemsSettings value = new ContextMenuItemsSettings();
value.readFromJsonString(s, idScheme);
return value;
}
@NonNull
public String getIdScheme() {
return idScheme;
}
}
public static class ContextMenuItemsSettings implements Serializable {
public static final String HIDDEN = "hidden";
public static final String ORDER = "order";
private List<String> hiddenIds = new ArrayList<>();
private List<String> orderIds = new ArrayList<>();
public ContextMenuItemsSettings() {
}
public ContextMenuItemsSettings(@NonNull List<String> hiddenIds, @NonNull List<String> orderIds) {
this.hiddenIds = hiddenIds;
this.orderIds = orderIds;
}
public void readFromJsonString(String jsonString, @NonNull String idScheme) {
if (Algorithms.isEmpty(jsonString)) {
return;
}
try {
JSONObject json = new JSONObject(jsonString);
hiddenIds = readIdsList(json.optJSONArray(HIDDEN), idScheme);
orderIds = readIdsList(json.optJSONArray(ORDER), idScheme);
} catch (JSONException e) {
LOG.error("Error converting to json string: " + e);
}
}
private List<String> readIdsList(JSONArray jsonArray, @NonNull String idScheme) {
List<String> list = new ArrayList<>();
if (jsonArray != null) {
for (int i = 0; i < jsonArray.length(); i++) {
String id = jsonArray.optString(i);
list.add(idScheme + id);
}
}
return list;
}
public String writeToJsonString(@NonNull String idScheme) {
try {
JSONObject json = new JSONObject();
json.put(HIDDEN, getJsonArray(hiddenIds, idScheme));
json.put(ORDER, getJsonArray(orderIds, idScheme));
return json.toString();
} catch (JSONException e) {
LOG.error("Error converting to json string: " + e);
}
return "";
}
private JSONArray getJsonArray(List<String> ids, @NonNull String idScheme) {
JSONArray jsonArray = new JSONArray();
if (ids != null && !ids.isEmpty()) {
for (String id : ids) {
jsonArray.put(id.replace(idScheme, ""));
}
}
return jsonArray;
}
public List<String> getHiddenIds() {
return Collections.unmodifiableList(hiddenIds);
}
public List<String> getOrderIds() {
return Collections.unmodifiableList(orderIds);
}
}
public class EnumIntPreference<E extends Enum<E>> extends CommonPreference<E> {
@ -3421,13 +3560,34 @@ public class OsmandSettings {
public void setSelectedPoiFilters(final Set<String> poiFilters) {
SELECTED_POI_FILTER_FOR_MAP.set(android.text.TextUtils.join(",", poiFilters));
}
public final ListStringPreference POI_FILTERS_ORDER = (ListStringPreference)
new ListStringPreference("poi_filters_order", null, ",,").makeProfile().cache();
public final ListStringPreference INACTIVE_POI_FILTERS = (ListStringPreference)
new ListStringPreference("inactive_poi_filters", null, ",,").makeProfile().cache();
public final ContextMenuItemsPreference DRAWER_ITEMS =
(ContextMenuItemsPreference) new ContextMenuItemsPreference("drawer_items", DRAWER_ITEM_ID_SCHEME).makeProfile().cache();
public final ContextMenuItemsPreference CONFIGURE_MAP_ITEMS =
(ContextMenuItemsPreference) new ContextMenuItemsPreference("context_menu_items", CONFIGURE_MAP_ITEM_ID_SCHEME).makeProfile().cache();
public final ContextMenuItemsPreference CONTEXT_MENU_ACTIONS_ITEMS =
(ContextMenuItemsPreference) new ContextMenuItemsPreference("configure_map_items", MAP_CONTEXT_MENU_ACTIONS).makeProfile().cache();
public final List<ContextMenuItemsPreference> CONTEXT_MENU_ITEMS_PREFERENCES = Arrays.asList(DRAWER_ITEMS, CONFIGURE_MAP_ITEMS, CONTEXT_MENU_ACTIONS_ITEMS);
@Nullable
public ContextMenuItemsPreference getContextMenuItemsPreference(@NonNull String id) {
for (ContextMenuItemsPreference preference : CONTEXT_MENU_ITEMS_PREFERENCES) {
if (id.startsWith(preference.idScheme)) {
return preference;
}
}
return null;
}
public static final String VOICE_PROVIDER_NOT_USE = "VOICE_PROVIDER_NOT_USE";
public static final String[] TTS_AVAILABLE_VOICES = new String[]{

View file

@ -42,7 +42,7 @@ public class HelpActivity extends OsmandActionBarActivity implements AdapterView
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_help_screen);
ContextMenuAdapter contextMenuAdapter = new ContextMenuAdapter();
ContextMenuAdapter contextMenuAdapter = new ContextMenuAdapter(getMyApplication());
contextMenuAdapter.setDefaultLayoutId(R.layout.two_line_with_images_list_item);
createBeginWithOsmandItems(contextMenuAdapter);

View file

@ -137,6 +137,7 @@ import net.osmand.plus.search.QuickSearchDialogFragment.QuickSearchTab;
import net.osmand.plus.search.QuickSearchDialogFragment.QuickSearchType;
import net.osmand.plus.settings.BaseSettingsFragment;
import net.osmand.plus.settings.BaseSettingsFragment.SettingsScreenType;
import net.osmand.plus.settings.ConfigureMenuItemsFragment;
import net.osmand.plus.settings.ConfigureProfileFragment;
import net.osmand.plus.settings.DataStorageFragment;
import net.osmand.plus.settings.ImportCompleteFragment;
@ -750,6 +751,11 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
importCompleteFragment.dismissFragment();
return;
}
ConfigureMenuItemsFragment configureMenuItemsFragment = getConfigureMenuItemsFragment();
if (configureMenuItemsFragment != null) {
configureMenuItemsFragment.exitFragment();
return;
}
super.onBackPressed();
}
@ -2469,6 +2475,10 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
return getFragment(ImportCompleteFragment.TAG);
}
public ConfigureMenuItemsFragment getConfigureMenuItemsFragment(){
return getFragment(ConfigureMenuItemsFragment.TAG);
}
public PointEditorFragmentNew getPointEditorFragmentNew() {
PointEditorFragmentNew pointEditorFragmentNew;
pointEditorFragmentNew = getFragment(FavoritePointEditor.TAG);

View file

@ -64,6 +64,7 @@ import net.osmand.plus.routepreparationmenu.WaypointsFragment;
import net.osmand.plus.routing.RouteProvider.GPXRouteParamsBuilder;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.settings.BaseSettingsFragment;
import net.osmand.plus.mapcontextmenu.AdditionalActionsBottomSheetDialogFragment.ContextMenuItemClickListener;
import net.osmand.plus.views.BaseMapLayer;
import net.osmand.plus.views.MapControlsLayer;
import net.osmand.plus.views.MapTileLayer;
@ -98,11 +99,15 @@ import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_SEARCH_ID;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_SETTINGS_ID;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_TRAVEL_GUIDES_ID;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_ADD_GPX_WAYPOINT;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_ADD_ID;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_AVOID_ROAD;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_DIRECTIONS_FROM_ID;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_EDIT_GPX_WP;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_MARKER_ID;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_MEASURE_DISTANCE;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_MORE_ID;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_SEARCH_NEARBY;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_SHARE_ID;
import static net.osmand.plus.ContextMenuAdapter.PROFILES_CHOSEN_PROFILE_TAG;
import static net.osmand.plus.ContextMenuAdapter.PROFILES_CONTROL_BUTTON_TAG;
import static net.osmand.plus.ContextMenuAdapter.PROFILES_NORMAL_PROFILE_TAG;
@ -331,10 +336,38 @@ public class MapActivityActions implements DialogProvider {
}
public void contextMenuPoint(final double latitude, final double longitude, final ContextMenuAdapter iadapter, Object selectedObj) {
final ContextMenuAdapter adapter = iadapter == null ? new ContextMenuAdapter() : iadapter;
public void addActionsToAdapter(final double latitude,
final double longitude,
final ContextMenuAdapter adapter,
Object selectedObj,
boolean all) {
ItemBuilder itemBuilder = new ItemBuilder();
adapter.addItem(itemBuilder
.setTitleId(R.string.shared_string_add, mapActivity)
.setId(MAP_CONTEXT_MENU_ADD_ID)
.setIcon(R.drawable.map_action_fav_dark)
.setOrder(0)
.createItem());
adapter.addItem(itemBuilder
.setTitleId(R.string.shared_string_marker, mapActivity)
.setId(MAP_CONTEXT_MENU_MARKER_ID)
.setIcon(R.drawable.map_action_flag_dark)
.setOrder(1)
.createItem());
adapter.addItem(itemBuilder
.setTitleId(R.string.shared_string_share, mapActivity)
.setId(MAP_CONTEXT_MENU_SHARE_ID)
.setIcon(R.drawable.map_action_gshare_dark)
.setOrder(2)
.createItem());
adapter.addItem(itemBuilder
.setTitleId(R.string.shared_string_actions, mapActivity)
.setId(MAP_CONTEXT_MENU_MORE_ID)
.setIcon(R.drawable.map_overflow_menu_white)
.setOrder(3)
.createItem());
adapter.addItem(itemBuilder
.setTitleId(R.string.context_menu_item_directions_from, mapActivity)
.setId(MAP_CONTEXT_MENU_DIRECTIONS_FROM_ID)
@ -362,22 +395,28 @@ public class MapActivityActions implements DialogProvider {
}
};
if (selectedObj instanceof WptPt
ContextMenuItem editGpxItem = new ItemBuilder()
.setTitleId(R.string.context_menu_item_edit_waypoint, mapActivity)
.setId(MAP_CONTEXT_MENU_EDIT_GPX_WP)
.setIcon(R.drawable.ic_action_edit_dark)
.setOrder(EDIT_GPX_WAYPOINT_ITEM_ORDER)
.setListener(listener).createItem();
ContextMenuItem addGpxItem = new ItemBuilder()
.setTitleId(R.string.context_menu_item_add_waypoint, mapActivity)
.setId(MAP_CONTEXT_MENU_ADD_GPX_WAYPOINT)
.setIcon(R.drawable.ic_action_gnew_label_dark)
.setOrder(ADD_GPX_WAYPOINT_ITEM_ORDER)
.setListener(listener).createItem();
if (all) {
adapter.addItem(editGpxItem);
adapter.addItem(addGpxItem);
} else if (selectedObj instanceof WptPt
&& getMyApplication().getSelectedGpxHelper().getSelectedGPXFile((WptPt) selectedObj) != null) {
adapter.addItem(new ItemBuilder()
.setTitleId(R.string.context_menu_item_edit_waypoint, mapActivity)
.setId(MAP_CONTEXT_MENU_EDIT_GPX_WP)
.setIcon(R.drawable.ic_action_edit_dark)
.setOrder(EDIT_GPX_WAYPOINT_ITEM_ORDER)
.setListener(listener).createItem());
adapter.addItem(editGpxItem);
} else if (!getMyApplication().getSelectedGpxHelper().getSelectedGPXFiles().isEmpty()
|| (OsmandPlugin.getEnabledPlugin(OsmandMonitoringPlugin.class) != null)) {
adapter.addItem(new ItemBuilder()
.setTitleId(R.string.context_menu_item_add_waypoint, mapActivity)
.setId(MAP_CONTEXT_MENU_ADD_GPX_WAYPOINT)
.setIcon(R.drawable.ic_action_gnew_label_dark)
.setOrder(ADD_GPX_WAYPOINT_ITEM_ORDER)
.setListener(listener).createItem());
adapter.addItem(addGpxItem);
}
adapter.addItem(itemBuilder
@ -395,12 +434,25 @@ public class MapActivityActions implements DialogProvider {
.createItem());
adapter.sortItemsByOrder();
}
public void contextMenuPoint(final double latitude, final double longitude, final ContextMenuAdapter iadapter, Object selectedObj) {
final ContextMenuAdapter adapter = iadapter == null ? new ContextMenuAdapter(getMyApplication()) : iadapter;
addActionsToAdapter(latitude, longitude, adapter, selectedObj, false);
showAdditionalActionsFragment(adapter, getContextMenuItemClickListener(latitude, longitude, adapter));
}
public void showAdditionalActionsFragment(final ContextMenuAdapter adapter, AdditionalActionsBottomSheetDialogFragment.ContextMenuItemClickListener listener) {
AdditionalActionsBottomSheetDialogFragment actionsBottomSheetDialogFragment = new AdditionalActionsBottomSheetDialogFragment();
actionsBottomSheetDialogFragment.setAdapter(adapter, listener);
actionsBottomSheetDialogFragment.show(mapActivity.getSupportFragmentManager(), AdditionalActionsBottomSheetDialogFragment.TAG);
}
public ContextMenuItemClickListener getContextMenuItemClickListener(final double latitude, final double longitude, final ContextMenuAdapter adapter) {
final ArrayAdapter<ContextMenuItem> listAdapter =
adapter.createListAdapter(mapActivity, getMyApplication().getSettings().isLightContent());
AdditionalActionsBottomSheetDialogFragment actionsBottomSheetDialogFragment = new AdditionalActionsBottomSheetDialogFragment();
actionsBottomSheetDialogFragment.setAdapter(adapter, new AdditionalActionsBottomSheetDialogFragment.ContextMenuItemClickListener() {
return new AdditionalActionsBottomSheetDialogFragment.ContextMenuItemClickListener() {
@Override
public void onItemClick(int position) {
ContextMenuItem item = adapter.getItem(position);
@ -423,10 +475,15 @@ public class MapActivityActions implements DialogProvider {
MeasurementToolFragment.showInstance(mapActivity.getSupportFragmentManager(), new LatLon(latitude, longitude));
} else if (standardId == R.string.avoid_road) {
getMyApplication().getAvoidSpecificRoads().addImpassableRoad(mapActivity, new LatLon(latitude, longitude), true, false, null);
} else if (standardId == R.string.shared_string_add) {
mapActivity.getContextMenu().buttonFavoritePressed();
} else if (standardId == R.string.shared_string_marker) {
mapActivity.getContextMenu().buttonWaypointPressed();
} else if (standardId == R.string.shared_string_share) {
mapActivity.getContextMenu().buttonSharePressed();
}
}
});
actionsBottomSheetDialogFragment.show(mapActivity.getSupportFragmentManager(), AdditionalActionsBottomSheetDialogFragment.TAG);
};
}
public void enterDirectionsFromPoint(final double latitude, final double longitude) {
@ -648,7 +705,7 @@ public class MapActivityActions implements DialogProvider {
public ContextMenuAdapter createMainOptionsMenu() {
final OsmandMapTileView mapView = mapActivity.getMapView();
final OsmandApplication app = mapActivity.getMyApplication();
ContextMenuAdapter optionsMenuHelper = new ContextMenuAdapter();
ContextMenuAdapter optionsMenuHelper = new ContextMenuAdapter(app);
boolean nightMode = getMyApplication().getDaynightHelper().isNightModeForMapControls();
if (drawerMode == DRAWER_MODE_SWITCH_PROFILE) {

View file

@ -270,7 +270,7 @@ public class MapActivityLayers {
public void showMultichoicePoiFilterDialog(final OsmandMapTileView mapView, final DismissListener listener) {
final OsmandApplication app = getApplication();
final PoiFiltersHelper poiFilters = app.getPoiFilters();
final ContextMenuAdapter adapter = new ContextMenuAdapter();
final ContextMenuAdapter adapter = new ContextMenuAdapter(app);
final List<PoiUIFilter> list = new ArrayList<>();
for (PoiUIFilter f : poiFilters.getSortedPoiFilters(true)) {
addFilterToList(adapter, list, f, true);
@ -344,7 +344,7 @@ public class MapActivityLayers {
public void showSingleChoicePoiFilterDialog(final OsmandMapTileView mapView, final DismissListener listener) {
final OsmandApplication app = getApplication();
final PoiFiltersHelper poiFilters = app.getPoiFilters();
final ContextMenuAdapter adapter = new ContextMenuAdapter();
final ContextMenuAdapter adapter = new ContextMenuAdapter(app);
adapter.addItem(new ContextMenuItem.ItemBuilder()
.setTitleId(R.string.shared_string_search, app)
.setIcon(R.drawable.ic_action_search_dark).createItem());

View file

@ -475,7 +475,7 @@ public class SettingsNavigationActivity extends SettingsBaseActivity {
return true;
} else if (preference == autoZoom) {
final ApplicationMode am = settings.getApplicationMode();
final ContextMenuAdapter adapter = new ContextMenuAdapter();
final ContextMenuAdapter adapter = new ContextMenuAdapter(getMyApplication());
int i = 0;
int selectedIndex = -1;
adapter.addItem(ContextMenuItem.createBuilder(getString(R.string.auto_zoom_none))
@ -546,7 +546,7 @@ public class SettingsNavigationActivity extends SettingsBaseActivity {
return true;
} else if (preference == reliefFactorRouting) {
final ApplicationMode am = settings.getApplicationMode();
final ContextMenuAdapter adapter = new ContextMenuAdapter();
final ContextMenuAdapter adapter = new ContextMenuAdapter(getMyApplication());
int i = 0;
int selectedIndex = -1;
for (RoutingParameter p : reliefFactorParameters) {

View file

@ -53,6 +53,7 @@ import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.poi.PoiFiltersHelper;
import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin;
import net.osmand.plus.render.RendererRegistry;
import net.osmand.plus.settings.ConfigureMenuRootFragment.ScreenType;
import net.osmand.plus.srtmplugin.SRTMPlugin;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.corenative.NativeCoreContext;
@ -128,7 +129,7 @@ public class ConfigureMapMenu {
OsmandApplication app = ma.getMyApplication();
boolean nightMode = app.getDaynightHelper().isNightModeForMapControls();
int themeRes = nightMode ? R.style.OsmandDarkTheme : R.style.OsmandLightTheme;
ContextMenuAdapter adapter = new ContextMenuAdapter();
ContextMenuAdapter adapter = new ContextMenuAdapter(app);
adapter.setDefaultLayoutId(R.layout.list_item_icon_and_menu);
adapter.addItem(new ContextMenuItem.ItemBuilder()
.setId(APP_PROFILES_ID)
@ -156,7 +157,6 @@ public class ConfigureMapMenu {
adapter.setNightMode(nightMode);
createLayersItems(customRules, adapter, ma, themeRes, nightMode);
createRenderingAttributeItems(customRules, adapter, ma, themeRes, nightMode);
return adapter;
}

View file

@ -24,7 +24,7 @@ public class RasterMapMenu {
public static ContextMenuAdapter createListAdapter(final MapActivity mapActivity,
final RasterMapType type) {
boolean nightMode = mapActivity.getMyApplication().getDaynightHelper().isNightModeForMapControls();
ContextMenuAdapter adapter = new ContextMenuAdapter();
ContextMenuAdapter adapter = new ContextMenuAdapter(mapActivity.getMyApplication());
adapter.setDefaultLayoutId(R.layout.list_item_icon_and_menu);
adapter.setProfileDependent(true);
adapter.setNightMode(nightMode);

View file

@ -164,7 +164,7 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
private void showContextMenu(final LocalIndexInfo info) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
final ContextMenuAdapter adapter = new ContextMenuAdapter();
final ContextMenuAdapter adapter = new ContextMenuAdapter(getMyApplication());
basicFileOperation(info, adapter);
OsmandPlugin.onContextMenuActivity(getActivity(), null, info, adapter);
@ -704,7 +704,7 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
//hide action bar from downloadindexfragment
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
int iconColorResId = getMyApplication().getSettings().isLightContent() ? R.color.active_buttons_and_links_text_light : R.color.active_buttons_and_links_text_dark;
optionsMenuAdapter = new ContextMenuAdapter();
optionsMenuAdapter = new ContextMenuAdapter(requireMyApplication());
ItemClickListener listener = new ContextMenuAdapter.ItemClickListener() {
@Override
public boolean onContextMenuClick(ArrayAdapter<ContextMenuItem> adapter,

View file

@ -234,7 +234,7 @@ public class GpxUiHelper {
}
allGpxList.add(0, new GPXInfo(activity.getString(R.string.show_current_gpx_title), 0, 0));
final ContextMenuAdapter adapter = createGpxContextMenuAdapter(allGpxList, selectedGpxList, true);
final ContextMenuAdapter adapter = createGpxContextMenuAdapter(allGpxList, selectedGpxList, true, app);
return createDialog(activity, true, true, true, callbackWithObject, allGpxList, adapter, dialogThemeRes, nightMode);
}
@ -253,7 +253,7 @@ public class GpxUiHelper {
list.add(0, new GPXInfo(activity.getString(R.string.show_current_gpx_title), 0, 0));
}
final ContextMenuAdapter adapter = createGpxContextMenuAdapter(list, null, showCurrentGpx);
final ContextMenuAdapter adapter = createGpxContextMenuAdapter(list, null, showCurrentGpx, app);
return createDialog(activity, showCurrentGpx, multipleChoice, false, callbackWithObject, list, adapter, dialogThemeRes, nightMode);
}
return null;
@ -280,16 +280,17 @@ public class GpxUiHelper {
}
}
final ContextMenuAdapter adapter = createGpxContextMenuAdapter(list, null, showCurrentGpx);
final ContextMenuAdapter adapter = createGpxContextMenuAdapter(list, null, showCurrentGpx, app);
return createSingleChoiceDialog(activity, showCurrentGpx, callbackWithObject, list, adapter);
}
return null;
}
private static ContextMenuAdapter createGpxContextMenuAdapter(List<GPXInfo> allGpxList,
List<String> selectedGpxList,
boolean showCurrentTrack) {
final ContextMenuAdapter adapter = new ContextMenuAdapter();
List<String> selectedGpxList,
boolean showCurrentTrack,
OsmandApplication app) {
final ContextMenuAdapter adapter = new ContextMenuAdapter(app);
//element position in adapter
int i = 0;
for (GPXInfo gpxInfo : allGpxList) {

View file

@ -47,6 +47,7 @@ import net.osmand.plus.mapcontextmenu.editors.RtePtEditor;
import net.osmand.plus.mapcontextmenu.editors.WptPtEditor;
import net.osmand.plus.mapcontextmenu.other.MapMultiSelectionMenu;
import net.osmand.plus.mapcontextmenu.other.ShareMenu;
import net.osmand.plus.mapcontextmenu.AdditionalActionsBottomSheetDialogFragment.ContextMenuItemClickListener;
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.transport.TransportStopRoute;
@ -1061,16 +1062,32 @@ public class MapContextMenu extends MenuTitleController implements StateChangedL
}
}
public void buttonMorePressed() {
public ContextMenuAdapter getActionsContextMenuAdapter(boolean all) {
MapActivity mapActivity = getMapActivity();
final ContextMenuAdapter menuAdapter = new ContextMenuAdapter(getMyApplication());
if (mapActivity != null) {
final ContextMenuAdapter menuAdapter = new ContextMenuAdapter();
LatLon latLon = getLatLon();
for (OsmandMapLayer layer : mapActivity.getMapView().getLayers()) {
layer.populateObjectContextMenu(latLon, getObject(), menuAdapter, mapActivity);
}
mapActivity.getMapActions().addActionsToAdapter(all ? 0 : latLon.getLatitude(), all ? 0 : latLon.getLatitude(), menuAdapter, getObject(), all);
}
return menuAdapter;
}
mapActivity.getMapActions().contextMenuPoint(latLon.getLatitude(), latLon.getLongitude(), menuAdapter, getObject());
public ContextMenuItemClickListener getContextMenuItemClickListener(ContextMenuAdapter menuAdapter) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
LatLon latLon = getLatLon();
return mapActivity.getMapActions().getContextMenuItemClickListener(latLon.getLatitude(), latLon.getLatitude(), menuAdapter);
}
return null;
}
public void showAdditionalActionsFragment(final ContextMenuAdapter adapter, ContextMenuItemClickListener listener) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.getMapActions().showAdditionalActionsFragment(adapter, listener);
}
}

View file

@ -51,6 +51,8 @@ import net.osmand.data.QuadPoint;
import net.osmand.data.QuadRect;
import net.osmand.data.RotatedTileBox;
import net.osmand.data.TransportRoute;
import net.osmand.plus.ContextMenuAdapter;
import net.osmand.plus.ContextMenuItem;
import net.osmand.plus.LockableScrollView;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
@ -68,6 +70,7 @@ import net.osmand.plus.mapcontextmenu.MenuController.MenuState;
import net.osmand.plus.mapcontextmenu.MenuController.TitleButtonController;
import net.osmand.plus.mapcontextmenu.MenuController.TitleProgressController;
import net.osmand.plus.mapcontextmenu.controllers.TransportStopController;
import net.osmand.plus.mapcontextmenu.AdditionalActionsBottomSheetDialogFragment.ContextMenuItemClickListener;
import net.osmand.plus.routepreparationmenu.ChooseRouteFragment;
import net.osmand.plus.routepreparationmenu.MapRouteInfoMenu;
import net.osmand.plus.transport.TransportStopRoute;
@ -83,6 +86,7 @@ import net.osmand.util.Algorithms;
import java.util.ArrayList;
import java.util.List;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_MORE_ID;
import static net.osmand.plus.mapcontextmenu.MenuBuilder.SHADOW_HEIGHT_TOP_DP;
@ -547,7 +551,7 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
View buttonsTopBorder = view.findViewById(R.id.buttons_top_border);
buttonsBottomBorder.setBackgroundColor(ContextCompat.getColor(mapActivity, nightMode ? R.color.ctx_menu_buttons_divider_dark : R.color.ctx_menu_buttons_divider_light));
buttonsTopBorder.setBackgroundColor(ContextCompat.getColor(mapActivity, nightMode ? R.color.ctx_menu_buttons_divider_dark : R.color.ctx_menu_buttons_divider_light));
View buttons = view.findViewById(R.id.context_menu_buttons);
LinearLayout buttons = view.findViewById(R.id.context_menu_buttons);
buttons.setBackgroundColor(ContextCompat.getColor(mapActivity, nightMode ? R.color.list_background_color_dark : R.color.activity_background_color_light));
if (!menu.buttonsVisible()) {
buttonsTopBorder.setVisibility(View.GONE);
@ -560,59 +564,31 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
}
// Action buttons
final ImageView imageFavorite = (ImageView) view.findViewById(R.id.context_menu_fav_image_view);
imageFavorite.setImageDrawable(getIcon(menu.getFavActionIconId(),
R.color.ctx_menu_buttons_icon_color));
((TextView) view.findViewById(R.id.context_menu_fav_text_view)).setText(menu.getFavActionStringId());
View favView = view.findViewById(R.id.context_menu_fav_view);
if (menu.isFavButtonEnabled()) {
favView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
menu.buttonFavoritePressed();
}
});
} else {
deactivate(favView);
}
final ImageView imageWaypoint = (ImageView) view.findViewById(R.id.context_menu_route_image_view);
imageWaypoint.setImageDrawable(getIcon(menu.getWaypointActionIconId(),
R.color.ctx_menu_buttons_icon_color));
((TextView) view.findViewById(R.id.context_menu_route_text_view)).setText(menu.getWaypointActionStringId());
View waypointView = view.findViewById(R.id.context_menu_route_view);
if (menu.isButtonWaypointEnabled()) {
waypointView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
menu.buttonWaypointPressed();
}
});
} else {
deactivate(waypointView);
}
final ImageView imageShare = (ImageView) view.findViewById(R.id.context_menu_share_image_view);
imageShare.setImageDrawable(getIcon(R.drawable.map_action_gshare_dark,
R.color.ctx_menu_buttons_icon_color));
View shareView = view.findViewById(R.id.context_menu_share_view);
shareView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
menu.buttonSharePressed();
// TODO refactor section
ContextMenuAdapter adapter = menu.getActionsContextMenuAdapter(false);
List<ContextMenuItem> items = adapter.getItems();
ContextMenuAdapter mainAdapter = new ContextMenuAdapter(requireMyApplication());
ContextMenuAdapter additionalAdapter = new ContextMenuAdapter(requireMyApplication());
for (int i = 0; i < items.size(); i++) {
if (i < 4) {
mainAdapter.addItem(items.get(i));
} else {
additionalAdapter.addItem(items.get(i));
}
});
}
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
1f
);
buttons.removeAllViews();
ContextMenuItemClickListener mainListener = menu.getContextMenuItemClickListener(mainAdapter);
ContextMenuItemClickListener additionalListener = menu.getContextMenuItemClickListener(additionalAdapter);
final ImageView imageMore = (ImageView) view.findViewById(R.id.context_menu_more_image_view);
imageMore.setImageDrawable(getIcon(R.drawable.map_overflow_menu_white,
R.color.ctx_menu_buttons_icon_color));
View moreView = view.findViewById(R.id.context_menu_more_view);
moreView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
menu.buttonMorePressed();
}
});
for (int i = 0; i < 4; i++) {
buttons.addView(getActionView(items.get(i), i, mainAdapter, additionalAdapter, mainListener, additionalListener), params);
}
buttons.setGravity(Gravity.CENTER);
//Bottom buttons
int bottomButtonsColor = nightMode ? R.color.ctx_menu_controller_button_text_color_dark_n : R.color.ctx_menu_controller_button_text_color_light_n;
@ -671,6 +647,38 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
return view;
}
private View getActionView(ContextMenuItem contextMenuItem,
final int position,
final ContextMenuAdapter mainAdapter,
final ContextMenuAdapter additionalAdapter,
final ContextMenuItemClickListener mainListener,
final ContextMenuItemClickListener additionalListener) {
UiUtilities uiUtilities = requireMyApplication().getUIUtilities();
LayoutInflater inflater = UiUtilities.getInflater(getMyApplication(), nightMode);
View view = inflater.inflate(R.layout.context_menu_action_item, null);
LinearLayout item = view.findViewById(R.id.item);
ImageView icon = view.findViewById(R.id.icon);
TextView title = view.findViewById(R.id.text);
icon.setImageDrawable(uiUtilities.getIcon(contextMenuItem.getIcon(), nightMode));
title.setText(contextMenuItem.getTitle());
if (contextMenuItem.getId().equals(MAP_CONTEXT_MENU_MORE_ID)) {
item.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
menu.showAdditionalActionsFragment(additionalAdapter, additionalListener);
}
});
} else {
item.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mainListener.onItemClick(position);
}
});
}
return view;
}
@Nullable
private TransportStopRouteAdapter createTransportStopRouteAdapter(List<TransportStopRoute> routes, boolean needMoreItem) {
OsmandApplication app = getMyApplication();
@ -1377,11 +1385,6 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
public void rebuildMenu(boolean centered) {
OsmandApplication app = getMyApplication();
if (app != null && view != null) {
final ImageView buttonFavorite = (ImageView) view.findViewById(R.id.context_menu_fav_image_view);
buttonFavorite.setImageDrawable(getIcon(menu.getFavActionIconId(), R.color.ctx_menu_buttons_icon_color));
String favActionString = getString(menu.getFavActionStringId());
((TextView) view.findViewById(R.id.context_menu_fav_text_view)).setText(favActionString);
buildHeader();
LinearLayout bottomLayout = (LinearLayout) view.findViewById(R.id.context_menu_bottom_view);

View file

@ -84,7 +84,7 @@ public class RoutePreferencesMenu {
Object obj = listAdapter.getItem(item);
if (obj instanceof LocalRoutingParameterGroup) {
final LocalRoutingParameterGroup group = (LocalRoutingParameterGroup) obj;
final ContextMenuAdapter adapter = new ContextMenuAdapter();
final ContextMenuAdapter adapter = new ContextMenuAdapter(app);
int i = 0;
int selectedIndex = -1;
for (LocalRoutingParameter p : group.getRoutingParameters()) {

View file

@ -475,7 +475,7 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
((FavoritesActivity) getActivity()).updateListViewFooter(footerView);
// TODO Rewrite without ContextMenuAdapter
optionsMenuAdapter = new ContextMenuAdapter();
optionsMenuAdapter = new ContextMenuAdapter(app);
ItemClickListener listener = new ContextMenuAdapter.ItemClickListener() {
@Override
public boolean onContextMenuClick(ArrayAdapter<ContextMenuItem> adapter, final int itemId, int pos, boolean isChecked, int[] viewCoordinates) {
@ -760,7 +760,7 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
private void moveGpx(final GpxInfo info) {
final ContextMenuAdapter menuAdapter = new ContextMenuAdapter();
final ContextMenuAdapter menuAdapter = new ContextMenuAdapter(app);
ContextMenuItem.ItemBuilder itemBuilder = new ContextMenuItem.ItemBuilder();
final List<File> dirs = new ArrayList<>();

View file

@ -26,7 +26,7 @@ public class OsmNotesMenu {
private static Integer[] zoomIntValues = {8, 9, 10, 11, 12, 13, 14, 15, 16};
public static ContextMenuAdapter createListAdapter(final MapActivity mapActivity) {
ContextMenuAdapter adapter = new ContextMenuAdapter();
ContextMenuAdapter adapter = new ContextMenuAdapter(mapActivity.getMyApplication());
boolean nightMode = mapActivity.getMyApplication().getDaynightHelper().isNightModeForMapControls();
adapter.setDefaultLayoutId(R.layout.list_item_icon_and_menu);
adapter.setProfileDependent(true);

View file

@ -288,7 +288,7 @@ public class ShowHidePoiAction extends QuickAction {
private void showSingleChoicePoiFilterDialog(final OsmandApplication app, final MapActivity activity, final Adapter filtersAdapter) {
final PoiFiltersHelper poiFilters = app.getPoiFilters();
final ContextMenuAdapter adapter = new ContextMenuAdapter();
final ContextMenuAdapter adapter = new ContextMenuAdapter(app);
final List<PoiUIFilter> list = new ArrayList<>();

View file

@ -113,7 +113,7 @@ public class RoutingOptionsHelper {
}
public void selectVoiceGuidance(final MapActivity mapActivity, final CallbackWithObject<String> callback, ApplicationMode applicationMode) {
final ContextMenuAdapter adapter = new ContextMenuAdapter();
final ContextMenuAdapter adapter = new ContextMenuAdapter(app);
String[] entries;
final String[] entrieValues;
@ -310,7 +310,7 @@ public class RoutingOptionsHelper {
public void showLocalRoutingParameterGroupDialog(final LocalRoutingParameterGroup group, final MapActivity mapActivity, final OnClickListener listener) {
OsmandSettings settings = app.getSettings();
final ContextMenuAdapter adapter = new ContextMenuAdapter();
final ContextMenuAdapter adapter = new ContextMenuAdapter(app);
int i = 0;
int selectedIndex = -1;
for (LocalRoutingParameter p : group.getRoutingParameters()) {

View file

@ -0,0 +1,473 @@
package net.osmand.plus.settings;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import net.osmand.AndroidUtils;
import net.osmand.PlatformUtil;
import net.osmand.plus.ApplicationMode;
import net.osmand.plus.ContextMenuAdapter;
import net.osmand.plus.ContextMenuItem;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.MapActivityActions;
import net.osmand.plus.base.BaseOsmAndFragment;
import net.osmand.plus.dialogs.ConfigureMapMenu;
import net.osmand.plus.mapcontextmenu.MapContextMenu;
import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet;
import net.osmand.plus.settings.ConfigureMenuRootFragment.ScreenType;
import net.osmand.plus.settings.bottomsheets.ChangeGeneralProfilesPrefBottomSheet;
import net.osmand.plus.views.controls.ReorderItemTouchHelperCallback;
import net.osmand.plus.settings.RearrangeMenuItemsAdapter.RearrangeMenuAdapterItem;
import net.osmand.plus.settings.RearrangeMenuItemsAdapter.MenuItemsAdapterListener;
import org.apache.commons.logging.Log;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_MORE_ID;
import static net.osmand.plus.settings.RearrangeMenuItemsAdapter.AdapterItemType.BUTTON;
import static net.osmand.plus.settings.RearrangeMenuItemsAdapter.AdapterItemType.DESCRIPTION;
import static net.osmand.plus.settings.RearrangeMenuItemsAdapter.AdapterItemType.DIVIDER;
import static net.osmand.plus.settings.RearrangeMenuItemsAdapter.AdapterItemType.HEADER;
import static net.osmand.plus.settings.RearrangeMenuItemsAdapter.AdapterItemType.MENU_ITEM;
public class ConfigureMenuItemsFragment extends BaseOsmAndFragment
implements SelectCopyAppModeBottomSheet.CopyAppModePrefsListener {
public static final String TAG = ConfigureMenuItemsFragment.class.getName();
public static final int MAIN_BUTTONS_QUANTITY = 4;
private static final Log LOG = PlatformUtil.getLog(ConfigureMenuItemsFragment.class.getName());
private static final String APP_MODE_KEY = "app_mode_key";
private static final String ITEM_TYPE_KEY = "item_type_key";
private static final String ITEMS_ORDER_KEY = "items_order_key";
private static final String HIDDEN_ITEMS_KEY = "hidden_items_key";
private static final String CONFIGURE_MENU_ITEMS_TAG = "configure_menu_items_tag";
private RearrangeMenuItemsAdapter rearrangeAdapter;
private HashMap<String, Integer> menuItemsOrder;
private ContextMenuAdapter contextMenuAdapter;
private List<String> hiddenMenuItems;
private ApplicationMode appMode;
private LayoutInflater mInflater;
private OsmandApplication app;
private ScreenType screenType;
private boolean nightMode;
private boolean wasReset = false;
private boolean isChanged = false;
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putStringArrayList(HIDDEN_ITEMS_KEY, new ArrayList<>(hiddenMenuItems));
outState.putSerializable(ITEMS_ORDER_KEY, menuItemsOrder);
outState.putSerializable(ITEM_TYPE_KEY, screenType);
outState.putString(APP_MODE_KEY, appMode.getStringKey());
}
public static ConfigureMenuItemsFragment showInstance(
@NonNull FragmentManager fm,
@NonNull ApplicationMode appMode,
@NonNull ScreenType type) {
ConfigureMenuItemsFragment fragment = new ConfigureMenuItemsFragment();
fragment.setScreenType(type);
fragment.setAppMode(appMode);
fm.beginTransaction()
.replace(R.id.fragmentContainer, fragment, TAG)
.addToBackStack(CONFIGURE_MENU_ITEMS_TAG)
.commitAllowingStateLoss();
return fragment;
}
public void setAppMode(ApplicationMode appMode) {
this.appMode = appMode;
}
public ApplicationMode getAppMode() {
return appMode != null ? appMode : app.getSettings().getApplicationMode();
}
@Override
public int getStatusBarColorId() {
View view = getView();
if (view != null && Build.VERSION.SDK_INT >= 23 && !nightMode) {
view.setSystemUiVisibility(view.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
return nightMode ? R.color.activity_background_dark : R.color.activity_background_light;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = requireMyApplication();
nightMode = !app.getSettings().isLightContent();
mInflater = UiUtilities.getInflater(app, nightMode);
instantiateContextMenuAdapter();
if (savedInstanceState != null
&& savedInstanceState.containsKey(ITEM_TYPE_KEY)
&& savedInstanceState.containsKey(HIDDEN_ITEMS_KEY)
&& savedInstanceState.containsKey(ITEMS_ORDER_KEY)) {
appMode = ApplicationMode.valueOfStringKey(savedInstanceState.getString(APP_MODE_KEY), null);
screenType = (ScreenType) savedInstanceState.getSerializable(ITEM_TYPE_KEY);
hiddenMenuItems = savedInstanceState.getStringArrayList(HIDDEN_ITEMS_KEY);
menuItemsOrder = (HashMap<String, Integer>) savedInstanceState.getSerializable(ITEMS_ORDER_KEY);
} else {
hiddenMenuItems = new ArrayList<>(getSettingForScreen(app, screenType).getModeValue(appMode).getHiddenIds());
menuItemsOrder = new HashMap<>();
List<String> orderIds = getSettingForScreen(app, screenType).getModeValue(appMode).getOrderIds();
for (int i = 0; i < orderIds.size(); i++) {
menuItemsOrder.put(orderIds.get(i), i);
}
}
}
private void instantiateContextMenuAdapter() {
Activity activity = getActivity();
if (activity instanceof MapActivity) {
switch (screenType) {
case DRAWER:
MapActivityActions mapActivityActions = new MapActivityActions((MapActivity) activity);
contextMenuAdapter = mapActivityActions.createMainOptionsMenu();
break;
case CONFIGURE_MAP:
ConfigureMapMenu configureMapMenu = new ConfigureMapMenu();
contextMenuAdapter = configureMapMenu.createListAdapter((MapActivity) activity);
break;
case CONTEXT_MENU_ACTIONS:
MapContextMenu menu = ((MapActivity) activity).getContextMenu();
contextMenuAdapter = menu.getActionsContextMenuAdapter(true);
break;
}
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable Bundle savedInstanceState) {
View root = mInflater.inflate(R.layout.edit_arrangement_list_fragment, container, false);
Toolbar toolbar = root.findViewById(R.id.toolbar);
TextView toolbarTitle = root.findViewById(R.id.toolbar_title);
ImageButton toolbarButton = root.findViewById(R.id.close_button);
RecyclerView recyclerView = root.findViewById(R.id.profiles_list);
recyclerView.setPadding(0, 0, 0, (int) app.getResources().getDimension(R.dimen.dialog_button_ex_min_width));
toolbar.setBackgroundColor(nightMode
? getResources().getColor(R.color.list_background_color_dark)
: getResources().getColor(R.color.list_background_color_light));
toolbarTitle.setTextColor(nightMode
? getResources().getColor(R.color.text_color_primary_dark)
: getResources().getColor(R.color.list_background_color_dark));
toolbarButton.setImageDrawable(getPaintedContentIcon(R.drawable.ic_arrow_back, getResources().getColor(R.color.text_color_secondary_light)));
toolbarTitle.setText(screenType.titleRes);
toolbarButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
exitFragment();
}
});
rearrangeAdapter = new RearrangeMenuItemsAdapter(app, getAdapterItems());
recyclerView.setLayoutManager(new LinearLayoutManager(app));
final ItemTouchHelper touchHelper = new ItemTouchHelper(new ReorderItemTouchHelperCallback(rearrangeAdapter));
touchHelper.attachToRecyclerView(recyclerView);
MenuItemsAdapterListener listener = new MenuItemsAdapterListener() {
private int fromPosition;
private int toPosition;
@Override
public void onDragStarted(RecyclerView.ViewHolder holder) {
fromPosition = holder.getAdapterPosition();
touchHelper.startDrag(holder);
}
@Override
public void onDragOrSwipeEnded(RecyclerView.ViewHolder holder) {
toPosition = holder.getAdapterPosition();
if (toPosition >= 0 && fromPosition >= 0 && toPosition != fromPosition) {
rearrangeAdapter.notifyDataSetChanged();
}
}
@Override
public void onButtonClicked(int position) {
RearrangeMenuAdapterItem rearrangeMenuAdapterItem = rearrangeAdapter.getItem(position);
if (rearrangeMenuAdapterItem.getValue() instanceof ContextMenuItem) {
ContextMenuItem menuItemBase = (ContextMenuItem) rearrangeMenuAdapterItem.getValue();
menuItemBase.setHidden(!menuItemBase.isHidden());
if (menuItemBase.isHidden()) {
hiddenMenuItems.add(menuItemBase.getId());
} else {
hiddenMenuItems.remove(menuItemBase.getId());
}
wasReset = false;
isChanged = true;
rearrangeAdapter.updateItems(getAdapterItems());
}
}
@Override
public void onItemMoved(String id, int position) {
menuItemsOrder.put(id, position);
wasReset = false;
isChanged = true;
}
};
rearrangeAdapter.setListener(listener);
recyclerView.setAdapter(rearrangeAdapter);
View cancelButton = root.findViewById(R.id.dismiss_button);
UiUtilities.setupDialogButton(nightMode, cancelButton, UiUtilities.DialogButtonType.SECONDARY, R.string.shared_string_cancel);
cancelButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FragmentActivity fragmentActivity = getActivity();
if (fragmentActivity != null) {
fragmentActivity.onBackPressed();
}
}
});
root.findViewById(R.id.buttons_divider).setVisibility(View.VISIBLE);
View applyButton = root.findViewById(R.id.right_bottom_button);
UiUtilities.setupDialogButton(nightMode, applyButton, UiUtilities.DialogButtonType.PRIMARY, R.string.shared_string_apply);
applyButton.setVisibility(View.VISIBLE);
applyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
List<ContextMenuItem> defItems = contextMenuAdapter.getDefaultItems();
List<String> ids = new ArrayList<>();
if (!menuItemsOrder.isEmpty()) {
sortByCustomOrder(defItems, menuItemsOrder);
for (ContextMenuItem item : defItems) {
ids.add(item.getId());
}
}
FragmentManager fm = getFragmentManager();
OsmandSettings.ContextMenuItemsSettings prefToSave = new OsmandSettings.ContextMenuItemsSettings(hiddenMenuItems, ids);
if (fm != null) {
ChangeGeneralProfilesPrefBottomSheet.showInstance(fm,
getSettingForScreen(app, screenType).getId(),
prefToSave,
getTargetFragment(),
false,
appMode,
new ChangeGeneralProfilesPrefBottomSheet.OnChangeSettingListener() {
@Override
public void onApplied() {
dismissFragment();
}
@Override
public void onDiscard() {
}
});
}
}
});
if (Build.VERSION.SDK_INT >= 21) {
AndroidUtils.addStatusBarPadding21v(app, root);
}
return root;
}
private List<RearrangeMenuAdapterItem> getAdapterItems() {
List<RearrangeMenuAdapterItem> items = new ArrayList<>();
items.add(new RearrangeMenuAdapterItem(DESCRIPTION, screenType));
List<RearrangeMenuAdapterItem> visible = getItemsForRearrangeAdapter(hiddenMenuItems, wasReset ? null : menuItemsOrder, false);
List<RearrangeMenuAdapterItem> hiddenItems = getItemsForRearrangeAdapter(hiddenMenuItems, wasReset ? null : menuItemsOrder, true);
if (screenType == ScreenType.CONTEXT_MENU_ACTIONS) {
for (int i = 0; i < visible.size(); i++) {
ContextMenuItem value = (ContextMenuItem) visible.get(i).getValue();
if (value.getId() != null && value.getId().equals(MAP_CONTEXT_MENU_MORE_ID)) {
int buttonMoreIndex = MAIN_BUTTONS_QUANTITY - 1;
if (i > buttonMoreIndex) {
RearrangeMenuAdapterItem third = visible.get(buttonMoreIndex);
visible.set(buttonMoreIndex, visible.get(i));
menuItemsOrder.put(((ContextMenuItem) third.getValue()).getId(), i);
menuItemsOrder.put(((ContextMenuItem) visible.get(i).getValue()).getId(), buttonMoreIndex);
}
}
}
List<RearrangeMenuAdapterItem> main = new ArrayList<>();
int actionsIndex = Math.min(MAIN_BUTTONS_QUANTITY, visible.size());
for (int i = 0; i < actionsIndex; i++) {
main.add(visible.get(i));
}
items.add(new RearrangeMenuAdapterItem(HEADER, new RearrangeMenuItemsAdapter.HeaderItem(R.string.main_actions, R.string.main_actions_descr)));
items.addAll(main);
items.add(new RearrangeMenuAdapterItem(HEADER, new RearrangeMenuItemsAdapter.HeaderItem(R.string.additional_actions, R.string.additional_actions_descr)));
List<RearrangeMenuAdapterItem> additional = new ArrayList<>();
for (int i = MAIN_BUTTONS_QUANTITY; i < visible.size(); i++) {
additional.add(visible.get(i));
}
items.addAll(additional);
} else {
items.addAll(visible);
}
if (!hiddenItems.isEmpty()) {
items.add(new RearrangeMenuAdapterItem(HEADER, new RearrangeMenuItemsAdapter.HeaderItem(R.string.shared_string_hidden, R.string.hidden_items_descr)));
items.addAll(hiddenItems);
}
items.add(new RearrangeMenuAdapterItem(DIVIDER, 1));
items.add(new RearrangeMenuAdapterItem(BUTTON, new RearrangeMenuItemsAdapter.ButtonItem(
R.string.reset_to_default,
R.drawable.ic_action_reset_to_default_dark,
new View.OnClickListener() {
@Override
public void onClick(View view) {
hiddenMenuItems.clear();
menuItemsOrder.clear();
wasReset = true;
isChanged = true;
getSettingForScreen(app, screenType).resetModeToDefault(appMode);
instantiateContextMenuAdapter();
rearrangeAdapter.updateItems(getAdapterItems());
}
})));
items.add(new RearrangeMenuAdapterItem(BUTTON, new RearrangeMenuItemsAdapter.ButtonItem(
R.string.copy_from_other_profile,
R.drawable.ic_action_copy,
new View.OnClickListener() {
@Override
public void onClick(View view) {
FragmentManager fm = getFragmentManager();
if (fm != null) {
SelectCopyAppModeBottomSheet.showInstance(
fm,
ConfigureMenuItemsFragment.this,
false,
appMode
);
}
}
})));
return items;
}
public void exitFragment() {
if (isChanged) {
showExitDialog();
} else {
dismissFragment();
}
}
public void showExitDialog() {
Context themedContext = UiUtilities.getThemedContext(getActivity(), nightMode);
AlertDialog.Builder dismissDialog = new AlertDialog.Builder(themedContext);
dismissDialog.setTitle(getString(R.string.shared_string_dismiss));
dismissDialog.setMessage(getString(R.string.exit_without_saving));
dismissDialog.setNegativeButton(R.string.shared_string_cancel, null);
dismissDialog.setPositiveButton(R.string.shared_string_exit, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dismissFragment();
}
});
dismissDialog.show();
}
private void dismissFragment() {
FragmentManager fm = getFragmentManager();
if (fm != null && !fm.isStateSaved()) {
getFragmentManager().popBackStack(CONFIGURE_MENU_ITEMS_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
private void setScreenType(@NonNull ScreenType screenType) {
this.screenType = screenType;
}
@Override
public void copyAppModePrefs(ApplicationMode appMode) {
if (appMode != null) {
List<OsmandSettings.OsmandPreference> prefs = new ArrayList<>();
prefs.add(getSettingForScreen(app, screenType));
app.getSettings().copyProfilePreferences(appMode, this.appMode, prefs);
dismissFragment();
}
}
public static OsmandSettings.ContextMenuItemsPreference getSettingForScreen(OsmandApplication app, ScreenType screenType) throws IllegalArgumentException {
switch (screenType) {
case DRAWER:
return app.getSettings().DRAWER_ITEMS;
case CONFIGURE_MAP:
return app.getSettings().CONFIGURE_MAP_ITEMS;
case CONTEXT_MENU_ACTIONS:
return app.getSettings().CONTEXT_MENU_ACTIONS_ITEMS;
default:
throw new IllegalArgumentException("Unsupported screen type");
}
}
private void initDefaultOrders(@NonNull List<ContextMenuItem> items) {
for (int i = 0; i < items.size(); i++) {
items.get(i).setOrder(i);
}
}
public List<RearrangeMenuAdapterItem> getItemsForRearrangeAdapter(@Nullable List<String> hiddenItemsIds, @Nullable HashMap<String, Integer> itemsOrderIds, boolean hidden) {
List<ContextMenuItem> defItems = contextMenuAdapter.getDefaultItems();
if (itemsOrderIds == null || itemsOrderIds.isEmpty()) {
initDefaultOrders(defItems);
} else {
sortByCustomOrder(defItems, itemsOrderIds);
}
List<RearrangeMenuAdapterItem> visibleItems = new ArrayList<>();
List<RearrangeMenuAdapterItem> hiddenItems = new ArrayList<>();
for (ContextMenuItem item : defItems) {
String id = item.getId();
if (hiddenItemsIds != null && hiddenItemsIds.contains(id)) {
item.setHidden(true);
hiddenItems.add(new RearrangeMenuAdapterItem(MENU_ITEM, item));
} else {
item.setHidden(false);
visibleItems.add(new RearrangeMenuAdapterItem(MENU_ITEM, item));
}
}
return hidden ? hiddenItems : visibleItems;
}
private void sortByCustomOrder(List<ContextMenuItem> defItems, HashMap<String, Integer> itemsOrderIds) {
for (ContextMenuItem item : defItems) {
Integer order = itemsOrderIds.get(item.getId());
if (order != null) {
item.setOrder(order);
}
}
Collections.sort(defItems, new Comparator<ContextMenuItem>() {
@Override
public int compare(ContextMenuItem item1, ContextMenuItem item2) {
int order1 = item1.getOrder();
int order2 = item2.getOrder();
return (order1 < order2) ? -1 : ((order1 == order2) ? 0 : 1);
}
});
}
}

View file

@ -0,0 +1,326 @@
package net.osmand.plus.settings;
import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import net.osmand.AndroidUtils;
import net.osmand.PlatformUtil;
import net.osmand.plus.ApplicationMode;
import net.osmand.plus.ContextMenuAdapter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.MapActivityActions;
import net.osmand.plus.activities.PluginsActivity;
import net.osmand.plus.base.BaseOsmAndFragment;
import net.osmand.plus.dialogs.ConfigureMapMenu;
import net.osmand.plus.helpers.FontCache;
import net.osmand.plus.mapcontextmenu.MapContextMenu;
import net.osmand.plus.widgets.style.CustomTypefaceSpan;
import org.apache.commons.logging.Log;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ConfigureMenuRootFragment extends BaseOsmAndFragment {
public static final String TAG = ConfigureMenuRootFragment.class.getName();
private static final String APP_MODE_KEY = "app_mode_key";
private static final Log LOG = PlatformUtil.getLog(TAG);
private OsmandApplication app;
private LayoutInflater mInflater;
private boolean nightMode;
private ApplicationMode appMode;
public static boolean showInstance(@NonNull FragmentManager fragmentManager,
Fragment target,
@NonNull ApplicationMode appMode) {
try {
ConfigureMenuRootFragment fragment = new ConfigureMenuRootFragment();
fragment.setAppMode(appMode);
fragment.setTargetFragment(target, 0);
fragmentManager.beginTransaction()
.replace(R.id.fragmentContainer, fragment, TAG)
.addToBackStack(null)
.commitAllowingStateLoss();
return true;
} catch (RuntimeException e) {
return false;
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
appMode = ApplicationMode.valueOfStringKey(savedInstanceState.getString(APP_MODE_KEY), null);
}
app = requireMyApplication();
nightMode = !app.getSettings().isLightContent();
mInflater = UiUtilities.getInflater(app, nightMode);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View root = mInflater.inflate(R.layout.fragment_ui_customization, container, false);
Toolbar toolbar = root.findViewById(R.id.toolbar);
TextView toolbarTitle = root.findViewById(R.id.toolbar_title);
TextView toolbarSubTitle = root.findViewById(R.id.toolbar_subtitle);
ImageButton toolbarButton = root.findViewById(R.id.close_button);
RecyclerView recyclerView = root.findViewById(R.id.list);
toolbar.setBackgroundColor(nightMode
? getResources().getColor(R.color.list_background_color_dark)
: getResources().getColor(R.color.list_background_color_light));
toolbarTitle.setTextColor(nightMode
? getResources().getColor(R.color.text_color_primary_dark)
: getResources().getColor(R.color.list_background_color_dark));
toolbarSubTitle.setTextColor(getResources().getColor(R.color.text_color_secondary_light));
toolbarButton.setImageDrawable(getPaintedContentIcon(R.drawable.ic_arrow_back, getResources().getColor(R.color.text_color_secondary_light)));
toolbarButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
FragmentManager fm = getFragmentManager();
if (fm != null) {
fm.popBackStack();
}
}
});
toolbarTitle.setText(R.string.ui_customization);
toolbarSubTitle.setText(appMode.toHumanString());
toolbarSubTitle.setVisibility(View.VISIBLE);
List<Object> items = new ArrayList<>();
String plugins = getString(R.string.prefs_plugins);
String description = String.format(getString(R.string.ui_customization_description), plugins);
items.add(description);
items.addAll(Arrays.asList(ScreenType.values()));
CustomizationItemsAdapter adapter = new CustomizationItemsAdapter(items, new OnCustomizationItemClickListener() {
@Override
public void onItemClick(ScreenType type) {
FragmentManager fm = getFragmentManager();
if (fm != null) {
ConfigureMenuItemsFragment.showInstance(fm, appMode, type);
}
}
});
recyclerView.setLayoutManager(new LinearLayoutManager(app));
recyclerView.setAdapter(adapter);
if (Build.VERSION.SDK_INT >= 21) {
AndroidUtils.addStatusBarPadding21v(app, root);
}
return root;
}
@Override
public int getStatusBarColorId() {
View view = getView();
if (view != null && Build.VERSION.SDK_INT >= 23 && !nightMode) {
view.setSystemUiVisibility(view.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
return nightMode ? R.color.activity_background_dark : R.color.activity_background_light;
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(APP_MODE_KEY, getAppMode().getStringKey());
}
public void setAppMode(ApplicationMode appMode) {
this.appMode = appMode;
}
public ApplicationMode getAppMode() {
return appMode != null ? appMode : app.getSettings().getApplicationMode();
}
private class CustomizationItemsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int DESCRIPTION_TYPE = 0;
private static final int ITEM_TYPE = 1;
private List<Object> items;
private OnCustomizationItemClickListener listener;
CustomizationItemsAdapter(List<Object> items, OnCustomizationItemClickListener listener) {
this.items = items;
this.listener = listener;
}
@Override
public int getItemViewType(int position) {
if (items.get(position) instanceof String) {
return DESCRIPTION_TYPE;
} else {
return ITEM_TYPE;
}
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == DESCRIPTION_TYPE) {
View view = mInflater.inflate(R.layout.list_item_description_with_image, parent, false);
return new DescriptionHolder(view);
} else {
View view = mInflater.inflate(R.layout.list_item_ui_customization, parent, false);
return new ItemHolder(view);
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
final Object currentItem = items.get(position);
if (holder instanceof DescriptionHolder) {
DescriptionHolder descriptionHolder = (DescriptionHolder) holder;
String plugins = getString(R.string.prefs_plugins);
setupClickableText(
descriptionHolder.description, (String) currentItem, plugins, new Intent(app, PluginsActivity.class));
descriptionHolder.image.setVisibility(View.GONE);
} else {
final ScreenType item = (ScreenType) currentItem;
ItemHolder itemHolder = (ItemHolder) holder;
itemHolder.icon.setImageResource(item.iconRes);
itemHolder.title.setText(item.titleRes);
itemHolder.subTitle.setText(getSubTitleText(item));
itemHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
listener.onItemClick(item);
}
});
}
}
@Override
public int getItemCount() {
return items.size();
}
private void setupClickableText(TextView textView, String text, String clickableText, final Intent intent) {
SpannableString spannableString = new SpannableString(text);
ClickableSpan clickableSpan = new ClickableSpan() {
@Override
public void onClick(@NonNull View view) {
startActivity(intent);
}
};
try {
int startIndex = text.indexOf(clickableText);
spannableString.setSpan(new CustomTypefaceSpan(FontCache.getRobotoMedium(app)), startIndex, startIndex + clickableText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spannableString.setSpan(clickableSpan, startIndex, startIndex + clickableText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(spannableString);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setHighlightColor(nightMode
? getResources().getColor(R.color.active_color_primary_dark)
: getResources().getColor(R.color.active_color_primary_light));
} catch (RuntimeException e) {
LOG.error("Error trying to find index of " + clickableText + " " + e);
}
}
private String getSubTitleText(ScreenType type) {
ContextMenuAdapter contextMenuAdapter = null;
Activity activity = getActivity();
if (activity instanceof MapActivity) {
switch (type) {
case DRAWER:
MapActivityActions mapActivityActions = new MapActivityActions((MapActivity) activity);
contextMenuAdapter = mapActivityActions.createMainOptionsMenu();
break;
case CONFIGURE_MAP:
ConfigureMapMenu configureMapMenu = new ConfigureMapMenu();
contextMenuAdapter = configureMapMenu.createListAdapter((MapActivity) activity);
break;
case CONTEXT_MENU_ACTIONS:
MapContextMenu menu = ((MapActivity) activity).getContextMenu();
contextMenuAdapter = menu.getActionsContextMenuAdapter(true);
break;
}
int hiddenCount = ConfigureMenuItemsFragment.getSettingForScreen(app, type).getModeValue(appMode).getHiddenIds().size();
int allCount = contextMenuAdapter.getDefaultItems().size();
String amount = getString(R.string.n_items_of_z, String.valueOf(allCount - hiddenCount), String.valueOf(allCount));
return getString(R.string.ltr_or_rtl_combine_via_colon, getString(R.string.shared_string_items), amount);
}
return "";
}
class DescriptionHolder extends RecyclerView.ViewHolder {
ImageView image;
TextView description;
DescriptionHolder(@NonNull View itemView) {
super(itemView);
image = itemView.findViewById(R.id.image);
description = itemView.findViewById(R.id.description);
}
}
class ItemHolder extends RecyclerView.ViewHolder {
ImageView icon;
TextView title;
TextView subTitle;
ItemHolder(@NonNull View itemView) {
super(itemView);
icon = itemView.findViewById(R.id.icon);
title = itemView.findViewById(R.id.title);
subTitle = itemView.findViewById(R.id.sub_title);
}
}
}
public enum ScreenType {
DRAWER(R.string.shared_string_drawer, R.drawable.ic_action_drawer, R.drawable.img_settings_customize_drawer_day, R.drawable.img_settings_customize_drawer_night),
CONFIGURE_MAP(R.string.configure_map, R.drawable.ic_action_layers, R.drawable.img_settings_customize_configure_map_day, R.drawable.img_settings_customize_configure_map_night),
CONTEXT_MENU_ACTIONS(R.string.context_menu_actions, R.drawable.ic_action_context_menu, R.drawable.img_settings_customize_context_menu_day, R.drawable.img_settings_customize_context_menu_night);
@StringRes
public int titleRes;
@DrawableRes
public int iconRes;
@DrawableRes
public int imageDayRes;
@DrawableRes
public int imageNightRes;
ScreenType(int titleRes, int iconRes, int imageDayRes, int imageNightRes) {
this.titleRes = titleRes;
this.iconRes = iconRes;
this.imageDayRes = imageDayRes;
this.imageNightRes = imageNightRes;
}
}
interface OnCustomizationItemClickListener {
void onItemClick(ScreenType type);
}
}

View file

@ -71,6 +71,7 @@ public class ConfigureProfileFragment extends BaseSettingsFragment implements Co
private static final String EXPORT_PROFILE = "export_profile";
private static final String DELETE_PROFILE = "delete_profile";
private static final String PROFILE_APPEARANCE = "profile_appearance";
private static final String UI_CUSTOMIZATION = "ui_customization";
@ColorRes
protected int getBackgroundColorRes() {
@ -273,6 +274,7 @@ public class ConfigureProfileFragment extends BaseSettingsFragment implements Co
setupConfigureMapPref();
setupConfigureScreenPref();
setupProfileAppearancePref();
setupUiCustomizationPref();
PreferenceCategory pluginSettings = (PreferenceCategory) findPreference(PLUGIN_SETTINGS);
setupOsmandPluginsPref(pluginSettings);
@ -382,6 +384,17 @@ public class ConfigureProfileFragment extends BaseSettingsFragment implements Co
}
}
private void setupUiCustomizationPref() {
Context ctx = getContext();
if (ctx == null) {
return;
}
Preference uiCustomization = findPreference(UI_CUSTOMIZATION);
if (uiCustomization != null) {
uiCustomization.setIcon(getContentIcon(R.drawable.ic_action_ui_customization));
}
}
@Override
public boolean onPreferenceClick(Preference preference) {
String prefId = preference.getKey();
@ -426,6 +439,14 @@ public class ConfigureProfileFragment extends BaseSettingsFragment implements Co
}
} else if (DELETE_PROFILE.equals(prefId)) {
onDeleteProfileClick();
} else if (UI_CUSTOMIZATION.equals(prefId)) {
FragmentManager fragmentManager = getFragmentManager();
if (fragmentManager != null) {
ConfigureMenuRootFragment.showInstance(
fragmentManager,
this,
getSelectedAppMode());
}
}
return super.onPreferenceClick(preference);
}

View file

@ -0,0 +1,451 @@
package net.osmand.plus.settings;
import android.annotation.SuppressLint;
import android.graphics.drawable.Drawable;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.core.content.ContextCompat;
import androidx.core.view.MotionEventCompat;
import androidx.recyclerview.widget.RecyclerView;
import net.osmand.AndroidUtils;
import net.osmand.plus.ContextMenuItem;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.helpers.FontCache;
import net.osmand.plus.views.controls.ReorderItemTouchHelperCallback;
import net.osmand.plus.settings.ConfigureMenuRootFragment.ScreenType;
import java.util.Collections;
import java.util.List;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_BUILDS_ID;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_DIVIDER_ID;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_MORE_ID;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_RENDERING_CATEGORY_ID;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.RENDERING_ITEMS_ID_SCHEME;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.SHOW_CATEGORY_ID;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.SHOW_ITEMS_ID_SCHEME;
import static net.osmand.plus.settings.ConfigureMenuItemsFragment.MAIN_BUTTONS_QUANTITY;
public class RearrangeMenuItemsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
implements ReorderItemTouchHelperCallback.OnItemMoveCallback {
private OsmandApplication app;
private UiUtilities uiUtilities;
private boolean nightMode;
private List<RearrangeMenuAdapterItem> items;
private MenuItemsAdapterListener listener;
private int activeColorRes;
private int textColorRes;
public RearrangeMenuItemsAdapter(OsmandApplication app,
List<RearrangeMenuAdapterItem> items) {
this.app = app;
this.items = items;
uiUtilities = app.getUIUtilities();
nightMode = !app.getSettings().isLightContent();
activeColorRes = nightMode
? R.color.active_color_primary_dark
: R.color.active_color_primary_light;
textColorRes = nightMode
? R.color.text_color_primary_dark
: R.color.text_color_primary_light;
}
@Override
public int getItemViewType(int position) {
RearrangeMenuAdapterItem item = items.get(position);
return item.type.ordinal();
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
AdapterItemType type = AdapterItemType.values()[viewType];
View view;
switch (type) {
case DESCRIPTION:
view = inflater.inflate(R.layout.list_item_description_with_image, parent, false);
return new DescriptionHolder(view);
case MENU_ITEM:
view = inflater.inflate(R.layout.profile_edit_list_item, parent, false);
return new ItemHolder(view);
case DIVIDER:
view = inflater.inflate(R.layout.divider, parent, false);
return new DividerHolder(view);
case HEADER:
view = inflater.inflate(R.layout.list_item_move_header, parent, false);
return new HeaderHolder(view);
case BUTTON:
view = inflater.inflate(R.layout.preference_button, parent, false);
return new ButtonHolder(view);
default:
throw new IllegalArgumentException("Unsupported view type");
}
}
@SuppressLint("ClickableViewAccessibility")
@Override
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) {
RearrangeMenuAdapterItem item = items.get(position);
if (holder instanceof DescriptionHolder) {
DescriptionHolder h = (DescriptionHolder) holder;
ScreenType screenType = (ScreenType) item.value;
int paddingStart = (int) app.getResources().getDimension(R.dimen.toolbar_height);
int paddingTop = (int) app.getResources().getDimension(R.dimen.content_padding);
h.description.setText(String.format(app.getString(R.string.reorder_or_hide_from), app.getString(screenType.titleRes)));
h.image.setImageResource(nightMode ? screenType.imageNightRes : screenType.imageDayRes);
if (screenType == ScreenType.CONTEXT_MENU_ACTIONS) {
h.deviceImage.setImageResource(nightMode
? R.drawable.img_settings_device_bottom_dark
: R.drawable.img_settings_device_bottom_light);
h.imageContainer.setPadding(paddingStart, 0, paddingStart, paddingTop);
} else {
h.deviceImage.setImageResource(nightMode
? R.drawable.img_settings_device_top_dark
: R.drawable.img_settings_device_top_light);
h.imageContainer.setPadding(paddingStart, paddingTop, paddingStart, 0);
}
} else if (holder instanceof ItemHolder) {
final ItemHolder h = (ItemHolder) holder;
ContextMenuItem menuItem = (ContextMenuItem) item.value;
String id = menuItem.getId();
if (DRAWER_DIVIDER_ID.equals(menuItem.getId())) {
h.title.setText(R.string.shared_string_divider);
h.title.setTypeface(FontCache.getFont(app, app.getString(R.string.font_roboto_medium)));
h.title.setTextColor(app.getResources().getColor(activeColorRes));
h.title.setTextSize(TypedValue.COMPLEX_UNIT_PX, app.getResources().getDimension(R.dimen.default_list_text_size));
h.description.setText(R.string.divider_descr);
h.icon.setVisibility(View.GONE);
h.actionIcon.setVisibility(View.GONE);
h.moveIcon.setVisibility(View.VISIBLE);
h.divider.setVisibility(View.VISIBLE);
} else if (SHOW_CATEGORY_ID.equals(id)
|| MAP_RENDERING_CATEGORY_ID.equals(id)) {
h.title.setText(menuItem.getTitle());
h.title.setTypeface(FontCache.getFont(app, app.getString(R.string.font_roboto_medium)));
h.title.setTextSize(TypedValue.COMPLEX_UNIT_PX, app.getResources().getDimension(R.dimen.default_list_text_size));
h.description.setText(R.string.move_inside_category);
h.icon.setVisibility(View.GONE);
h.actionIcon.setVisibility(View.GONE);
h.moveIcon.setVisibility(View.GONE);
h.divider.setVisibility(View.VISIBLE);
h.movable = false;
} else {
if (menuItem.getIcon() != -1) {
h.icon.setImageDrawable(uiUtilities.getIcon(menuItem.getIcon(), nightMode));
h.icon.setVisibility(View.VISIBLE);
h.actionIcon.setVisibility(View.VISIBLE);
}
h.title.setTypeface(FontCache.getFont(app, app.getString(R.string.font_roboto_regular)));
h.title.setText(menuItem.getTitle());
h.title.setTextColor(app.getResources().getColor(textColorRes));
h.description.setText(getDescription(menuItem.getId()));
h.divider.setVisibility(View.GONE);
h.moveIcon.setVisibility(View.VISIBLE);
}
h.actionIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int pos = holder.getAdapterPosition();
if (listener != null && pos != RecyclerView.NO_POSITION) {
listener.onButtonClicked(pos);
}
}
});
h.moveIcon.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
listener.onDragStarted(holder);
}
return false;
}
});
if (!menuItem.isHidden()
&& !id.equals(SHOW_CATEGORY_ID)
&& !id.equals(MAP_RENDERING_CATEGORY_ID)) {
h.moveIcon.setVisibility(View.VISIBLE);
h.moveIcon.setImageDrawable(uiUtilities.getIcon(R.drawable.ic_action_item_move, nightMode));
h.actionIcon.setImageDrawable(uiUtilities.getIcon(R.drawable.ic_action_remove, R.color.color_osm_edit_delete));
} else {
h.moveIcon.setVisibility(View.GONE);
h.actionIcon.setImageDrawable(uiUtilities.getIcon(R.drawable.ic_action_undo, R.color.color_osm_edit_create));
}
if (id.equals(MAP_CONTEXT_MENU_MORE_ID)) {
h.moveIcon.setImageDrawable(uiUtilities.getIcon(R.drawable.ic_action_item_move, nightMode));
h.actionIcon.setImageDrawable(uiUtilities.getIcon(R.drawable.ic_action_remove, nightMode));
h.actionIcon.setOnClickListener(null);
}
} else if (holder instanceof HeaderHolder) {
HeaderHolder h = (HeaderHolder) holder;
HeaderItem header = (HeaderItem) item.value;
h.title.setTypeface(FontCache.getFont(app, app.getString(R.string.font_roboto_medium)));
h.title.setTextSize(TypedValue.COMPLEX_UNIT_PX, app.getResources().getDimension(R.dimen.default_list_text_size));
h.title.setText(header.titleRes);
h.description.setText(header.descrRes);
h.moveIcon.setVisibility(View.GONE);
} else if (holder instanceof ButtonHolder) {
ButtonHolder h = (ButtonHolder) holder;
ButtonItem button = (ButtonItem) item.value;
h.title.setText(app.getString(button.titleRes));
h.icon.setImageDrawable(uiUtilities.getIcon(button.iconRes, activeColorRes));
h.button.setOnClickListener(button.listener);
Drawable drawable = UiUtilities.getColoredSelectableDrawable(app, ContextCompat.getColor(app, activeColorRes), 0.3f);
AndroidUtils.setBackground(h.itemView, drawable);
}
}
@Override
public int getItemCount() {
return items.size();
}
@Override
public boolean onItemMove(int from, int to) {
Object itemFrom = items.get(from).value;
Object itemTo = items.get(to).value;
if (itemFrom instanceof ContextMenuItem
&& itemTo instanceof ContextMenuItem) {
ContextMenuItem menuItemFrom = (ContextMenuItem) itemFrom;
ContextMenuItem menuItemTo = (ContextMenuItem) itemTo;
int orderFrom = menuItemFrom.getOrder();
int orderTo = menuItemTo.getOrder();
if (menuItemFrom.getId().startsWith(SHOW_ITEMS_ID_SCHEME) && menuItemTo.getId().startsWith(RENDERING_ITEMS_ID_SCHEME)
|| menuItemFrom.getId().startsWith(RENDERING_ITEMS_ID_SCHEME) && menuItemTo.getId().startsWith(SHOW_ITEMS_ID_SCHEME)
|| menuItemTo.isHidden()) {
return false;
}
int buttonMoreIndex = MAIN_BUTTONS_QUANTITY + 1;
if (menuItemFrom.getId().equals(MAP_CONTEXT_MENU_MORE_ID)) {
if (to > buttonMoreIndex) {
return false;
}
} else if (menuItemTo.getId().equals(MAP_CONTEXT_MENU_MORE_ID)) {
if (from > buttonMoreIndex) {
return false;
}
}
menuItemFrom.setOrder(orderTo);
menuItemTo.setOrder(orderFrom);
listener.onItemMoved(menuItemFrom.getId(), orderTo);
listener.onItemMoved(menuItemTo.getId(), orderFrom);
Collections.swap(items, from, to);
notifyItemMoved(from, to);
return true;
}
return false;
}
@Override
public void onItemDismiss(RecyclerView.ViewHolder holder) {
listener.onDragOrSwipeEnded(holder);
}
private static class DescriptionHolder extends RecyclerView.ViewHolder
implements ReorderItemTouchHelperCallback.UnmovableItem {
private ImageView image;
private ImageView deviceImage;
private TextView description;
private FrameLayout imageContainer;
DescriptionHolder(@NonNull View itemView) {
super(itemView);
image = itemView.findViewById(R.id.image);
deviceImage = itemView.findViewById(R.id.device_image);
description = itemView.findViewById(R.id.description);
imageContainer = itemView.findViewById(R.id.image_container);
}
@Override
public boolean isMovingDisabled() {
return true;
}
}
private static class ItemHolder extends RecyclerView.ViewHolder
implements ReorderItemTouchHelperCallback.UnmovableItem {
private TextView title;
private TextView description;
private ImageView icon;
private ImageView actionIcon;
private ImageView moveIcon;
private View divider;
private boolean movable = true;
ItemHolder(@NonNull View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
description = itemView.findViewById(R.id.description);
actionIcon = itemView.findViewById(R.id.action_icon);
icon = itemView.findViewById(R.id.icon);
moveIcon = itemView.findViewById(R.id.move_icon);
divider = itemView.findViewById(R.id.divider);
}
@Override
public boolean isMovingDisabled() {
return !movable;
}
}
private static class DividerHolder extends RecyclerView.ViewHolder
implements ReorderItemTouchHelperCallback.UnmovableItem {
View divider;
DividerHolder(View itemView) {
super(itemView);
divider = itemView.findViewById(R.id.divider);
}
@Override
public boolean isMovingDisabled() {
return true;
}
}
private static class HeaderHolder extends RecyclerView.ViewHolder
implements ReorderItemTouchHelperCallback.UnmovableItem {
private ImageView moveIcon;
private TextView title;
private TextView description;
HeaderHolder(@NonNull View itemView) {
super(itemView);
moveIcon = itemView.findViewById(R.id.move_icon);
title = itemView.findViewById(R.id.title);
description = itemView.findViewById(R.id.summary);
}
@Override
public boolean isMovingDisabled() {
return true;
}
}
private static class ButtonHolder extends RecyclerView.ViewHolder
implements ReorderItemTouchHelperCallback.UnmovableItem {
private View button;
private ImageView icon;
private TextView title;
ButtonHolder(@NonNull View itemView) {
super(itemView);
button = itemView;
icon = itemView.findViewById(android.R.id.icon);
title = itemView.findViewById(android.R.id.title);
}
@Override
public boolean isMovingDisabled() {
return true;
}
}
public static class RearrangeMenuAdapterItem {
private AdapterItemType type;
private Object value;
public RearrangeMenuAdapterItem(AdapterItemType type, Object value) {
this.type = type;
this.value = value;
}
public AdapterItemType getType() {
return type;
}
public Object getValue() {
return value;
}
}
public static class ButtonItem {
@StringRes
private int titleRes;
@DrawableRes
private int iconRes;
private View.OnClickListener listener;
public ButtonItem(int titleRes, int iconRes, View.OnClickListener listener) {
this.titleRes = titleRes;
this.iconRes = iconRes;
this.listener = listener;
}
}
public static class HeaderItem {
@StringRes
private int titleRes;
@StringRes
private int descrRes;
public HeaderItem(int titleRes, int descrRes) {
this.titleRes = titleRes;
this.descrRes = descrRes;
}
}
public enum AdapterItemType {
DESCRIPTION,
MENU_ITEM,
DIVIDER,
HEADER,
BUTTON
}
public interface MenuItemsAdapterListener {
void onDragStarted(RecyclerView.ViewHolder holder);
void onDragOrSwipeEnded(RecyclerView.ViewHolder holder);
void onButtonClicked(int view);
void onItemMoved(String id, int position);
}
public void setListener(MenuItemsAdapterListener listener) {
this.listener = listener;
}
public RearrangeMenuAdapterItem getItem(int position) {
return items.get(position);
}
public void updateItems(List<RearrangeMenuAdapterItem> items) {
this.items = items;
notifyDataSetChanged();
}
private int getDescription(String id) {
if (id.equals(DRAWER_BUILDS_ID)) {
return R.string.developer_plugin;
} else {
return R.string.app_name_osmand;
}
}
}

View file

@ -21,6 +21,9 @@ import net.osmand.plus.settings.BaseSettingsFragment;
import org.apache.commons.logging.Log;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class ChangeGeneralProfilesPrefBottomSheet extends BasePreferenceBottomSheet {
@ -30,8 +33,16 @@ public class ChangeGeneralProfilesPrefBottomSheet extends BasePreferenceBottomSh
private static final String NEW_VALUE_KEY = "new_value_key";
@Nullable
private Serializable newValue;
@Nullable
private OnChangeSettingListener listener;
public void setListener(@Nullable OnChangeSettingListener listener) {
this.listener = listener;
}
@Override
public void createMenuItems(Bundle savedInstanceState) {
final OsmandApplication app = getMyApplication();
@ -55,7 +66,11 @@ public class ChangeGeneralProfilesPrefBottomSheet extends BasePreferenceBottomSh
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
app.getSettings().setPreferenceForAllModes(prefId, newValue);
updateTargetSettings(false, true);
if (listener != null) {
listener.onApplied();
}
dismiss();
}
})
@ -71,7 +86,11 @@ public class ChangeGeneralProfilesPrefBottomSheet extends BasePreferenceBottomSh
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
app.getSettings().setPreference(prefId, newValue, getAppMode());
updateTargetSettings(false, false);
if (listener != null) {
listener.onApplied();
}
dismiss();
}
})
@ -86,6 +105,9 @@ public class ChangeGeneralProfilesPrefBottomSheet extends BasePreferenceBottomSh
@Override
public void onClick(View v) {
updateTargetSettings(true, false);
if (listener != null) {
listener.onDiscard();
}
dismiss();
}
})
@ -127,8 +149,32 @@ public class ChangeGeneralProfilesPrefBottomSheet extends BasePreferenceBottomSh
}
}
public static void showInstance(@NonNull FragmentManager fm, String prefId, Serializable newValue, Fragment target,
boolean usedOnMap, @Nullable ApplicationMode appMode) {
public static void showInstance(@NonNull FragmentManager fm,
@Nullable String prefId,
@Nullable Serializable newValue,
Fragment target,
boolean usedOnMap,
@Nullable ApplicationMode appMode) {
showFragmentInstance(fm, prefId, newValue, target, usedOnMap, appMode, null);
}
public static void showInstance(@NonNull FragmentManager fm,
@Nullable String prefId,
@Nullable Serializable newValue,
Fragment target,
boolean usedOnMap,
@Nullable ApplicationMode appMode,
@Nullable OnChangeSettingListener listener) {
showFragmentInstance(fm, prefId, newValue, target, usedOnMap, appMode, listener);
}
private static void showFragmentInstance(@NonNull FragmentManager fm,
@Nullable String prefId,
@Nullable Serializable newValue,
Fragment target,
boolean usedOnMap,
@Nullable ApplicationMode appMode,
@Nullable OnChangeSettingListener listener) {
try {
if (fm.findFragmentByTag(ChangeGeneralProfilesPrefBottomSheet.TAG) == null) {
Bundle args = new Bundle();
@ -140,10 +186,17 @@ public class ChangeGeneralProfilesPrefBottomSheet extends BasePreferenceBottomSh
fragment.setUsedOnMap(usedOnMap);
fragment.setAppMode(appMode);
fragment.setTargetFragment(target, 0);
fragment.setListener(listener);
fragment.show(fm, ChangeGeneralProfilesPrefBottomSheet.TAG);
}
} catch (RuntimeException e) {
LOG.error("showInstance", e);
}
}
public interface OnChangeSettingListener {
void onApplied();
void onDiscard();
}
}

View file

@ -38,7 +38,7 @@ public class ContourLinesMenu {
OsmandPlugin.enablePlugin(mapActivity, mapActivity.getMyApplication(), plugin, true);
}
boolean nightMode = isNightMode(mapActivity.getMyApplication());
ContextMenuAdapter adapter = new ContextMenuAdapter();
ContextMenuAdapter adapter = new ContextMenuAdapter(mapActivity.getMyApplication());
adapter.setDefaultLayoutId(R.layout.list_item_icon_and_menu);
adapter.setProfileDependent(true);
adapter.setNightMode(nightMode);

View file

@ -404,7 +404,7 @@ public class TerrainFragment extends BaseOsmAndFragment implements View.OnClickL
}
private void updateDownloadSection() {
final ContextMenuAdapter adapter = new ContextMenuAdapter();
final ContextMenuAdapter adapter = new ContextMenuAdapter(app);
adapter.setDefaultLayoutId(R.layout.list_item_icon_and_menu);
adapter.setProfileDependent(true);
adapter.setNightMode(nightMode);

View file

@ -798,7 +798,7 @@ public class MapWidgetRegistry {
}
public ContextMenuAdapter getViewConfigureMenuAdapter(final MapActivity map) {
final ContextMenuAdapter cm = new ContextMenuAdapter();
final ContextMenuAdapter cm = new ContextMenuAdapter(app);
boolean nightMode = app.getDaynightHelper().isNightModeForMapControls();
cm.setProfileDependent(true);
cm.setNightMode(nightMode);

View file

@ -54,7 +54,7 @@ public class WikipediaPoiMenu {
final int languageActionStringId = R.string.shared_string_language;
final int spaceHeight = app.getResources().getDimensionPixelSize(R.dimen.bottom_sheet_big_item_height);
final boolean enabled = app.getPoiFilters().isShowingAnyPoi(PoiTemplateList.WIKI);
ContextMenuAdapter adapter = new ContextMenuAdapter();
ContextMenuAdapter adapter = new ContextMenuAdapter(app);
adapter.setDefaultLayoutId(R.layout.dash_item_with_description_72dp);
adapter.setProfileDependent(true);
adapter.setNightMode(nightMode);