Arrange POI initial commit

This commit is contained in:
Nazar 2020-01-29 12:01:04 +02:00
parent 725503ef67
commit f0f4f445e3
11 changed files with 945 additions and 13 deletions

View file

@ -0,0 +1,68 @@
<?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:minHeight="@dimen/bottom_sheet_list_item_height"
android:background="?attr/list_background_color"
android:gravity="center_vertical">
<LinearLayout
android:id="@+id/selectable_list_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/content_padding_half"
android:paddingBottom="@dimen/content_padding_half"
android:orientation="horizontal"
tools:background="?android:attr/selectableItemBackground">
<ImageButton
android:id="@+id/action_icon"
style="@style/Widget.AppCompat.ActionButton"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_gravity="center"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
tools:src="@drawable/ic_action_remove"
tools:tint="@color/icon_color_default_light" />
<ImageView
android:id="@+id/icon"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_gravity="center"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
tools:src="@drawable/mm_air_transport"
tools:tint="@color/poi_background" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:ellipsize="marquee"
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:singleLine="true"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_regular"
tools:text="@string/poi_aerialway_transport" />
<ImageView
android:id="@+id/move_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:src="@drawable/ic_action_item_move"
android:tint="?attr/secondary_icon_color" />
</LinearLayout>
</LinearLayout>

View file

@ -11,6 +11,12 @@
Thx - Hardy
-->
<string name="rearrange_categories">Rearrange categories</string>
<string name="create_custom_categories_list_promo">You can add custom categories hide categories that you dont find necessary and change the sort order of the list. The list can be imported and exported with profiles.</string>
<string name="add_new_custom_category_button_promo">You can add a new custom category by selecting one or a few needed categories.</string>
<string name="reset_to_default_category_button_promo">Reset to default will delete or custom categories and reset sort order to the default state after installation.</string>
<string name="shared_string_available">Available</string>
<string name="add_custom_category">Add custom category</string>
<string name="permission_is_required">Permission is required to use this option.</string>
<string name="logcat_buffer_descr">Check and share detailed logs of the application</string>
<string name="file_does_not_contain_routing_rules">No routing rules in \'%1$s\'. Please choose another file.</string>

View file

