ui changes & search implementation

This commit is contained in:
veliymolfar 2020-04-22 16:51:13 +03:00
parent ab599be3e1
commit c35722aa3a
6 changed files with 651 additions and 444 deletions

View file

@ -0,0 +1,24 @@
<?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"
android:orientation="vertical">
<include layout="@layout/list_shadow_header" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/bg_color"
android:lineSpacingMultiplier="@dimen/line_spacing_multiplier_description"
android:paddingStart="@dimen/content_padding"
android:paddingTop="@dimen/list_header_settings_top_margin"
android:paddingEnd="@dimen/content_padding"
android:paddingBottom="@dimen/list_header_settings_top_margin"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_desc_text_size"
tools:text="@string/select_data_to_import" />
</LinearLayout>

View file

@ -133,45 +133,49 @@
android:id="@+id/bottomBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="52dp"
android:background="?attr/color_dialog_buttons"
android:background="?attr/bg_color"
android:minHeight="@dimen/dialog_button_ex_height"
android:visibility="gone"
tools:visibility="visible">
<LinearLayout
<FrameLayout
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:orientation="horizontal">
android:background="?attr/color_dialog_buttons">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/barTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="@color/color_white"
android:layout_gravity="center_vertical"
android:layout_marginLeft="16dp"
android:textSize="@dimen/default_desc_text_size"
tools:text="Selected: 3 categories"
android:layout_marginStart="16dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="?attr/selectableItemBackground"
android:gravity="center"
android:orientation="vertical">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/barButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:textColor="@color/color_white"
android:textSize="@dimen/default_sub_text_size"
osmand:typeface="@string/font_roboto_medium"
osmand:textAllCapsCompat="true"
android:text="@string/shared_string_show"
android:layout_marginEnd="20dp"
android:layout_marginStart="20dp" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/barTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="@color/color_white"
android:textSize="@dimen/default_list_text_size"
tools:text="Show" />
</LinearLayout>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/barSubTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:textColor="@color/text_color_primary_dark"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="Selected categories: 3" />
</LinearLayout>
</FrameLayout>
</LinearLayout>

View file

