package net.osmand.plus.activities; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.content.ContextCompat; import android.support.v4.content.FileProvider; import android.support.v4.view.MenuItemCompat; import android.support.v7.app.AlertDialog; import android.support.v7.view.ActionMode; import android.text.Html; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.ExpandableListView; import android.widget.Filter; import android.widget.Filterable; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import net.osmand.data.FavouritePoint; import net.osmand.data.LatLon; import net.osmand.data.PointDescription; import net.osmand.plus.FavouritesDbHelper; import net.osmand.plus.FavouritesDbHelper.FavoriteGroup; import net.osmand.plus.MapMarkersHelper; import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandSettings; import net.osmand.plus.R; import net.osmand.plus.TargetPointsHelper; import net.osmand.plus.base.FavoriteImageDrawable; import net.osmand.plus.base.OsmandExpandableListFragment; import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.helpers.FontCache; import net.osmand.plus.myplaces.FavoritesActivity; import net.osmand.util.Algorithms; import net.osmand.util.MapUtils; import java.io.File; import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; public class FavoritesTreeFragment extends OsmandExpandableListFragment { public static final int SEARCH_ID = -1; // public static final int EXPORT_ID = 0; // public static final int IMPORT_ID = 1; public static final int DELETE_ID = 2; public static final int DELETE_ACTION_ID = 3; public static final int SHARE_ID = 4; public static final int SELECT_MAP_MARKERS_ID = 5; public static final int SELECT_MAP_MARKERS_ACTION_MODE_ID = 6; public static final String GROUP_EXPANDED_POSTFIX = "_group_expanded"; private FavouritesAdapter favouritesAdapter = new FavouritesAdapter(); private FavouritesDbHelper helper; private boolean selectionMode = false; private Set<FavouritePoint> favoritesSelected = new LinkedHashSet<>(); private Set<FavoriteGroup> groupsToDelete = new LinkedHashSet<>(); private ActionMode actionMode; Drawable arrowImage; Drawable arrowImageDisabled; private HashMap<String, OsmandSettings.OsmandPreference<Boolean>> preferenceCache = new HashMap<>(); private View footerView; @Override public void onAttach(Context context) { super.onAttach(context); helper = getMyApplication().getFavorites(); favouritesAdapter.synchronizeGroups(); setAdapter(favouritesAdapter); boolean light = getMyApplication().getSettings().isLightContent(); arrowImage = ContextCompat.getDrawable(context, R.drawable.ic_direction_arrow); arrowImage.mutate(); if (light) { arrowImage.setColorFilter(ContextCompat.getColor(context, R.color.color_distance), PorterDuff.Mode.MULTIPLY); } else { arrowImage.setColorFilter(ContextCompat.getColor(context, R.color.color_distance), PorterDuff.Mode.MULTIPLY); } arrowImageDisabled = ContextCompat.getDrawable(context, R.drawable.ic_direction_arrow); arrowImageDisabled.mutate(); arrowImageDisabled.setColorFilter(ContextCompat.getColor( context, light ? R.color.icon_color : R.color.icon_color_light), PorterDuff.Mode.MULTIPLY); } private void deleteFavorites() { new AsyncTask<Void, Object, String>() { @Override protected void onPreExecute() { showProgressBar(); } @Override protected void onPostExecute(String result) { hideProgressBar(); favouritesAdapter.synchronizeGroups(); } @Override protected String doInBackground(Void... params) { helper.delete(groupsToDelete, favoritesSelected); favoritesSelected.clear(); groupsToDelete.clear(); return getString(R.string.favourites_delete_multiple_succesful); } }.execute(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.favorites_tree, container, false); ExpandableListView listView = (ExpandableListView) view.findViewById(android.R.id.list); favouritesAdapter.synchronizeGroups(); if (!favouritesAdapter.isEmpty()) { boolean light = getMyApplication().getSettings().isLightContent(); View searchView = inflater.inflate(R.layout.search_fav_list_item, null); searchView.setBackgroundResource(light ? R.color.bg_color_light : R.color.bg_color_dark); TextView title = (TextView) searchView.findViewById(R.id.title); title.setCompoundDrawablesWithIntrinsicBounds(getMyApplication().getIconsCache().getThemedIcon(R.drawable.ic_action_search_dark), null, null, null); title.setHint(R.string.shared_string_search); searchView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { FavoritesSearchFragment.showInstance(getActivity(), ""); } }); listView.addHeaderView(searchView); listView.addHeaderView(inflater.inflate(R.layout.list_item_divider, null, false)); footerView = inflater.inflate(R.layout.list_shadow_footer, null, false); listView.addFooterView(footerView); } listView.setAdapter(favouritesAdapter); setListView(listView); setHasOptionsMenu(true); listView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() { @Override public void onGroupCollapse(int groupPosition) { String groupName = favouritesAdapter.getGroup(groupPosition).name; getGroupExpandedPreference(groupName).set(false); } }); listView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() { @Override public void onGroupExpand(int groupPosition) { String groupName = favouritesAdapter.getGroup(groupPosition).name; getGroupExpandedPreference(groupName).set(true); } }); return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); listView.setBackgroundColor(getResources().getColor( getMyApplication().getSettings().isLightContent() ? R.color.ctx_menu_info_view_bg_light : R.color.ctx_menu_info_view_bg_dark)); } @Override public void onResume() { super.onResume(); favouritesAdapter.synchronizeGroups(); initListExpandedState(); } public void reloadData() { favouritesAdapter.synchronizeGroups(); favouritesAdapter.notifyDataSetInvalidated(); } private void updateSelectionMode(ActionMode m) { if (favoritesSelected.size() > 0) { m.setTitle(favoritesSelected.size() + " " + getMyApplication().getString(R.string.shared_string_selected_lowercase)); } else { m.setTitle(""); } } @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { if (selectionMode) { CheckBox ch = (CheckBox) v.findViewById(R.id.toggle_item); FavouritePoint model = favouritesAdapter.getChild(groupPosition, childPosition); ch.setChecked(!ch.isChecked()); if (ch.isChecked()) { favoritesSelected.add(model); } else { favoritesSelected.remove(model); } updateSelectionMode(actionMode); } else { final FavouritePoint point = favouritesAdapter.getChild(groupPosition, childPosition); showOnMap(point); } return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == SELECT_MAP_MARKERS_ID) { selectMapMarkers(); return true; } else if (item.getItemId() == SHARE_ID) { shareFavourites(); return true; } else if (item.getItemId() == DELETE_ID) { enterDeleteMode(); return true; } else if (item.getItemId() == DELETE_ACTION_ID) { deleteFavoritesAction(); return true; } else { return super.onOptionsItemSelected(item); } } private void selectMapMarkers() { enterMapMarkersMode(); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { menu.clear(); MenuItem mi = createMenuItem(menu, SEARCH_ID, R.string.search_poi_filter, R.drawable.ic_action_search_dark, R.drawable.ic_action_search_dark, MenuItemCompat.SHOW_AS_ACTION_ALWAYS | MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW); mi.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { FavoritesSearchFragment.showInstance(getActivity(), ""); return true; } }); if (AndroidUiHelper.isOrientationPortrait(getActivity())) { menu = ((FavoritesActivity) getActivity()).getClearToolbar(true).getMenu(); } else { ((FavoritesActivity) getActivity()).getClearToolbar(false); } ((FavoritesActivity) getActivity()).updateListViewFooter(footerView); if (!MenuItemCompat.isActionViewExpanded(mi)) { createMenuItem(menu, SHARE_ID, R.string.shared_string_share, R.drawable.ic_action_gshare_dark, R.drawable.ic_action_gshare_dark, MenuItemCompat.SHOW_AS_ACTION_ALWAYS); if (getSettings().USE_MAP_MARKERS.get()) { createMenuItem(menu, SELECT_MAP_MARKERS_ID, R.string.select_map_markers, R.drawable.ic_action_flag_dark, R.drawable.ic_action_flag_dark, MenuItemCompat.SHOW_AS_ACTION_ALWAYS); } else { createMenuItem(menu, SELECT_MAP_MARKERS_ID, R.string.select_destination_and_intermediate_points, R.drawable.ic_action_intermediate, R.drawable.ic_action_intermediate, MenuItemCompat.SHOW_AS_ACTION_ALWAYS); } createMenuItem(menu, DELETE_ID, R.string.shared_string_delete, R.drawable.ic_action_delete_dark, R.drawable.ic_action_delete_dark, MenuItemCompat.SHOW_AS_ACTION_ALWAYS); // createMenuItem(menu, EXPORT_ID, R.string.shared_string_export, R.drawable.ic_action_gsave_light, // R.drawable.ic_action_gsave_dark, MenuItem.SHOW_AS_ACTION_IF_ROOM); } } public void showProgressBar() { OsmandActionBarActivity activity = getActionBarActivity(); if(activity != null) { activity.setSupportProgressBarIndeterminateVisibility(true); } } public void hideProgressBar() { OsmandActionBarActivity activity = getActionBarActivity(); if(activity != null) { activity.setSupportProgressBarIndeterminateVisibility(false); } } private void enterMapMarkersMode() { actionMode = getActionBarActivity().startSupportActionMode(new ActionMode.Callback() { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { enableSelectionMode(true); if (getSettings().USE_MAP_MARKERS.get()) { createMenuItem(menu, SELECT_MAP_MARKERS_ACTION_MODE_ID, R.string.select_map_markers, R.drawable.ic_action_flag_dark, R.drawable.ic_action_flag_dark, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM); } else { createMenuItem(menu, SELECT_MAP_MARKERS_ACTION_MODE_ID, R.string.select_destination_and_intermediate_points, R.drawable.ic_action_intermediate, R.drawable.ic_action_intermediate, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM); } favoritesSelected.clear(); groupsToDelete.clear(); favouritesAdapter.notifyDataSetInvalidated(); updateSelectionMode(mode); return true; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } @Override public void onDestroyActionMode(ActionMode mode) { enableSelectionMode(false); favouritesAdapter.notifyDataSetInvalidated(); } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { if (item.getItemId() == SELECT_MAP_MARKERS_ACTION_MODE_ID) { mode.finish(); selectMapMarkersImpl(); } return true; } }); } private void selectMapMarkersImpl() { if(!favoritesSelected.isEmpty()) { if (getSettings().USE_MAP_MARKERS.get()) { MapMarkersHelper markersHelper = getMyApplication().getMapMarkersHelper(); List<LatLon> points = new ArrayList<>(favoritesSelected.size()); List<PointDescription> names = new ArrayList<>(favoritesSelected.size()); for (FavouritePoint fp : favoritesSelected) { points.add(new LatLon(fp.getLatitude(), fp.getLongitude())); names.add(new PointDescription(PointDescription.POINT_TYPE_MAP_MARKER, fp.getName())); } markersHelper.addMapMarkers(points, names); MapActivity.launchMapActivityMoveToTop(getActivity()); } else { final TargetPointsHelper targetPointsHelper = getMyApplication().getTargetPointsHelper(); for (FavouritePoint fp : favoritesSelected) { targetPointsHelper.navigateToPoint(new LatLon(fp.getLatitude(), fp.getLongitude()), false, targetPointsHelper.getIntermediatePoints().size() + 1, new PointDescription(PointDescription.POINT_TYPE_FAVORITE, fp.getName())); } if (getMyApplication().getRoutingHelper().isRouteCalculated()) { targetPointsHelper.updateRouteAndRefresh(true); } IntermediatePointsDialog.openIntermediatePointsDialog(getActivity(), getMyApplication(), true); } } } private void enterDeleteMode() { actionMode = getActionBarActivity().startSupportActionMode(new ActionMode.Callback() { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { enableSelectionMode(true); createMenuItem(menu, DELETE_ACTION_ID, R.string.shared_string_delete, R.drawable.ic_action_delete_dark, R.drawable.ic_action_delete_dark, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM); favoritesSelected.clear(); groupsToDelete.clear(); favouritesAdapter.notifyDataSetInvalidated(); updateSelectionMode(mode); return true; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } @Override public void onDestroyActionMode(ActionMode mode) { enableSelectionMode(false); favouritesAdapter.notifyDataSetInvalidated(); } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { if (item.getItemId() == DELETE_ACTION_ID) { mode.finish(); deleteFavoritesAction(); } return true; } }); } private void enableSelectionMode(boolean selectionMode) { this.selectionMode = selectionMode; ((FavoritesActivity) getActivity()).setToolbarVisibility(!selectionMode && AndroidUiHelper.isOrientationPortrait(getActivity())); ((FavoritesActivity) getActivity()).updateListViewFooter(footerView); } private void deleteFavoritesAction() { if (groupsToDelete.size() + favoritesSelected.size() > 0) { AlertDialog.Builder b = new AlertDialog.Builder(getActivity()); b.setMessage(getString(R.string.favorite_delete_multiple, favoritesSelected.size(), groupsToDelete.size())); b.setPositiveButton(R.string.shared_string_delete, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (actionMode != null) { actionMode.finish(); } deleteFavorites(); } }); b.setNegativeButton(R.string.shared_string_cancel, null); b.show(); } } private StringBuilder generateHtmlPrint(List<FavoriteGroup> groups) { StringBuilder html = new StringBuilder(); html.append("<h1>My Favorites</h1>"); for (FavoriteGroup group : groups) { html.append("<h3>"+group.name+"</h3>"); for(FavouritePoint fp : group.points) { String url = "geo:"+((float)fp.getLatitude())+","+((float)fp.getLongitude())+"?m="+fp.getName(); html.append("<p>" + fp.getName() + " - " + "<a href=\"" + url + "\">geo:" + ((float) fp.getLatitude()) + "," + ((float) fp.getLongitude()) + "</a><br>"); if(!Algorithms.isEmpty(fp.getDescription())) { html.append(": " + fp.getDescription()); } html.append("</p>"); } } return html; } private void shareFavourites() { if (favouritesAdapter.isEmpty()) { Toast.makeText(getActivity(), R.string.no_fav_to_save, Toast.LENGTH_LONG).show(); } else { shareFavorites(null); } } public void shareFavorites(final FavoriteGroup group) { final AsyncTask<Void, Void, Void> exportTask = new AsyncTask<Void, Void, Void>() { File src = null; File dst = null; @Override protected Void doInBackground(Void... params) { if (group != null) { helper.saveFile(group.points, dst); } return null; } @Override protected void onPreExecute() { showProgressBar(); File dir = new File(getActivity().getCacheDir(), "share"); if (!dir.exists()) { dir.mkdir(); } if (group == null) { src = helper.getExternalFile(); } dst = new File(dir, src != null ? src.getName() : FavouritesDbHelper.FILE_TO_SAVE); } @Override protected void onPostExecute(Void res) { hideProgressBar(); try { if (src != null && dst != null) { Algorithms.fileCopy(src, dst); } final Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); List<FavoriteGroup> groups; if (group != null) { groups = new ArrayList<>(); groups.add(group); } else { groups = getMyApplication().getFavorites().getFavoriteGroups(); } sendIntent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(generateHtmlPrint(groups).toString())); sendIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_fav_subject)); sendIntent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(getActivity(), getActivity().getPackageName() + ".fileprovider", dst)); sendIntent.setType("text/plain"); startActivity(sendIntent); } catch (IOException e) { //Toast.makeText(getActivity(), "Error sharing favorites: " + e.getMessage(), Toast.LENGTH_LONG).show(); e.printStackTrace(); } } }; exportTask.execute(); } protected void export() { final File tosave = getMyApplication().getAppPath(FavouritesDbHelper.FILE_TO_SAVE); if (favouritesAdapter.isEmpty()) { Toast.makeText(getActivity(), R.string.no_fav_to_save, Toast.LENGTH_LONG).show(); } else if (!tosave.getParentFile().exists()) { Toast.makeText(getActivity(), R.string.sd_dir_not_accessible, Toast.LENGTH_LONG).show(); } else { final AsyncTask<Void, Void, String> exportTask = new AsyncTask<Void, Void, String>() { @Override protected String doInBackground(Void... params) { return helper.exportFavorites(); } @Override protected void onPreExecute() { showProgressBar(); } @Override protected void onPostExecute(String warning) { hideProgressBar(); if (warning == null) { Toast.makeText( getActivity(), MessageFormat.format(getString(R.string.fav_saved_sucessfully), tosave.getAbsolutePath()), Toast.LENGTH_LONG).show(); } else { Toast.makeText(getActivity(), warning, Toast.LENGTH_LONG).show(); } } }; if (tosave.exists()) { AlertDialog.Builder bld = new AlertDialog.Builder(getActivity()); bld.setPositiveButton(R.string.shared_string_yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { exportTask.execute(); } }); bld.setNegativeButton(R.string.shared_string_no, null); bld.setMessage(R.string.fav_export_confirmation); bld.show(); } else { exportTask.execute(); } } } private void initListExpandedState() { for (int i = 0; i < favouritesAdapter.getGroupCount(); i++) { String groupName = favouritesAdapter.getGroup(i).name; if (getGroupExpandedPreference(groupName).get()) { listView.expandGroup(i); } else { listView.collapseGroup(i); } } } private OsmandSettings.OsmandPreference<Boolean> getGroupExpandedPreference(String groupName) { OsmandSettings.OsmandPreference<Boolean> preference = preferenceCache.get(groupName); if (preference == null) { String groupKey = groupName + GROUP_EXPANDED_POSTFIX; preference = getSettings().registerBooleanPreference(groupKey, false); preferenceCache.put(groupKey, preference); } return preference; } public void showOnMap(final FavouritePoint point) { getMyApplication().getSettings().FAVORITES_TAB.set(FavoritesActivity.FAV_TAB); final OsmandSettings settings = getMyApplication().getSettings(); LatLon location = new LatLon(point.getLatitude(), point.getLongitude()); settings.setMapLocationToShow(location.getLatitude(), location.getLongitude(), settings.getLastKnownMapZoom(), new PointDescription(PointDescription.POINT_TYPE_FAVORITE, point.getName()), true, point); //$NON-NLS-1$ MapActivity.launchMapActivityMoveToTop(getActivity()); } class FavouritesAdapter extends OsmandBaseExpandableListAdapter implements Filterable { private static final boolean showOptionsButton = false; Map<FavoriteGroup, List<FavouritePoint>> favoriteGroups = new LinkedHashMap<>(); List<FavoriteGroup> groups = new ArrayList<FavoriteGroup>(); Filter myFilter; private Set<?> filter; public void synchronizeGroups() { favoriteGroups.clear(); groups.clear(); List<FavoriteGroup> disablesGroups = new ArrayList<>(); List<FavoriteGroup> gs = helper.getFavoriteGroups(); Set<?> flt = filter; for (FavoriteGroup key : gs) { boolean empty = true; if (flt == null || flt.contains(key)) { empty = false; favoriteGroups.put(key, new ArrayList<>(key.points)); } else { ArrayList<FavouritePoint> list = new ArrayList<>(); for (FavouritePoint p : key.points) { if (flt.contains(p)) { list.add(p); empty = false; } } favoriteGroups.put(key, list); } if (!empty) { if (key.visible) { groups.add(key); } else { disablesGroups.add(key); } } } groups.addAll(disablesGroups); notifyDataSetChanged(); } @Override public FavouritePoint getChild(int groupPosition, int childPosition) { return favoriteGroups.get(groups.get(groupPosition)).get(childPosition); } @Override public long getChildId(int groupPosition, int childPosition) { return groupPosition * 10000 + childPosition; } @Override public int getChildrenCount(int groupPosition) { return favoriteGroups.get(groups.get(groupPosition)).size(); } @Override public FavoriteGroup getGroup(int groupPosition) { return groups.get(groupPosition); } @Override public int getGroupCount() { return groups.size(); } @Override public long getGroupId(int groupPosition) { return groupPosition; } @Override public boolean hasStableIds() { return false; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { View row = convertView; boolean checkBox = row != null && row.findViewById(R.id.toggle_item) instanceof CheckBox; boolean same = (selectionMode && checkBox) || (!selectionMode && !checkBox); if (row == null || !same) { LayoutInflater inflater = getActivity().getLayoutInflater(); row = inflater.inflate(R.layout.expandable_list_item_category, parent, false); fixBackgroundRepeat(row); } OsmandApplication app = getMyApplication(); boolean light = app.getSettings().isLightContent(); final FavoriteGroup model = getGroup(groupPosition); boolean visible = model.visible; int enabledColor = light ? R.color.primary_text_light : R.color.primary_text_dark; int disabledColor = light ? R.color.secondary_text_light : R.color.secondary_text_dark; row.findViewById(R.id.group_divider).setVisibility(groupPosition == 0 ? View.GONE : View.VISIBLE); int color = model.color == 0 || model.color == Color.BLACK ? getResources().getColor(R.color.color_favorite) : model.color; setCategoryIcon(app, app.getIconsCache().getPaintedIcon( R.drawable.ic_action_fav_dark, visible ? (color | 0xff000000) : getResources().getColor(disabledColor)), groupPosition, isExpanded, row, light); adjustIndicator(app, groupPosition, isExpanded, row, light); TextView label = (TextView) row.findViewById(R.id.category_name); label.setTextColor(getResources().getColor(visible ? enabledColor : disabledColor)); if (visible) { Typeface typeface = FontCache.getFont(getContext(), "fonts/Roboto-Medium.ttf"); label.setTypeface(typeface, Typeface.NORMAL); } else { label.setTypeface(Typeface.DEFAULT, Typeface.ITALIC); } label.setText(model.name.length() == 0 ? getString(R.string.shared_string_favorites) : model.name); if (selectionMode) { final CheckBox ch = (CheckBox) row.findViewById(R.id.toggle_item); ch.setVisibility(View.VISIBLE); ch.setChecked(groupsToDelete.contains(model)); ch.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { List<FavouritePoint> fvs = model.points; if (ch.isChecked()) { groupsToDelete.add(model); if (fvs != null) { favoritesSelected.addAll(fvs); } } else { groupsToDelete.remove(model); if (fvs != null) { favoritesSelected.removeAll(fvs); } } favouritesAdapter.notifyDataSetInvalidated(); updateSelectionMode(actionMode); } }); row.findViewById(R.id.category_icon).setVisibility(View.GONE); } else { final CheckBox ch = (CheckBox) row.findViewById(R.id.toggle_item); ch.setVisibility(View.GONE); row.findViewById(R.id.category_icon).setVisibility(View.VISIBLE); } final View ch = row.findViewById(R.id.options); if (!selectionMode) { ((ImageView) ch).setImageDrawable(getMyApplication().getIconsCache().getThemedIcon(R.drawable.ic_overflow_menu_white)); ch.setVisibility(View.VISIBLE); ch.setContentDescription(getString(R.string.shared_string_settings)); ch.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { EditFavoriteGroupDialogFragment.showInstance(getChildFragmentManager(), model.name); } }); } else { ch.setVisibility(View.GONE); } return row; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { View row = convertView; if (row == null) { LayoutInflater inflater = getActivity().getLayoutInflater(); row = inflater.inflate(R.layout.favorites_list_item, parent, false); row.findViewById(R.id.list_divider).setVisibility(View.VISIBLE); } OsmandApplication app = getMyApplication(); boolean light = app.getSettings().isLightContent(); int enabledColor = light ? R.color.primary_text_light : R.color.primary_text_dark; int disabledColor = light ? R.color.secondary_text_light : R.color.secondary_text_dark; int disabledIconColor = light ? R.color.icon_color : R.color.icon_color_light; TextView name = (TextView) row.findViewById(R.id.favourite_label); TextView distanceText = (TextView) row.findViewById(R.id.distance); ImageView icon = (ImageView) row.findViewById(R.id.favourite_icon); final FavouritePoint model = getChild(groupPosition, childPosition); boolean visible = model.isVisible(); row.setTag(model); if (showOptionsButton) { ImageView options = (ImageView) row.findViewById(R.id.options); options.setFocusable(false); options.setImageDrawable(getMyApplication().getIconsCache().getThemedIcon( R.drawable.ic_overflow_menu_white)); options.setVisibility(View.VISIBLE); options.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { showOnMap(model); } }); } icon.setImageDrawable(FavoriteImageDrawable.getOrCreate(getActivity(), visible ? model.getColor() : getResources().getColor(disabledIconColor), false)); LatLon lastKnownMapLocation = getMyApplication().getSettings().getLastKnownMapLocation(); int dist = (int) (MapUtils.getDistance(model.getLatitude(), model.getLongitude(), lastKnownMapLocation.getLatitude(), lastKnownMapLocation.getLongitude())); String distance = OsmAndFormatter.getFormattedDistance(dist, getMyApplication()) + " "; name.setText(model.getName(), TextView.BufferType.SPANNABLE); name.setTypeface(Typeface.DEFAULT, visible ? Typeface.NORMAL : Typeface.ITALIC); name.setTextColor(getResources().getColor(visible ? enabledColor : disabledColor)); distanceText.setText(distance); if (visible) { distanceText.setTextColor(getResources().getColor(R.color.color_distance)); } else { distanceText.setTextColor(getResources().getColor(disabledColor)); } row.findViewById(R.id.group_image).setVisibility(View.GONE); ImageView direction = (ImageView) row.findViewById(R.id.direction); direction.setVisibility(View.VISIBLE); if (visible) { direction.setImageDrawable(arrowImage); } else { direction.setImageDrawable(arrowImageDisabled); } final CheckBox ch = (CheckBox) row.findViewById(R.id.toggle_item); if (selectionMode) { ch.setVisibility(View.VISIBLE); ch.setChecked(favoritesSelected.contains(model)); row.findViewById(R.id.favourite_icon).setVisibility(View.GONE); ch.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (ch.isChecked()) { favoritesSelected.add(model); } else { favoritesSelected.remove(model); } updateSelectionMode(actionMode); } }); } else { row.findViewById(R.id.favourite_icon).setVisibility(View.VISIBLE); ch.setVisibility(View.GONE); } return row; } @Override public Filter getFilter() { if (myFilter == null) { myFilter = new FavoritesFilter(); } return myFilter; } public void setFilterResults(Set<?> values) { this.filter = values; } } public class FavoritesFilter extends Filter { public FavoritesFilter() { } @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults results = new FilterResults(); if (constraint == null || constraint.length() == 0) { results.values = null; results.count = 1; } else { Set<Object> filter = new HashSet<>(); String cs = constraint.toString().toLowerCase(); for (FavoriteGroup g : helper.getFavoriteGroups()) { if (g.name.toLowerCase().contains(cs)) { filter.add(g); } else { for (FavouritePoint fp : g.points) { if (fp.getName().toLowerCase().contains(cs)) { filter.add(fp); } } } } results.values = filter; results.count = filter.size(); } return results; } @Override protected void publishResults(CharSequence constraint, FilterResults results) { synchronized (favouritesAdapter) { favouritesAdapter.setFilterResults((Set<?>) results.values); favouritesAdapter.synchronizeGroups(); } favouritesAdapter.notifyDataSetChanged(); if (constraint != null && constraint.length() > 1) { initListExpandedState(); } } } }