@ -3057,6 +3057,10 @@ public class OsmandSettings {
SELECTED_POI_FILTER_FOR_MAP.set(android.text.TextUtils.join(",", poiFilters));
}
public final OsmandPreference<Boolean> ARRANGE_POI_FILTERS_BY_DEFAULT = new BooleanPreference("arrange_poi_filters_by_default", false).makeProfile().cache();
public final OsmandPreference<String> POI_FILTERS_ARRANGEMENT = new StringPreference("poi_filters_arrangement", null).makeProfile().cache();
public static final String VOICE_PROVIDER_NOT_USE = "VOICE_PROVIDER_NOT_USE";
public static final String[] TTS_AVAILABLE_VOICES = new String[]{

View file

@ -276,10 +276,7 @@ public class MapActivityLayers {
final PoiFiltersHelper poiFilters = app.getPoiFilters();
final ContextMenuAdapter adapter = new ContextMenuAdapter();
final List<PoiUIFilter> list = new ArrayList<>();
for (PoiUIFilter f : poiFilters.getTopDefinedPoiFilters()) {
addFilterToList(adapter, list, f, true);
}
for (PoiUIFilter f : poiFilters.getSearchPoiFilters()) {
for (PoiUIFilter f : poiFilters.getProfileDependentPoiUIFilters(true)) {
addFilterToList(adapter, list, f, true);
}
list.add(poiFilters.getCustomPOIFilter());
@ -357,10 +354,7 @@ public class MapActivityLayers {
.setIcon(R.drawable.ic_action_search_dark).createItem());
final List<PoiUIFilter> list = new ArrayList<>();
list.add(poiFilters.getCustomPOIFilter());
for (PoiUIFilter f : poiFilters.getTopDefinedPoiFilters()) {
addFilterToList(adapter, list, f, false);
}
for (PoiUIFilter f : poiFilters.getSearchPoiFilters()) {
for (PoiUIFilter f : poiFilters.getProfileDependentPoiUIFilters(true)) {
addFilterToList(adapter, list, f, false);
}

View file

@ -2,6 +2,11 @@ package net.osmand.plus.poi;
import android.support.annotation.NonNull;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import com.google.gson.reflect.TypeToken;
import net.osmand.osm.AbstractPoiType;
import net.osmand.osm.MapPoiTypes;
import net.osmand.osm.PoiCategory;
@ -13,9 +18,12 @@ import net.osmand.plus.api.SQLiteAPI.SQLiteCursor;
import net.osmand.plus.api.SQLiteAPI.SQLiteStatement;
import net.osmand.util.Algorithms;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
@ -25,6 +33,9 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import static net.osmand.plus.poi.PoiFiltersHelper.PoiFilterType.SEARCH;
import static net.osmand.plus.poi.PoiFiltersHelper.PoiFilterType.TOP_DEFINED;
public class PoiFiltersHelper {
private final OsmandApplication application;
@ -55,6 +66,25 @@ public class PoiFiltersHelper {
UDF_PUBLIC_TRANSPORT, UDF_ACCOMMODATION, UDF_RESTAURANTS, UDF_PARKING
};
public static final Comparator<PoiUIFilter> ORDER_COMPARATOR = new Comparator<PoiUIFilter>() {
@Override
public int compare(PoiUIFilter o1, PoiUIFilter o2) {
return (o1.getOrder() < o2.getOrder()) ? -1 : ((o1.getOrder() == o2.getOrder()) ? 0 : 1);
}
};
public static final Comparator<PoiUIFilter> ALPHABET_COMPARATOR = new Comparator<PoiUIFilter>() {
@Override
public int compare(PoiUIFilter o1, PoiUIFilter o2) {
return o1.compareTo(o2);
}
};
public enum PoiFilterType {
TOP_DEFINED,
SEARCH
}
public PoiFiltersHelper(OsmandApplication application) {
this.application = application;
PoiFilterDbHelper helper = openDbHelperNoPois();
@ -248,6 +278,149 @@ public class PoiFiltersHelper {
return result;
}
public List<PoiUIFilter> getProfileDependentPoiUIFilters(boolean onlyActive) {
return getProfileDependentPoiUIFilters(onlyActive, new PoiFilterType[]{TOP_DEFINED, SEARCH});
}
public List<PoiUIFilter> getProfileDependentPoiUIFilters(boolean onlyActive, PoiFilterType[] filterTypes) {
initPoiUIFiltersArrangementAndActivation();
List<PoiUIFilter> result = new ArrayList<>();
for (PoiFilterType type : filterTypes) {
List<PoiUIFilter> filterList = new ArrayList<>();
switch (type) {
case TOP_DEFINED:
filterList = getTopDefinedPoiFilters();
break;
case SEARCH:
filterList = getSearchPoiFilters();
break;
}
if (onlyActive) {
for (PoiUIFilter f : filterList) {
if (f.isActive) {
result.add(f);
}
}
} else {
result.addAll(filterList);
}
}
Collections.sort(result, ORDER_COMPARATOR);
return result;
}
private void initPoiUIFiltersArrangementAndActivation() {
List<PoiUIFilter> allFilters = new ArrayList<>();
allFilters.addAll(getTopDefinedPoiFilters());
allFilters.addAll(getSearchPoiFilters());
List<PoiFilterBean> poiBeans = getPoiFiltersBeans();
Map<String, Boolean> activation = null;
Map<String, Integer> arrangement = null;
if (poiBeans != null) {
activation = new HashMap<>();
arrangement = new HashMap<>();
for (PoiFilterBean filterBean : poiBeans) {
activation.put(filterBean.getFilterId(), filterBean.isActive);
arrangement.put(filterBean.getFilterId(), filterBean.getOrder());
}
}
reorderPoiFilters(allFilters, arrangement);
refreshPoiFiltersActivation(allFilters, activation);
//set up the biggest order to custom filter
PoiUIFilter customFilter = getCustomPOIFilter();
customFilter.setActive(true);
customFilter.setOrder(allFilters.size());
}
private void reorderPoiFilters(List<PoiUIFilter> filters, Map<String, Integer> arrangement) {
boolean defaultArrangement = application.getSettings().ARRANGE_POI_FILTERS_BY_DEFAULT.get();
if (arrangement == null || defaultArrangement) {
//arrangement by default
Collections.sort(filters, ALPHABET_COMPARATOR);
for (int i = 0; i < filters.size(); i++) {
PoiUIFilter poiFilter = filters.get(i);
poiFilter.setOrder(i);
}
} else {
for (PoiUIFilter filter : filters) {
String filterId = filter.getFilterId();
if (arrangement.containsKey(filterId)) {
filter.setOrder(arrangement.get(filterId));
}
}
}
}
private void refreshPoiFiltersActivation(List<PoiUIFilter> allFilters, Map<String, Boolean> activation) {
if (activation == null) {
//activation by default
for (PoiUIFilter filter : allFilters) {
filter.setActive(true);
}
} else {
for (PoiUIFilter filter : allFilters) {
String filterId = filter.getFilterId();
if (activation.containsKey(filterId)) {
filter.setActive(activation.get(filterId));
}
}
}
}
public static class PoiFilterBean {
@Expose
String filterId;
@Expose
int order;
@Expose
boolean isActive;
public PoiFilterBean(String filterId, int order, boolean isActive) {
this.filterId = filterId;
this.order = order;
this.isActive = isActive;
}
public String getFilterId() {
return filterId;
}
public int getOrder() {
return order;
}
public boolean isActive() {
return isActive;
}
public void setFilterId(String filterId) {
this.filterId = filterId;
}
public void setOrder(int order) {
this.order = order;
}
public void setActive(boolean active) {
isActive = active;
}
}
public void savePoiFiltersBeans(List<PoiFilterBean> list) {
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
String defaultProfiles = gson.toJson(list);
application.getSettings().POI_FILTERS_ARRANGEMENT.set(defaultProfiles);
}
public List<PoiFilterBean> getPoiFiltersBeans() {
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
Type t = new TypeToken<ArrayList<PoiFilterBean>>() {
}.getType();
return gson.fromJson(application.getSettings().POI_FILTERS_ARRANGEMENT.get(), t);
}
private PoiFilterDbHelper openDbHelperNoPois() {
return new PoiFilterDbHelper(null, application);
}

View file

@ -52,6 +52,8 @@ public class PoiUIFilter implements SearchPoiTypeFilter, Comparable<PoiUIFilter>
protected String standardIconId = "";
protected String name;
protected boolean isStandardFilter;
protected int order;
protected boolean isActive = true;
protected final OsmandApplication app;
@ -743,6 +745,22 @@ public class PoiUIFilter implements SearchPoiTypeFilter, Comparable<PoiUIFilter>
this.isStandardFilter = isStandardFilter;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public boolean isActive() {
return isActive;
}
public void setActive(boolean active) {
isActive = active;
}
public Context getApplication() {
return app;
}

View file

@ -0,0 +1,664 @@
package net.osmand.plus.poi;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.MotionEventCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import net.osmand.AndroidUtils;
import net.osmand.PlatformUtil;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.render.RenderingIcons;
import net.osmand.plus.search.QuickSearchCustomPoiFragment;
import net.osmand.plus.views.controls.ReorderItemTouchHelperCallback;
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.plus.poi.PoiUIFilter.CUSTOM_FILTER_ID;
import static net.osmand.plus.poi.PoiFiltersHelper.PoiFilterBean;
import static net.osmand.plus.poi.RearrangePoiFiltersFragment.ItemType.DESCRIPTION;
import static net.osmand.plus.poi.RearrangePoiFiltersFragment.ItemType.POI;
import static net.osmand.plus.poi.RearrangePoiFiltersFragment.ItemType.SPACE;
public class RearrangePoiFiltersFragment extends DialogFragment {
public static final String TAG = "RearrangePoiFiltersFragment";
private static final Log LOG = PlatformUtil.getLog(RearrangePoiFiltersFragment.class);
private boolean usedOnMap;
private List<ListItem> items = new ArrayList<>();
private EditPoiFiltersAdapter adapter;
private boolean isChanged = false;
private boolean orderModified = false;
private boolean isResetToDefault = false;
private HashMap<String, Integer> poiFiltersOrders = new HashMap<>();
private List<String> availableFiltersKeys = new ArrayList<>();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean nightMode = isNightMode(requireMyApplication(), usedOnMap);
int themeId = nightMode ? R.style.OsmandDarkTheme : R.style.OsmandLightTheme;
setStyle(STYLE_NO_FRAME, themeId);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
final OsmandApplication app = requireMyApplication();
boolean nightMode = isNightMode(app, usedOnMap);
View mainView = UiUtilities.getInflater(app, nightMode).inflate(R.layout.edit_arrangement_list_fragment, container, false);
ImageButton closeButton = mainView.findViewById(R.id.close_button);
closeButton.setImageResource(R.drawable.ic_action_remove_dark);
closeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
TextView toolbarTitle = mainView.findViewById(R.id.toolbar_title);
toolbarTitle.setText(R.string.rearrange_categories);
RecyclerView recyclerView = mainView.findViewById(R.id.profiles_list);
recyclerView.setLayoutManager(new LinearLayoutManager(app));
adapter = new EditPoiFiltersAdapter(app, nightMode);
initFiltersOrders(app, false);
final ItemTouchHelper touchHelper = new ItemTouchHelper(new ReorderItemTouchHelperCallback(adapter));
touchHelper.attachToRecyclerView(recyclerView);
orderModified = !app.getSettings().ARRANGE_POI_FILTERS_BY_DEFAULT.get();
adapter.setListener(new PoiAdapterListener() {
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) {
adapter.notifyDataSetChanged();
}
}
@Override
public void onButtonClicked(int pos) {
ListItem item = items.get(pos);
if (item.value instanceof PoiUIFilterDataObject) {
isChanged = true;
isResetToDefault = false;
PoiUIFilterDataObject poiInfo = (PoiUIFilterDataObject) item.value;
poiInfo.toggleActive();
if (!poiInfo.isActive) {
availableFiltersKeys.add(poiInfo.filterId);
} else {
availableFiltersKeys.remove(poiInfo.filterId);
}
updateItems();
}
}
});
recyclerView.setAdapter(adapter);
View cancelButton = mainView.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) {
dismiss();
}
});
mainView.findViewById(R.id.buttons_divider).setVisibility(View.VISIBLE);
View applyButton = mainView.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) {
if (isChanged) {
List<PoiFilterBean> savingData = new ArrayList<>();
for (PoiUIFilter filter : getProfileDependentPoiUiFilters(app)) {
String filterId = filter.getFilterId();
Integer order = poiFiltersOrders.get(filterId);
if (order == null) {
order = filter.getOrder();
}
boolean isActive = !availableFiltersKeys.contains(filterId);
filter.setActive(isActive);
filter.setOrder(order);
savingData.add(new PoiFilterBean(filterId, order, isActive));
}
app.getPoiFilters().savePoiFiltersBeans(savingData);
app.getSettings().ARRANGE_POI_FILTERS_BY_DEFAULT.set(!orderModified);
} else if (isResetToDefault) {
app.getPoiFilters().savePoiFiltersBeans(null);
app.getSettings().ARRANGE_POI_FILTERS_BY_DEFAULT.set(true);
}
dismiss();
}
});
return mainView;
}
private void initFiltersOrders(OsmandApplication app, boolean arrangementByDefault) {
poiFiltersOrders.clear();
availableFiltersKeys.clear();
List<PoiUIFilter> filters = getProfileDependentPoiUiFilters(app);
if (arrangementByDefault) {
Collections.sort(filters);
for (int i = 0; i < filters.size(); i++) {
PoiUIFilter filter = filters.get(i);
poiFiltersOrders.put(filter.getFilterId(), i);
}
} else {
for (PoiUIFilter filter : filters) {
poiFiltersOrders.put(filter.getFilterId(), filter.getOrder());
if (!filter.isActive) {
availableFiltersKeys.add(filter.getFilterId());
}
}
}
updateItems();
}
private void updateItems() {
final OsmandApplication app = requireMyApplication();
List<ListItem> active = getPoiFilters(true);
List<ListItem> available = getPoiFilters(false);
items.clear();
items.add(new ListItem(DESCRIPTION, app.getString(R.string.create_custom_categories_list_promo)));
items.add(new ListItem(ItemType.SPACE, app.getResources().getDimension(R.dimen.content_padding)));
items.addAll(active);
items.add(new ListItem(ItemType.DIVIDER, 0));
if (availableFiltersKeys != null && availableFiltersKeys.size() > 0) {
items.add(new ListItem(ItemType.HEADER, app.getString(R.string.shared_string_available)));
items.addAll(available);
items.add(new ListItem(ItemType.DIVIDER, 1));
}
items.add(new ListItem(ItemType.BUTTON, new ControlButton(app.getString(R.string.add_custom_category),
R.drawable.ic_action_plus, new View.OnClickListener() {
@Override
public void onClick(View v) {
QuickSearchCustomPoiFragment.showDialog(RearrangePoiFiltersFragment.this, app.getPoiFilters().getCustomPOIFilter().getFilterId());
}
})));
items.add(new ListItem(ItemType.BUTTON, new ControlButton(app.getString(R.string.reset_to_default),
R.drawable.ic_action_reset_to_default_dark, new View.OnClickListener() {
@Override
public void onClick(View v) {
isChanged = false;
orderModified = false;
isResetToDefault = true;
initFiltersOrders(app, true);
}
})));
items.add(new ListItem(DESCRIPTION, app.getString(R.string.add_new_custom_category_button_promo) +
'\n' + app.getString(R.string.reset_to_default_category_button_promo)));
adapter.setItems(items);
}
public static void showInstance(@NonNull DialogFragment parentFragment, boolean usedOnMap) {
try {
RearrangePoiFiltersFragment fragment = new RearrangePoiFiltersFragment();
fragment.setUsedOnMap(usedOnMap);
fragment.show(parentFragment.getChildFragmentManager(), RearrangePoiFiltersFragment.TAG);
} catch (RuntimeException e) {
LOG.error("showInstance", e);
}
}
public List<ListItem> getPoiFilters(boolean isActive) {
OsmandApplication app = requireMyApplication();
List<ListItem> result = new ArrayList<>();
for (PoiUIFilter f : getProfileDependentPoiUiFilters(app)) {
addFilterToList(result, f, isActive);
}
Collections.sort(result, new Comparator<ListItem>() {
@Override
public int compare(ListItem o1, ListItem o2) {
int order1 = ((PoiUIFilterDataObject) o1.value).order;
int order2 = ((PoiUIFilterDataObject) o2.value).order;
return (order1 < order2) ? -1 : ((order1 == order2) ? 0 : 1);
}
});
return result;
}
private void addFilterToList(List<ListItem> list, PoiUIFilter f, boolean isActive) {
String filterId = f.getFilterId();
if (!isActive && availableFiltersKeys.contains(filterId) || isActive && !availableFiltersKeys.contains(filterId)) {
Integer order = poiFiltersOrders.get(filterId);
if (order == null) {
order = f.getOrder();
}
PoiUIFilterDataObject poiInfo = new PoiUIFilterDataObject();
poiInfo.filterId = filterId;
poiInfo.name = f.getName();
poiInfo.order = order;
String iconRes = f.getIconId();
if (iconRes != null && RenderingIcons.containsBigIcon(iconRes)) {
poiInfo.iconRes = RenderingIcons.getBigIconResourceId(iconRes);
} else {
poiInfo.iconRes = R.drawable.mx_user_defined;
}
poiInfo.isActive = !availableFiltersKeys.contains(filterId);
list.add(new ListItem(POI, poiInfo));
}
}
private static List<PoiUIFilter> getProfileDependentPoiUiFilters(@NonNull OsmandApplication app) {
List<PoiUIFilter> filters = app.getPoiFilters().getProfileDependentPoiUIFilters(false);
//remove custom filter
for (int i = filters.size() - 1; i >= 0; i--) {
PoiUIFilter filter = filters.get(i);
if (filter.getFilterId().equals(CUSTOM_FILTER_ID)) {
filters.remove(filter);
break;
}
}
return filters;
}
public void setUsedOnMap(boolean usedOnMap) {
this.usedOnMap = usedOnMap;
}
@NonNull
protected OsmandApplication requireMyApplication() {
FragmentActivity activity = requireActivity();
return (OsmandApplication) activity.getApplication();
}
public static boolean isNightMode(OsmandApplication app, boolean usedOnMap) {
if (app != null) {
return usedOnMap ? app.getDaynightHelper().isNightModeForMapControls() : !app.getSettings().isLightContent();
}
return false;
}
public class PoiUIFilterDataObject {
String filterId;
String name;
int iconRes;
int order;
boolean isActive;
public void toggleActive() {
isActive = !isActive;
}
}
protected class ControlButton {
private String title;
private int iconRes;
private View.OnClickListener listener;
public ControlButton(String title, int iconRes, View.OnClickListener listener) {
this.title = title;
this.iconRes = iconRes;
this.listener = listener;
}
}
protected enum ItemType {
DESCRIPTION,
POI,
HEADER,
DIVIDER,
SPACE,
BUTTON
}
private class ListItem {
ItemType type;
Object value;
public ListItem(ItemType type, Object value) {
this.type = type;
this.value = value;
}
public ListItem(ItemType type) {
this.type = type;
}
}
private class EditPoiFiltersAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
implements ReorderItemTouchHelperCallback.OnItemMoveCallback {
private OsmandApplication app;
private UiUtilities uiUtilities;
private List<ListItem> items = new ArrayList<>();
private boolean nightMode;
private PoiAdapterListener listener;
public EditPoiFiltersAdapter(OsmandApplication app, boolean nightMode) {
setHasStableIds(true);
this.app = app;
this.uiUtilities = app.getUIUtilities();
this.nightMode = nightMode;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewTypeId) {
Context ctx = parent.getContext();
LayoutInflater inflater = UiUtilities.getInflater(ctx, nightMode);
ItemType type = viewTypeId < ItemType.values().length ? ItemType.values()[viewTypeId] : SPACE;
View itemView;
switch (type) {
case POI:
itemView = inflater.inflate(R.layout.arrange_poi_list_item, parent, false);
return new PoiViewHolder(itemView);
case SPACE:
itemView = new View(ctx);
return new SpaceViewHolder(itemView);
case BUTTON:
itemView = inflater.inflate(R.layout.preference_button, parent, false);
return new ButtonViewHolder(itemView);
case HEADER:
itemView = inflater.inflate(R.layout.preference_category_with_descr, parent, false);
return new HeaderViewHolder(itemView);
case DIVIDER:
itemView = inflater.inflate(R.layout.divider, parent, false);
return new DividerViewHolder(itemView);
case DESCRIPTION:
itemView = inflater.inflate(R.layout.bottom_sheet_item_description_long, parent, false);
return new DescriptionViewHolder(itemView);
default:
throw new IllegalArgumentException("Unsupported view type");
}
}
@SuppressLint("ClickableViewAccessibility")
@Override
public void onBindViewHolder(final @NonNull RecyclerView.ViewHolder holder, int position) {
ListItem item = items.get(position);
boolean nightMode = isNightMode(app, usedOnMap);
int activeColorResId = nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light;
if (holder instanceof PoiViewHolder) {
PoiViewHolder h = (PoiViewHolder) holder;
PoiUIFilterDataObject poiInfo = (PoiUIFilterDataObject) item.value;
int osmandOrangeColorResId = nightMode ? R.color.osmand_orange_dark : R.color.osmand_orange;
h.title.setText(poiInfo.name);
h.icon.setImageDrawable(uiUtilities.getIcon(poiInfo.iconRes, osmandOrangeColorResId));
h.moveIcon.setVisibility(poiInfo.isActive ? View.VISIBLE : View.GONE);
h.actionIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int pos = holder.getAdapterPosition();
if (listener != null && pos != RecyclerView.NO_POSITION) {
listener.onButtonClicked(pos);
}
}
});
if (poiInfo.isActive) {
h.actionIcon.setImageDrawable(uiUtilities.getIcon(R.drawable.ic_action_remove, R.color.color_osm_edit_delete));
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;
}
});
} else {
h.actionIcon.setImageDrawable(uiUtilities.getIcon(R.drawable.ic_action_add, R.color.color_osm_edit_create));
}
} else if (holder instanceof SpaceViewHolder) {
float space = (float) item.value;
((SpaceViewHolder) holder).setSpace((int) space);
} else if (holder instanceof ButtonViewHolder) {
ControlButton buttonInfo = (ControlButton) item.value;
ButtonViewHolder h = (ButtonViewHolder) holder;
h.buttonView.setOnClickListener(buttonInfo.listener);
h.icon.setImageDrawable(uiUtilities.getIcon(buttonInfo.iconRes, activeColorResId));
h.title.setText(buttonInfo.title);
Drawable drawable = UiUtilities.getColoredSelectableDrawable(app, ContextCompat.getColor(app, activeColorResId), 0.3f);
AndroidUtils.setBackground(h.buttonView, drawable);
} else if (holder instanceof HeaderViewHolder) {
String header = (String) item.value;
((HeaderViewHolder) holder).tvTitle.setText(header);
} else if (holder instanceof DescriptionViewHolder) {
String description = (String) item.value;
((DescriptionViewHolder) holder).tvDescription.setText(description);
}
}
public void setListener(PoiAdapterListener listener) {
this.listener = listener;
}
public void setItems(List<ListItem> items) {
this.items = items;
notifyDataSetChanged();
}
@Override
public int getItemCount() {
return items.size();
}
@Override
public int getItemViewType(int position) {
ListItem item = items.get(position);
return item.type.ordinal();
}
@Override
public boolean onItemMove(int from, int to) {
Object itemFrom = items.get(from).value;
Object itemTo = items.get(to).value;
if (itemFrom instanceof PoiUIFilterDataObject && itemTo instanceof PoiUIFilterDataObject) {
isChanged = true;
orderModified = true;
isResetToDefault = false;
PoiUIFilterDataObject poiFrom = (PoiUIFilterDataObject) itemFrom;
PoiUIFilterDataObject poiTo = (PoiUIFilterDataObject) itemTo;
int orderFrom = poiFrom.order;
int orderTo = poiTo.order;
poiFrom.order = orderTo;
poiTo.order = orderFrom;
poiFiltersOrders.put(poiFrom.filterId, orderTo);
poiFiltersOrders.put(poiTo.filterId, orderFrom);
Collections.swap(items, from, to);
notifyItemMoved(from, to);
return true;
}
return false;
}
@Override
public long getItemId(int position) {
ListItem item = items.get(position);
if (item.value instanceof PoiUIFilterDataObject) {
return ((PoiUIFilterDataObject) item.value).filterId.hashCode();
} else if (item.value instanceof ControlButton) {
return ((ControlButton) item.value).title.hashCode();
} else if (item.value != null) {
return item.value.hashCode();
}
return item.hashCode();
}
@Override
public void onItemDismiss(RecyclerView.ViewHolder holder) {
listener.onDragOrSwipeEnded(holder);
}
private class DividerViewHolder extends RecyclerView.ViewHolder implements ReorderItemTouchHelperCallback.UnmovableItem {
View divider;
public DividerViewHolder(View itemView) {
super(itemView);
divider = itemView.findViewById(R.id.divider);
}
@Override
public boolean isMovingDisabled() {
return true;
}
}
private class HeaderViewHolder extends RecyclerView.ViewHolder implements ReorderItemTouchHelperCallback.UnmovableItem {
private TextView tvTitle;
private TextView tvDescription;
public HeaderViewHolder(View itemView) {
super(itemView);
tvTitle = itemView.findViewById(android.R.id.title);
tvDescription = itemView.findViewById(android.R.id.summary);
tvDescription.setVisibility(View.GONE);
}
@Override
public boolean isMovingDisabled() {
return true;
}
}
private class ButtonViewHolder extends RecyclerView.ViewHolder implements ReorderItemTouchHelperCallback.UnmovableItem {
private View buttonView;
private ImageView icon;
private TextView title;
public ButtonViewHolder(View itemView) {
super(itemView);
buttonView = itemView;
icon = itemView.findViewById(android.R.id.icon);
title = itemView.findViewById(android.R.id.title);
}
@Override
public boolean isMovingDisabled() {
return true;
}
}
private class SpaceViewHolder extends RecyclerView.ViewHolder implements ReorderItemTouchHelperCallback.UnmovableItem {
View space;
public SpaceViewHolder(View itemView) {
super(itemView);
space = itemView;
}
public void setSpace(int hSpace) {
ViewGroup.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, hSpace);
space.setLayoutParams(lp);
}
@Override
public boolean isMovingDisabled() {
return true;
}
}
private class PoiViewHolder extends RecyclerView.ViewHolder implements ReorderItemTouchHelperCallback.UnmovableItem {
private TextView title;
private TextView description;
private ImageView icon;
private ImageButton actionIcon;
private ImageView moveIcon;
private View itemsContainer;
public PoiViewHolder(View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
actionIcon = itemView.findViewById(R.id.action_icon);
icon = itemView.findViewById(R.id.icon);
moveIcon = itemView.findViewById(R.id.move_icon);
itemsContainer = itemView.findViewById(R.id.selectable_list_item);
}
@Override
public boolean isMovingDisabled() {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
ListItem item = items.get(position);
if (item.value instanceof PoiUIFilterDataObject) {
PoiUIFilterDataObject pdo = (PoiUIFilterDataObject) item.value;
return !pdo.isActive;
}
}
return false;
}
}
private class DescriptionViewHolder extends RecyclerView.ViewHolder implements ReorderItemTouchHelperCallback.UnmovableItem {
private TextView tvDescription;
public DescriptionViewHolder(View itemView) {
super(itemView);
tvDescription = itemView.findViewById(R.id.description);
}
@Override
public boolean isMovingDisabled() {
return true;
}
}
}
public interface PoiAdapterListener {
void onDragStarted(RecyclerView.ViewHolder holder);
void onDragOrSwipeEnded(RecyclerView.ViewHolder holder);
void onButtonClicked(int view);
}
}