@ -5,6 +5,8 @@ import android.content.Context;
import android.content.DialogInterface;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -12,11 +14,13 @@ import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.appcompat.widget.SwitchCompat;
@ -26,9 +30,9 @@ import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import net.osmand.AndroidUtils;
import net.osmand.osm.PoiCategory;
import net.osmand.osm.PoiType;
import net.osmand.plus.DialogListItemAdapter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
@ -36,14 +40,13 @@ import net.osmand.plus.UiUtilities;
import net.osmand.plus.poi.PoiFiltersHelper;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.render.RenderingIcons;
import net.osmand.util.Algorithms;
import java.text.Collator;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class QuickSearchCustomPoiFragment extends DialogFragment {
@ -55,16 +58,22 @@ public class QuickSearchCustomPoiFragment extends DialogFragment {
private UiUtilities uiUtilities;
private View view;
private ListView listView;
private CategoryListAdapter listAdapter;
private CategoryListAdapter categoryListAdapter;
private SubCategoriesAdapter subCategoriesAdapter;
private String filterId;
private PoiUIFilter filter;
private PoiFiltersHelper helper;
private View bottomBarShadow;
private View bottomBar;
private TextView barTitle;
private TextView barButton;
private TextView barSubTitle;
private boolean editMode;
private boolean nightMode;
private EditText searchEditText;
private FrameLayout button;
private List<PoiCategory> poiCategoryList;
private View headerShadow;
private View headerDescription;
public QuickSearchCustomPoiFragment() {
}
@ -80,12 +89,13 @@ public class QuickSearchCustomPoiFragment extends DialogFragment {
uiUtilities = app.getUIUtilities();
this.nightMode = app.getSettings().OSMAND_THEME.get() == OsmandSettings.OSMAND_DARK_THEME;
setStyle(STYLE_NO_FRAME, nightMode ? R.style.OsmandDarkTheme : R.style.OsmandLightTheme);
poiCategoryList = app.getPoiTypes().getCategories(false);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final OsmandApplication app = getMyApplication();
LayoutInflater layoutInflater = UiUtilities.getInflater(app, nightMode);
helper = app.getPoiFilters();
if (getArguments() != null) {
filterId = getArguments().getString(QUICK_SEARCH_CUSTOM_POI_FILTER_ID_KEY);
@ -101,7 +111,7 @@ public class QuickSearchCustomPoiFragment extends DialogFragment {
}
editMode = !filterId.equals(helper.getCustomPOIFilter().getFilterId());
view = inflater.inflate(R.layout.search_custom_poi, container, false);
view = layoutInflater.inflate(R.layout.search_custom_poi, container, false);
Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);
Drawable icClose = app.getUIUtilities().getIcon(R.drawable.ic_action_remove_dark,
@ -127,56 +137,65 @@ public class QuickSearchCustomPoiFragment extends DialogFragment {
app.getSettings().isLightContent() ? R.color.activity_background_color_light
: R.color.activity_background_color_dark));
View header = getLayoutInflater(savedInstanceState).inflate(R.layout.list_shadow_header, null);
listView.addHeaderView(header, null, false);
View footer = inflater.inflate(R.layout.list_shadow_footer, listView, false);
listView.addFooterView(footer, null, false);
listAdapter = new CategoryListAdapter(app, app.getPoiTypes().getCategories(false));
listView.setAdapter(listAdapter);
headerShadow = layoutInflater.inflate(R.layout.list_shadow_header, null);
headerDescription = layoutInflater.inflate(R.layout.list_item_description, null);
((TextView) headerDescription.findViewById(R.id.description)).setText(R.string.search_poi_types_descr);
listView.addHeaderView(headerDescription, null, false);
View footerShadow = layoutInflater.inflate(R.layout.list_shadow_footer, listView, false);
listView.addFooterView(footerShadow, null, false);
subCategoriesAdapter = new SubCategoriesAdapter(app, new ArrayList<PoiType>(), true,
new SubCategoriesAdapter.SubCategoryClickListener() {
@Override
public void onCategoryClick(boolean allSelected) {
setupAddButton();
}
});
categoryListAdapter = new CategoryListAdapter(app, poiCategoryList);
listView.setAdapter(categoryListAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final PoiCategory category = listAdapter.getItem(position - listView.getHeaderViewsCount());
PoiCategory category = categoryListAdapter.getItem(position - listView.getHeaderViewsCount());
FragmentManager fm = getFragmentManager();
if (fm != null) {
QuickSearchSubCategoriesFragment.showInstance(fm, category, false, new QuickSearchSubCategoriesFragment.OnFiltersSelectedListener() {
@Override
public void onFiltersSelected(LinkedHashSet<String> filters) {
if (filter.getAcceptedSubtypes(category).size() == filters.size()) {
filter.selectSubTypesToAccept(category, null);
} else if (filters.size() == 0) {
filter.setTypeToAccept(category, false);
} else {
filter.selectSubTypesToAccept(category, filters);
}
saveFilter();
listAdapter.notifyDataSetChanged();
}
});
if (fm != null && category != null) {
showSubCategoriesFragment(fm, category, false);
}
}
});
bottomBarShadow = view.findViewById(R.id.bottomBarShadow);
bottomBar = view.findViewById(R.id.bottomBar);
barTitle = (TextView) view.findViewById(R.id.barTitle);
barButton = (TextView) view.findViewById(R.id.barButton);
bottomBar.setOnClickListener(new View.OnClickListener() {
button = view.findViewById(R.id.button);
barTitle = view.findViewById(R.id.barTitle);
barSubTitle = view.findViewById(R.id.barSubTitle);
ImageView searchIcon = view.findViewById(R.id.search_icon);
searchIcon.setImageDrawable(uiUtilities.getIcon(R.drawable.ic_action_search_dark, nightMode));
ImageView searchCloseIcon = view.findViewById(R.id.search_close);
searchCloseIcon.setImageDrawable(uiUtilities.getIcon(R.drawable.ic_action_cancel, nightMode));
searchCloseIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
if (!editMode) {
dismiss();
QuickSearchDialogFragment quickSearchDialogFragment = getQuickSearchDialogFragment();
if (quickSearchDialogFragment != null) {
quickSearchDialogFragment.showFilter(filterId);
}
} else {
QuickSearchPoiFilterFragment quickSearchPoiFilterFragment = getQuickSearchPoiFilterFragment();
if(quickSearchPoiFilterFragment!= null) {
quickSearchPoiFilterFragment.refreshList();
}
}
public void onClick(View view) {
subCategoriesAdapter.setSelectedItems(new ArrayList<PoiType>());
clearSearch();
}
});
searchEditText = view.findViewById(R.id.search);
searchEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
searchSubCategory(charSequence.toString());
}
@Override
public void afterTextChanged(Editable editable) {
}
});
@ -261,8 +280,7 @@ public class QuickSearchCustomPoiFragment extends DialogFragment {
@NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) app
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
View row = convertView;
if (row == null) {
row = inflater.inflate(R.layout.list_item_icon24_and_menu, parent, false);
@ -326,7 +344,10 @@ public class QuickSearchCustomPoiFragment extends DialogFragment {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (check.isChecked()) {
showDialog(category, true);
FragmentManager fm = getFragmentManager();
if (fm != null) {
showSubCategoriesFragment(fm, category, true);
}
} else {
filter.setTypeToAccept(category, false);
saveFilter();
@ -346,131 +367,161 @@ public class QuickSearchCustomPoiFragment extends DialogFragment {
bottomBarShadow.setVisibility(View.GONE);
bottomBar.setVisibility(View.GONE);
} else {
barTitle.setText(ctx.getString(R.string.selected_categories) + ": " + filter.getAcceptedTypesCount());
UiUtilities.setMargins(button, 0, 0, 0, 0);
button.setBackgroundResource(nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light);
barTitle.setText(R.string.shared_string_show);
barSubTitle.setVisibility(View.VISIBLE);
barSubTitle.setText(ctx.getString(R.string.selected_categories) + ": " + filter.getAcceptedTypesCount());
bottomBarShadow.setVisibility(View.VISIBLE);
bottomBar.setVisibility(View.VISIBLE);
}
}
}
private void showDialog(final PoiCategory poiCategory, boolean selectAll) {
final int index = listView.getFirstVisiblePosition();
View v = listView.getChildAt(0);
final int top = (v == null) ? 0 : v.getTop();
final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
final LinkedHashMap<String, String> subCategories = new LinkedHashMap<String, String>();
Set<String> acceptedCategories = filter.getAcceptedSubtypes(poiCategory);
if (acceptedCategories != null) {
for (String s : acceptedCategories) {
subCategories.put(s, Algorithms.capitalizeFirstLetterAndLowercase(s));
}
}
for (PoiType pt : poiCategory.getPoiTypes()) {
subCategories.put(pt.getKeyName(), pt.getTranslation());
}
final String[] array = subCategories.keySet().toArray(new String[0]);
final Collator cl = Collator.getInstance();
cl.setStrength(Collator.SECONDARY);
Arrays.sort(array, 0, array.length, new Comparator<String>() {
@Override
public int compare(String object1, String object2) {
String v1 = subCategories.get(object1);
String v2 = subCategories.get(object2);
return cl.compare(v1, v2);
}
});
final String[] visibleNames = new String[array.length];
final boolean[] selected = new boolean[array.length];
boolean allSelected = true;
for (int i = 0; i < array.length; i++) {
final String subcategory = array[i];
visibleNames[i] = subCategories.get(subcategory);
if (acceptedCategories == null || selectAll) {
selected[i] = true;
} else {
if (allSelected) {
allSelected = false;
}
selected[i] = acceptedCategories.contains(subcategory);
}
}
View titleView = LayoutInflater.from(getActivity())
.inflate(R.layout.subcategories_dialog_title, null);
TextView titleTextView = (TextView) titleView.findViewById(R.id.title);
titleTextView.setText(poiCategory.getTranslation());
View toggleButtonContainer = titleView.findViewById(R.id.buttonContainer);
final CompoundButton selectAllToggle = (CompoundButton) toggleButtonContainer.findViewById(R.id.check);
UiUtilities.setupCompoundButton(selectAllToggle, nightMode, UiUtilities.CompoundButtonType.GLOBAL);
toggleButtonContainer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
selectAllToggle.setChecked(!selectAllToggle.isChecked());
}
});
selectAllToggle.setChecked(allSelected);
builder.setCustomTitle(titleView);
builder.setCancelable(true);
builder.setNegativeButton(getContext().getText(R.string.shared_string_cancel),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
listAdapter.notifyDataSetChanged();
}
});
builder.setPositiveButton(getContext().getText(R.string.shared_string_apply),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
LinkedHashSet<String> accepted = new LinkedHashSet<String>();
for (int i = 0; i < selected.length; i++) {
if (selected[i]) {
accepted.add(array[i]);
}
}
if (subCategories.size() == accepted.size()) {
filter.selectSubTypesToAccept(poiCategory, null);
} else if (accepted.size() == 0) {
filter.setTypeToAccept(poiCategory, false);
} else {
filter.selectSubTypesToAccept(poiCategory, accepted);
}
saveFilter();
listAdapter.notifyDataSetChanged();
listView.setSelectionFromTop(index, top);
}
});
int activeColor = ContextCompat.getColor(getMyApplication(), nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light);
int themeRes = nightMode ? R.style.OsmandDarkTheme : R.style.OsmandLightTheme;
final DialogListItemAdapter adapter = DialogListItemAdapter.createMultiChoiceAdapter(visibleNames,
nightMode, selected, getMyApplication(), activeColor, themeRes, new View.OnClickListener() {
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int which = (int) v.getTag();
selected[which] = !selected[which];
dismiss();
if (!editMode) {
dismiss();
QuickSearchDialogFragment quickSearchDialogFragment = getQuickSearchDialogFragment();
if (quickSearchDialogFragment != null) {
quickSearchDialogFragment.showFilter(filterId);
}
} else {
QuickSearchPoiFilterFragment quickSearchPoiFilterFragment = getQuickSearchPoiFilterFragment();
if (quickSearchPoiFilterFragment != null) {
quickSearchPoiFilterFragment.refreshList();
}
}
}
});
builder.setAdapter(adapter, null);
final AlertDialog dialog = builder.show();
adapter.setDialog(dialog);
selectAllToggle.setOnCheckedChangeListener(new OnCheckedChangeListener() {
}
}
}
private void searchSubCategory(String search) {
List<PoiType> result = new ArrayList<>();
if (search.isEmpty()) {
if (subCategoriesAdapter.getSelectedItems().isEmpty()) {
listView.setAdapter(categoryListAdapter);
categoryListAdapter.notifyDataSetChanged();
removeAllHeaders();
listView.addHeaderView(headerDescription, null, false);
} else {
listView.setAdapter(subCategoriesAdapter);
subCategoriesAdapter.clear();
subCategoriesAdapter.addAll(new ArrayList<>(subCategoriesAdapter.getSelectedItems()));
subCategoriesAdapter.notifyDataSetChanged();
removeAllHeaders();
listView.addHeaderView(headerShadow, null, false);
setupAddButton();
}
} else {
for (PoiCategory category : poiCategoryList) {
for (PoiType poiType : category.getPoiTypes()) {
if (poiType.getTranslation().toLowerCase().contains(search.toLowerCase())) {
result.add(poiType);
}
}
}
listView.setAdapter(subCategoriesAdapter);
subCategoriesAdapter.clear();
subCategoriesAdapter.addAll(result);
subCategoriesAdapter.notifyDataSetChanged();
removeAllHeaders();
listView.addHeaderView(headerShadow, null, false);
setupAddButton();
}
}
private void removeAllHeaders() {
listView.removeHeaderView(headerDescription);
listView.removeHeaderView(headerShadow);
}
private void clearSearch() {
searchEditText.setText("");
AndroidUtils.hideSoftKeyboard(requireActivity(), searchEditText);
}
private void setupAddButton() {
if (subCategoriesAdapter.getSelectedItems().isEmpty()) {
bottomBar.setVisibility(View.GONE);
bottomBarShadow.setVisibility(View.GONE);
return;
}
int startMargin = (int) app.getResources().getDimension(R.dimen.content_padding);
int topMargin = (int) app.getResources().getDimension(R.dimen.content_padding_small);
UiUtilities.setMargins(button, startMargin, topMargin, startMargin, topMargin);
barSubTitle.setVisibility(View.GONE);
barTitle.setText(R.string.shared_string_add);
button.setBackgroundResource(nightMode ? R.drawable.dlg_btn_primary_dark : R.drawable.dlg_btn_primary_light);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
Arrays.fill(selected, true);
} else {
Arrays.fill(selected, false);
}
for (int i = 0; i < selected.length; i++) {
dialog.getListView().setItemChecked(i, selected[i]);
}
adapter.notifyDataSetChanged();
public void onClick(View view) {
updateFilter(subCategoriesAdapter.getSelectedItems());
}
});
bottomBar.setVisibility(View.VISIBLE);
bottomBarShadow.setVisibility(View.VISIBLE);
}
private void updateFilter(List<PoiType> selectedPoiCategoryList) {
if (selectedPoiCategoryList.isEmpty()) {
return;
}
HashMap<PoiCategory, LinkedHashSet<String>> map = new HashMap<>();
for (PoiType poiType : selectedPoiCategoryList) {
if (map.containsKey(poiType.getCategory())) {
map.get(poiType.getCategory()).add(poiType.getKeyName());
} else {
LinkedHashSet<String> list = new LinkedHashSet<>();
list.add(poiType.getKeyName());
map.put(poiType.getCategory(), list);
}
}
for (Map.Entry<PoiCategory, LinkedHashSet<String>> entry : map.entrySet()) {
PoiCategory poiCategory = entry.getKey();
Set<String> acceptedSubtypes = filter.getAcceptedSubtypes(poiCategory);
LinkedHashSet<String> filters = entry.getValue();
if (filters.isEmpty()) {
filter.setTypeToAccept(poiCategory, false);
} else if (acceptedSubtypes != null && acceptedSubtypes.size() == filters.size()) {
filter.selectSubTypesToAccept(poiCategory, null);
} else {
filter.selectSubTypesToAccept(poiCategory, filters);
}
}
subCategoriesAdapter.clear();
subCategoriesAdapter.setSelectedItems(new ArrayList<PoiType>());
clearSearch();
saveFilter();
}
private void showSubCategoriesFragment(@NonNull FragmentManager fm,
@NonNull PoiCategory poiCategory,
boolean selectAll) {
Set<String> acceptedCategories = filter.getAcceptedSubtypes(poiCategory);
QuickSearchSubCategoriesFragment.showInstance(fm, poiCategory, acceptedCategories, selectAll,
new QuickSearchSubCategoriesFragment.OnFiltersSelectedListener() {
@Override
public void onFiltersSelected(PoiCategory poiCategory, LinkedHashSet<String> filters) {
List<String> subCategories = new ArrayList<>();
Set<String> acceptedCategories = filter.getAcceptedSubtypes(poiCategory);
if (acceptedCategories != null) {
subCategories.addAll(acceptedCategories);
}
for (PoiType pt : poiCategory.getPoiTypes()) {
subCategories.add(pt.getKeyName());
}
if (subCategories.size() == filters.size()) {
filter.selectSubTypesToAccept(poiCategory, null);
} else if (filters.size() == 0) {
filter.setTypeToAccept(poiCategory, false);
} else {
filter.selectSubTypesToAccept(poiCategory, filters);
}
saveFilter();
categoryListAdapter.notifyDataSetChanged();
}
});
}
}

View file

@ -1,15 +1,14 @@
package net.osmand.plus.search;
import android.content.res.ColorStateList;
import android.content.DialogInterface;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
@ -19,8 +18,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SwitchCompat;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.core.widget.CompoundButtonCompat;
import androidx.fragment.app.FragmentManager;
import net.osmand.AndroidUtils;
@ -30,262 +27,230 @@ import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.base.BaseOsmAndDialogFragment;
import net.osmand.plus.render.RenderingIcons;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class QuickSearchSubCategoriesFragment extends BaseOsmAndDialogFragment {
public static final String TAG = QuickSearchSubCategoriesFragment.class.getName();
private static final String CATEGORY_NAME_KEY = "category_key";
private static final String ALL_SELECTED_KEY = "all_selected";
private OnFiltersSelectedListener listener;
private OsmandApplication app;
private UiUtilities uiUtilities;
private PoiCategory poiCategory;
private List<PoiType> poiTypeList;
private List<PoiType> selectedPoiTypeList;
private SubCategoriesAdapter adapter;
private EditText searchEditText;
private ListView listView;
private View headerSelectAll;
private View headerShadow;
private View footerShadow;
private boolean selectAll;
private boolean nightMode;
public static final String TAG = QuickSearchSubCategoriesFragment.class.getName();
private static final String CATEGORY_NAME_KEY = "category_key";
private static final String ALL_SELECTED_KEY = "all_selected";
private OnFiltersSelectedListener listener;
private OsmandApplication app;
private UiUtilities uiUtilities;
private PoiCategory poiCategory;
private List<PoiType> poiTypeList;
private Set<String> acceptedCategories;
private SubCategoriesAdapter adapter;
private EditText searchEditText;
private ListView listView;
private SwitchCompat selectAllSwitch;
private View headerSelectAll;
private View headerShadow;
private View footerShadow;
private boolean selectAll;
private boolean nightMode;
public static void showInstance(@NonNull FragmentManager fm,
@NonNull PoiCategory poiCategory,
@Nullable Set<String> acceptedCategories,
boolean selectAll,
@NonNull OnFiltersSelectedListener listener) {
QuickSearchSubCategoriesFragment fragment = new QuickSearchSubCategoriesFragment();
fragment.setPoiCategory(poiCategory);
fragment.setSelectAll(selectAll);
fragment.setAcceptedCategories(acceptedCategories);
fragment.setListener(listener);
fragment.show(fm, TAG);
}
public static void showInstance(@NonNull FragmentManager fm, @NonNull PoiCategory poiCategory,
boolean selectAll, @NonNull OnFiltersSelectedListener listener) {
QuickSearchSubCategoriesFragment fragment = new QuickSearchSubCategoriesFragment();
fragment.setPoiCategory(poiCategory);
fragment.setSelectAll(selectAll);
fragment.setListener(listener);
fragment.show(fm, TAG);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = getMyApplication();
uiUtilities = app.getUIUtilities();
nightMode = !app.getSettings().isLightContent();
if (savedInstanceState != null) {
poiCategory = app.getPoiTypes().getPoiCategoryByName(savedInstanceState.getString(CATEGORY_NAME_KEY));
selectAll = savedInstanceState.getBoolean(ALL_SELECTED_KEY);
}
poiTypeList = new ArrayList<>(poiCategory.getPoiTypes());
Collections.sort(poiTypeList, new Comparator<PoiType>() {
@Override
public int compare(PoiType poiType, PoiType t1) {
return poiType.getTranslation().compareTo(t1.getTranslation());
}
});
adapter = new SubCategoriesAdapter(app, new ArrayList<>(poiTypeList), false, new SubCategoriesAdapter.SubCategoryClickListener() {
@Override
public void onCategoryClick(boolean allSelected) {
selectAll = allSelected;
selectAllSwitch.setChecked(allSelected);
}
});
if (selectAll || acceptedCategories == null) {
adapter.setSelectedItems(poiTypeList);
selectAll = true;
} else {
List<PoiType> selected = new ArrayList<>();
for (PoiType poiType : poiTypeList) {
if (acceptedCategories.contains(poiType.getKeyName())) {
selected.add(poiType);
}
}
adapter.setSelectedItems(selected);
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = getMyApplication();
uiUtilities = app.getUIUtilities();
nightMode = !app.getSettings().isLightContent();
selectedPoiTypeList = new ArrayList<>();
if (savedInstanceState != null) {
poiCategory = app.getPoiTypes().getPoiCategoryByName(savedInstanceState.getString(CATEGORY_NAME_KEY));
selectAll = savedInstanceState.getBoolean(ALL_SELECTED_KEY);
}
poiTypeList = new ArrayList<>(poiCategory.getPoiTypes());
if (selectAll) {
selectedPoiTypeList.addAll(poiTypeList);
}
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(CATEGORY_NAME_KEY, poiCategory.getKeyName());
outState.putBoolean(ALL_SELECTED_KEY, selectAll);
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(CATEGORY_NAME_KEY, poiCategory.getKeyName());
outState.putBoolean(ALL_SELECTED_KEY, selectAll);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_subcategories, container, false);
Toolbar toolbar = root.findViewById(R.id.toolbar);
Drawable icClose = app.getUIUtilities().getIcon(R.drawable.ic_arrow_back,
nightMode ? R.color.active_buttons_and_links_text_dark : R.color.active_buttons_and_links_text_light);
toolbar.setNavigationIcon(icClose);
toolbar.setNavigationContentDescription(R.string.shared_string_close);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LinkedHashSet<String> list = new LinkedHashSet<>();
for (PoiType poiType : adapter.getSelectedItems()) {
list.add(poiType.getKeyName());
}
listener.onFiltersSelected(poiCategory, list);
dismiss();
}
});
TextView title = root.findViewById(R.id.title);
title.setText(poiCategory.getTranslation());
listView = root.findViewById(R.id.list);
headerShadow = inflater.inflate(R.layout.list_shadow_header, listView, false);
footerShadow = inflater.inflate(R.layout.list_shadow_footer, listView, false);
headerSelectAll = inflater.inflate(R.layout.select_all_switch_list_item, listView, false);
selectAllSwitch = headerSelectAll.findViewById(R.id.select_all);
selectAllSwitch.setChecked(selectAll);
selectAllSwitch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
selectAll = !selectAll;
selectAllSwitch.setChecked(selectAll);
adapter.selectAll(selectAll);
}
});
listView.addFooterView(footerShadow);
listView.addHeaderView(headerSelectAll);
searchEditText = root.findViewById(R.id.search);
searchEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_subcategories, container, false);
Toolbar toolbar = root.findViewById(R.id.toolbar);
Drawable icClose = app.getUIUtilities().getIcon(R.drawable.ic_arrow_back,
nightMode ? R.color.active_buttons_and_links_text_dark : R.color.active_buttons_and_links_text_light);
toolbar.setNavigationIcon(icClose);
toolbar.setNavigationContentDescription(R.string.shared_string_close);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LinkedHashSet<String> list = new LinkedHashSet<>();
for (PoiType poiType : selectedPoiTypeList) {
list.add(poiType.getKeyName());
}
listener.onFiltersSelected(list);
dismiss();
}
});
TextView title = root.findViewById(R.id.title);
title.setText(poiCategory.getTranslation());
listView = root.findViewById(R.id.list);
headerShadow = inflater.inflate(R.layout.list_shadow_header, listView, false);
footerShadow = inflater.inflate(R.layout.list_shadow_footer, listView, false);
headerSelectAll = inflater.inflate(R.layout.select_all_switch_list_item, listView, false);
final SwitchCompat selectAllSwitch = headerSelectAll.findViewById(R.id.select_all);
selectAllSwitch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
selectAll = !selectAll;
selectAllSwitch.setChecked(selectAll);
selectAll(selectAll);
}
});
listView.addFooterView(footerShadow);
listView.addHeaderView(headerSelectAll);
searchEditText = root.findViewById(R.id.search);
searchEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
searchSubCategory(charSequence.toString());
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
searchSubCategory(charSequence.toString());
}
@Override
public void afterTextChanged(Editable editable) {
@Override
public void afterTextChanged(Editable editable) {
}
});
ImageView searchIcon = root.findViewById(R.id.search_icon);
searchIcon.setImageDrawable(uiUtilities.getIcon(R.drawable.ic_action_search_dark, nightMode));
ImageView searchCloseIcon = root.findViewById(R.id.search_close);
searchCloseIcon.setImageDrawable(uiUtilities.getIcon(R.drawable.ic_action_cancel, nightMode));
searchCloseIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
clearSearch();
}
});
listView.setAdapter(adapter);
return root;
}
}
});
ImageView searchIcon = root.findViewById(R.id.search_icon);
searchIcon.setImageDrawable(uiUtilities.getIcon(R.drawable.ic_action_search_dark, nightMode));
ImageView searchCloseIcon = root.findViewById(R.id.search_close);
searchCloseIcon.setImageDrawable(uiUtilities.getIcon(R.drawable.ic_action_cancel, nightMode));
searchCloseIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
clearSearch();
}
});
Collections.sort(poiTypeList, new Comparator<PoiType>() {
@Override
public int compare(PoiType poiType, PoiType t1) {
return poiType.getTranslation().compareTo(t1.getTranslation());
}
});
adapter = new SubCategoriesAdapter(app, new ArrayList<PoiType>(poiTypeList));
listView.setAdapter(adapter);
return root;
}
@Override
public void onResume() {
super.onResume();
getDialog().setOnKeyListener(new DialogInterface.OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if (keyCode == android.view.KeyEvent.KEYCODE_BACK) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
return true;
} else {
LinkedHashSet<String> list = new LinkedHashSet<>();
for (PoiType poiType : adapter.getSelectedItems()) {
list.add(poiType.getKeyName());
}
listener.onFiltersSelected(poiCategory, list);
dismiss();
return true;
}
}
return false;
}
});
}
private void clearSearch() {
searchEditText.setText("");
AndroidUtils.hideSoftKeyboard(requireActivity(), searchEditText);
}
private void clearSearch() {
searchEditText.setText("");
AndroidUtils.hideSoftKeyboard(requireActivity(), searchEditText);
}
private void selectAll(boolean selectAll) {
selectedPoiTypeList.clear();
if (selectAll) {
selectedPoiTypeList.addAll(poiTypeList);
}
adapter.notifyDataSetChanged();
}
private void searchSubCategory(String search) {
List<PoiType> result = new ArrayList<>();
if (search.isEmpty()) {
listView.removeHeaderView(headerShadow);
listView.removeHeaderView(headerSelectAll);
listView.addHeaderView(headerSelectAll);
result.addAll(new ArrayList<>(poiTypeList));
} else {
listView.removeHeaderView(headerSelectAll);
listView.removeHeaderView(headerShadow);
listView.addHeaderView(headerShadow);
for (PoiType poiType : poiTypeList) {
if (poiType.getTranslation().toLowerCase().contains(search.toLowerCase())) {
result.add(poiType);
}
}
}
adapter.clear();
adapter.addAll(result);
adapter.notifyDataSetChanged();
}
private void searchSubCategory(String search) {
List<PoiType> result = new ArrayList<>();
if (search.isEmpty()) {
listView.removeHeaderView(headerShadow);
listView.removeHeaderView(headerSelectAll);
listView.addHeaderView(headerSelectAll);
result.addAll(new ArrayList<>(poiTypeList));
} else {
listView.removeHeaderView(headerSelectAll);
listView.removeHeaderView(headerShadow);
listView.removeFooterView(footerShadow);
listView.addHeaderView(headerShadow);
for (PoiType poiType : poiTypeList) {
if (poiType.getTranslation().toLowerCase().contains(search.toLowerCase())) {
result.add(poiType);
}
}
if (result.isEmpty()) {
listView.removeHeaderView(headerShadow);
listView.removeFooterView(footerShadow);
} else {
listView.addHeaderView(headerShadow);
listView.addFooterView(footerShadow);
}
}
adapter.clear();
adapter.addAll(result);
adapter.notifyDataSetChanged();
}
public void setSelectAll(boolean selectAll) {
this.selectAll = selectAll;
}
public void setSelectAll(boolean selectAll) {
this.selectAll = selectAll;
}
public void setPoiCategory(PoiCategory poiCategory) {
this.poiCategory = poiCategory;
}
public void setPoiCategory(PoiCategory poiCategory) {
this.poiCategory = poiCategory;
}
public void setListener(OnFiltersSelectedListener listener) {
this.listener = listener;
}
public void setListener(OnFiltersSelectedListener listener) {
this.listener = listener;
}
public void setAcceptedCategories(Set<String> acceptedCategories) {
this.acceptedCategories = acceptedCategories;
}
private class SubCategoriesAdapter extends ArrayAdapter<PoiType> {
private UiUtilities uiUtilities;
private boolean nightMode;
private int activeColorRes;
private int secondaryColorRes;
public SubCategoriesAdapter(OsmandApplication app, List<PoiType> items) {
super(app, R.layout.profile_data_list_item_child, items);
uiUtilities = app.getUIUtilities();
nightMode = !app.getSettings().isLightContent();
activeColorRes = nightMode
? R.color.icon_color_active_dark
: R.color.icon_color_active_light;
secondaryColorRes = nightMode
? R.color.icon_color_secondary_dark
: R.color.icon_color_secondary_light;
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
if (convertView == null) {
convertView = UiUtilities.getInflater(app, nightMode)
.inflate(R.layout.profile_data_list_item_child, parent, false);
}
final PoiType poiType = getItem(position);
final boolean selected = selectedPoiTypeList.contains(poiType);
int tintColorRes = selected ? activeColorRes : secondaryColorRes;
if (poiType != null) {
TextView title = convertView.findViewById(R.id.title_tv);
title.setText(poiType.getTranslation());
final CheckBox checkBox = convertView.findViewById(R.id.check_box);
checkBox.setChecked(selected);
checkBox.setClickable(false);
CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, tintColorRes)));
convertView.findViewById(R.id.sub_title_tv).setVisibility(View.GONE);
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (selected) {
selectedPoiTypeList.remove(poiType);
} else {
selectedPoiTypeList.add(poiType);
}
notifyDataSetChanged();
}
});
ImageView icon = convertView.findViewById(R.id.icon);
int iconRes = RenderingIcons.getBigIconResourceId(poiType.getIconKeyName());
if (iconRes == 0) {
iconRes = RenderingIcons.getBigIconResourceId(poiType.getOsmTag() + "_" + poiType.getOsmValue());
if (iconRes == 0) {
// TODO: change default icon
iconRes = R.drawable.ic_person;
}
}
icon.setImageDrawable(uiUtilities.getIcon(iconRes, tintColorRes));
}
return convertView;
}
}
public interface OnFiltersSelectedListener {
void onFiltersSelected(LinkedHashSet<String> filters);
}
public interface OnFiltersSelectedListener {
void onFiltersSelected(PoiCategory poiCategory, LinkedHashSet<String> filters);
}
}