View file

@ -65,7 +65,7 @@ public class EditProfilesFragment extends BaseOsmAndFragment {
}
nightMode = !app.getSettings().isLightContent();
View mainView = UiUtilities.getInflater(getContext(), nightMode).inflate(R.layout.edit_profiles_list_fragment, container, false);
View mainView = UiUtilities.getInflater(getContext(), nightMode).inflate(R.layout.edit_arrangement_list_fragment, container, false);
ImageButton closeButton = mainView.findViewById(R.id.close_button);
closeButton.setImageResource(R.drawable.ic_action_remove_dark);
closeButton.setOnClickListener(new View.OnClickListener() {

View file

@ -283,10 +283,7 @@ public class ShowHidePoiAction extends QuickAction {
final List<PoiUIFilter> list = new ArrayList<>();
for (PoiUIFilter f : poiFilters.getTopDefinedPoiFilters()) {
addFilterToList(adapter, list, f);
}
for (PoiUIFilter f : poiFilters.getSearchPoiFilters()) {
for (PoiUIFilter f : poiFilters.getProfileDependentPoiUIFilters(true)) {
addFilterToList(adapter, list, f);
}

View file

@ -76,6 +76,7 @@ import net.osmand.plus.activities.MapActivity.ShowQuickSearchMode;
import net.osmand.plus.helpers.SearchHistoryHelper;
import net.osmand.plus.helpers.SearchHistoryHelper.HistoryEntry;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.poi.RearrangePoiFiltersFragment;
import net.osmand.plus.resources.RegionAddressRepository;
import net.osmand.plus.search.QuickSearchHelper.SearchHistoryAPI;
import net.osmand.plus.search.listitems.QuickSearchButtonListItem;
@ -1224,6 +1225,13 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
QuickSearchDialogFragment.this, filter.getFilterId());
}
}));
rows.add(new QuickSearchButtonListItem(app, R.drawable.ic_action_item_move,
app.getString(R.string.rearrange_categories), new OnClickListener() {
@Override
public void onClick(View v) {
RearrangePoiFiltersFragment.showInstance(QuickSearchDialogFragment.this, false);
}
}));
if (categoriesSearchFragment != null) {
categoriesSearchFragment.updateListAdapter(rows, false);
}