View file

@ -0,0 +1,140 @@
package net.osmand.plus.search;
import android.content.res.ColorStateList;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.widget.CompoundButtonCompat;
import net.osmand.osm.PoiType;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.render.RenderingIcons;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class SubCategoriesAdapter extends ArrayAdapter<PoiType> {
private OsmandApplication app;
private UiUtilities uiUtilities;
private SubCategoryClickListener listener;
private boolean nightMode;
private boolean showCategory;
private int activeColorRes;
private int secondaryColorRes;
private List<PoiType> selectedItems;
private List<PoiType> items;
public SubCategoriesAdapter(@NonNull OsmandApplication app,
@NonNull List<PoiType> items,
boolean showCategory,
@Nullable SubCategoryClickListener listener) {
super(app, R.layout.profile_data_list_item_child, items);
this.app = app;
this.showCategory = showCategory;
this.listener = listener;
this.items = new ArrayList<>(items);
selectedItems = new ArrayList<>();
uiUtilities = app.getUIUtilities();
nightMode = !app.getSettings().isLightContent();
activeColorRes = nightMode
? R.color.icon_color_active_dark
: R.color.icon_color_active_light;
secondaryColorRes = nightMode
? R.color.icon_color_secondary_dark
: R.color.icon_color_secondary_light;
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
if (convertView == null) {
convertView = UiUtilities.getInflater(app, nightMode)
.inflate(R.layout.profile_data_list_item_child, parent, false);
}
final PoiType poiType = getItem(position);
final boolean selected = selectedItems.contains(poiType);
int tintColorRes = selected ? activeColorRes : secondaryColorRes;
if (poiType != null) {
TextView title = convertView.findViewById(R.id.title_tv);
title.setText(poiType.getTranslation());
final CheckBox checkBox = convertView.findViewById(R.id.check_box);
checkBox.setChecked(selected);
checkBox.setClickable(false);
CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, tintColorRes)));
if (showCategory) {
TextView subTitle = convertView.findViewById(R.id.sub_title_tv);
subTitle.setVisibility(View.VISIBLE);
subTitle.setText(poiType.getCategory().getTranslation());
} else {
convertView.findViewById(R.id.sub_title_tv).setVisibility(View.GONE);
}
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (selected) {
selectedItems.remove(poiType);
} else {
selectedItems.add(poiType);
}
if (listener != null) {
listener.onCategoryClick(selectedItems.containsAll(items));
}
notifyDataSetChanged();
}
});
ImageView icon = convertView.findViewById(R.id.icon);
int iconRes = RenderingIcons.getBigIconResourceId(poiType.getIconKeyName());
if (iconRes == 0) {
iconRes = RenderingIcons.getBigIconResourceId(poiType.getOsmTag() + "_" + poiType.getOsmValue());
if (iconRes == 0) {
iconRes = R.drawable.ic_action_categories_search;
}
}
icon.setImageDrawable(uiUtilities.getIcon(iconRes, tintColorRes));
}
return convertView;
}
@Override
public void addAll(@NonNull Collection<? extends PoiType> collection) {
super.addAll(collection);
items.addAll(collection);
}
@Override
public void clear() {
super.clear();
items.clear();
}
public void selectAll(boolean selectAll) {
selectedItems.clear();
if (selectAll) {
selectedItems.addAll(items);
}
notifyDataSetChanged();
}
public void setSelectedItems(List<PoiType> selectedItems) {
this.selectedItems = selectedItems;
}
public List<PoiType> getSelectedItems() {
return selectedItems;
}
interface SubCategoryClickListener {
void onCategoryClick(boolean allSelected);
}
}

View file

@ -26,12 +26,17 @@ import net.osmand.plus.R;
import net.osmand.plus.activities.search.SearchHistoryFragment;
import net.osmand.plus.base.FavoriteImageDrawable;
import net.osmand.plus.helpers.SearchHistoryHelper.HistoryEntry;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.render.RenderingIcons;
import net.osmand.search.core.CustomSearchPoiFilter;
import net.osmand.search.core.SearchResult;
import net.osmand.util.Algorithms;
import java.io.File;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
public class QuickSearchListItem {
@ -324,11 +329,29 @@ public class QuickSearchListItem {
iconId = RenderingIcons.getBigIconResourceId(iconName);
}
} else if (searchResult.object instanceof CustomSearchPoiFilter) {
Object res = ((CustomSearchPoiFilter) searchResult.object).getIconResource();
if (res instanceof String && RenderingIcons.containsBigIcon(res.toString())) {
iconId = RenderingIcons.getBigIconResourceId(res.toString());
} else {
iconId = R.drawable.mx_user_defined;
CustomSearchPoiFilter searchPoiFilter = (CustomSearchPoiFilter) searchResult.object;
PoiUIFilter filter = app.getPoiFilters().getFilterById(searchPoiFilter.getFilterId());
iconId = R.drawable.ic_action_categories_search;
if (filter != null) {
Map<PoiCategory, LinkedHashSet<String>> acceptedTypes = filter.getAcceptedTypes();
List<PoiCategory> categories = new ArrayList<>(acceptedTypes.keySet());
if (categories.size() == 1) {
String res = "";
PoiCategory category = categories.get(0);
LinkedHashSet<String> f = acceptedTypes.get(category);
List<String> filters;
if (f != null) {
filters = new ArrayList<>(f);
if (filters.size() == 1) {
res = getPoiTypeIconName(category.getPoiTypeByKeyName(filters.get(0)));
} else {
res = category.getIconKeyName();
}
if (res != null && RenderingIcons.containsBigIcon(res)) {
iconId = RenderingIcons.getBigIconResourceId(res);
}
}
}
}
}
if (iconId > 0) {