Merge pull request #10655 from osmandapp/points_menu_gpx

Points GPX context menu
This commit is contained in:
vshcherb 2021-01-25 09:17:57 +01:00 committed by GitHub
commit d224fdecaa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 1299 additions and 122 deletions

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
android:id="@+id/search_container"
android:layout_width="match_parent"
android:layout_height="56dp"
android:focusableInTouchMode="true"

View file

@ -43,8 +43,8 @@
android:paddingStart="@dimen/context_menu_padding_margin_default"
android:paddingLeft="@dimen/context_menu_padding_margin_default"
android:paddingEnd="@dimen/context_menu_padding_margin_default"
android:paddingRight="@dimen/context_menu_padding_margin_default"
android:paddingBottom="@dimen/context_menu_direction_margin">
android:paddingRight="@dimen/context_menu_padding_margin_default"
android:paddingBottom="@dimen/context_menu_direction_margin">
<LinearLayout
android:layout_width="0dp"
@ -73,7 +73,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:visibility="gone"
tools:text="@string/amenity_type_finance" />
tools:text="@string/amenity_type_finance" />
</LinearLayout>
@ -81,7 +81,7 @@
android:id="@+id/icon_view"
android:layout_width="@dimen/map_widget_icon"
android:layout_height="@dimen/map_widget_icon"
android:layout_marginTop="@dimen/context_menu_second_line_top_margin"
android:layout_marginTop="@dimen/context_menu_second_line_top_margin"
android:tint="?attr/default_icon_color"
osmand:srcCompat="@drawable/ic_action_polygom_dark" />
@ -118,6 +118,79 @@
</LinearLayout>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/context_menu_toolbar_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="0">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/actionModeBackground"
android:minHeight="@dimen/toolbar_height"
android:padding="0dp"
osmand:contentInsetEnd="0dp"
osmand:contentInsetLeft="0dp"
osmand:contentInsetRight="0dp"
osmand:contentInsetStart="0dp"
osmand:theme="@style/ThemeOverlay.AppCompat.ActionBar">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="@dimen/toolbar_height">
<ImageButton
android:id="@+id/close_button"
style="@style/Widget.AppCompat.Toolbar.Button.Navigation"
android:layout_width="@dimen/toolbar_height"
android:layout_height="@dimen/toolbar_height"
android:contentDescription="@string/access_shared_string_navigate_up"
osmand:srcCompat="@drawable/ic_arrow_back" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/toolbar_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_weight="1"
android:ellipsize="end"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:maxLines="2"
android:textColor="?attr/app_bar_primary_item_color"
android:textSize="@dimen/dialog_header_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="@string/routing_settings_2" />
<include
layout="@layout/search_text_layout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:maxLines="1"
android:visibility="gone" />
<ImageButton
android:id="@+id/search_button"
style="@style/Widget.AppCompat.Toolbar.Button.Navigation"
android:layout_width="@dimen/toolbar_height"
android:layout_height="@dimen/toolbar_height"
android:contentDescription="@string/access_shared_string_navigate_up"
android:visibility="gone"
osmand:srcCompat="@drawable/ic_action_search_dark" />
</LinearLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_navigation"
android:layout_width="match_parent"

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ExpandableListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="0dp"
android:layout_marginLeft="0dp"
android:layout_marginTop="0dp"
android:layout_marginEnd="0dp"
android:layout_marginRight="0dp"
android:divider="@null"
android:dividerHeight="0dp"
android:drawSelectorOnTop="false"
android:groupIndicator="@android:color/transparent" />
</LinearLayout>

View file

@ -12,6 +12,9 @@
-->
<string name="copy_to_map_favorites">Copy to favorites</string>
<string name="copy_to_map_markers">Copy to map markers</string>
<string name="delete_waypoints">Delete waypoints</string>
<string name="context_menu_edit_descr">Edit description</string>
<string name="context_menu_read_full">Read full</string>
<string name="delete_online_routing_engine">Delete this online routing engine?</string>

View file

@ -1,5 +1,6 @@
package net.osmand;
import android.os.AsyncTask;
import android.widget.Toast;
import androidx.annotation.NonNull;
@ -8,6 +9,8 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.Metadata;
import net.osmand.plus.GpxSelectionHelper;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.OsmandApplication;
@ -109,6 +112,8 @@ public class FileUtils {
selected.getGpxFile().path = dest.getAbsolutePath();
helper.updateSelectedGpxFile(selected);
}
RenameGpxAsyncTask renameGpxAsyncTask = new RenameGpxAsyncTask(app, dest);
renameGpxAsyncTask.execute();
return dest;
}
return null;
@ -196,4 +201,34 @@ public class FileUtils {
public interface RenameCallback {
void renamedTo(File file);
}
private static class RenameGpxAsyncTask extends AsyncTask<Void, Void, Exception> {
private OsmandApplication app;
private File file;
private RenameGpxAsyncTask(@NonNull OsmandApplication app, @NonNull File file) {
this.app = app;
this.file = file;
}
@Override
protected Exception doInBackground(Void... voids) {
GpxSelectionHelper helper = app.getSelectedGpxHelper();
SelectedGpxFile selected = helper.getSelectedFileByPath(file.getAbsolutePath());
GPXFile gpxFile;
if (selected != null && selected.getGpxFile() != null) {
gpxFile = selected.getGpxFile();
} else {
gpxFile = GPXUtilities.loadGPXFile(file);
}
if (gpxFile.metadata == null) {
gpxFile.metadata = new Metadata();
}
gpxFile.metadata.name = Algorithms.getFileNameWithoutExtension(file.getName());
return GPXUtilities.writeGpxFile(file, gpxFile);
}
}
}

View file

@ -45,10 +45,12 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.StringTokenizer;
public class GpxSelectionHelper {
@ -60,6 +62,7 @@ public class GpxSelectionHelper {
private static final String BACKUPMODIFIEDTIME = "backupTime";
private static final String COLOR = "color";
private static final String SELECTED_BY_USER = "selected_by_user";
private static final String HIDDEN_GROUPS = "hidden_groups";
private OsmandApplication app;
private SavingTrackHelper savingTrackHelper;
@ -577,7 +580,10 @@ public class GpxSelectionHelper {
} else if (obj.has(BACKUP)) {
selectedGpxFilesBackUp.put(gpx, gpx.modifiedTime);
} else {
selectGpxFile(gpx, true, false, true, selectedByUser, false);
SelectedGpxFile file = selectGpxFile(gpx, true, false, true, selectedByUser, false);
if (obj.has(HIDDEN_GROUPS)) {
readHiddenGroups(file, obj.getString(HIDDEN_GROUPS));
}
}
gpx.addGeneralTrack();
} else if (obj.has(CURRENT_TRACK)) {
@ -598,6 +604,33 @@ public class GpxSelectionHelper {
}
}
private String saveHiddenGroups(SelectedGpxFile selectedGpxFile) {
StringBuilder stringBuilder = new StringBuilder();
Iterator<String> it = selectedGpxFile.hiddenGroups.iterator();
while (it.hasNext()) {
String name = it.next();
stringBuilder.append(name != null ? name : " ");
if (it.hasNext()) {
stringBuilder.append(",");
}
}
return stringBuilder.toString();
}
public void readHiddenGroups(SelectedGpxFile selectedGpxFile, String text) {
StringTokenizer toks = new StringTokenizer(text, ",");
Set<String> res = new HashSet<>();
while (toks.hasMoreTokens()) {
String token = toks.nextToken();
if (!Algorithms.isBlank(token)) {
res.add(token);
} else {
res.add(null);
}
}
selectedGpxFile.hiddenGroups = res;
}
private int parseColor(String color) {
try {
return Algorithms.isEmpty(color) ? 0 : Algorithms.parseColor(color);
@ -619,6 +652,7 @@ public class GpxSelectionHelper {
if (s.gpxFile.getColor(0) != 0) {
obj.put(COLOR, Algorithms.colorToString(s.gpxFile.getColor(0)));
}
obj.put(HIDDEN_GROUPS, saveHiddenGroups(s));
}
obj.put(SELECTED_BY_USER, s.selectedByUser);
} catch (JSONException e) {
@ -765,6 +799,7 @@ public class GpxSelectionHelper {
private GPXFile gpxFile;
private GPXTrackAnalysis trackAnalysis;
private Set<String> hiddenGroups = new HashSet<>();
private List<TrkSegment> processedPointsToDisplay = new ArrayList<>();
private List<GpxDisplayGroup> displayGroups;
@ -832,6 +867,18 @@ public class GpxSelectionHelper {
return processedPointsToDisplay;
}
public Set<String> getHiddenGroups() {
return Collections.unmodifiableSet(hiddenGroups);
}
public void addHiddenGroups(String group) {
hiddenGroups.add(group);
}
public void removeHiddenGroups(String group) {
hiddenGroups.remove(group);
}
public GPXFile getGpxFile() {
return gpxFile;
}

View file

@ -62,6 +62,8 @@ public class RenameFileBottomSheet extends MenuBottomSheetDialogFragment {
file = new File(path);
}
selectedFileName = savedInstanceState.getString(SELECTED_FILE_NAME_KEY);
} else {
selectedFileName = Algorithms.getFileNameWithoutExtension(file);
}
items.add(new TitleItem(getString(R.string.shared_string_rename)));
@ -74,7 +76,7 @@ public class RenameFileBottomSheet extends MenuBottomSheetDialogFragment {
nameTextBox.setDefaultHintTextColor(colorStateList);
editText = view.findViewById(R.id.name_edit_text);
editText.setText(selectedFileName != null ? selectedFileName : Algorithms.getFileNameWithoutExtension(file));
editText.setText(selectedFileName);
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
@ -127,12 +129,13 @@ public class RenameFileBottomSheet extends MenuBottomSheetDialogFragment {
File dest;
int index = file.getName().lastIndexOf('.');
String ext = index == -1 ? "" : file.getName().substring(index);
String newName = Algorithms.getFileNameWithoutExtension(selectedFileName);
if (SQLiteTileSource.EXT.equals(ext)) {
dest = renameSQLiteFile(app, file, selectedFileName + ext, null);
dest = renameSQLiteFile(app, file, newName + ext, null);
} else if (IndexConstants.GPX_FILE_EXT.equals(ext)) {
dest = renameGpxFile(app, file, selectedFileName + ext, false, null);
dest = renameGpxFile(app, file, newName + ext, false, null);
} else {
dest = renameFile(app, file, selectedFileName + ext, false, null);
dest = renameFile(app, file, newName + ext, false, null);
}
if (dest != null) {
Fragment fragment = getTargetFragment();

View file

@ -15,14 +15,14 @@ import java.io.File;
import java.lang.ref.WeakReference;
import java.util.Set;
class DeletePointsTask extends AsyncTask<Void, Void, Void> {
public class DeletePointsTask extends AsyncTask<Void, Void, Void> {
private OsmandApplication app;
private GPXFile gpx;
private Set<GpxDisplayItem> selectedItems;
private WeakReference<OnPointsDeleteListener> listenerRef;
DeletePointsTask(OsmandApplication app, GPXFile gpxFile, Set<GpxDisplayItem> selectedItems, OnPointsDeleteListener listener) {
public DeletePointsTask(OsmandApplication app, GPXFile gpxFile, Set<GpxDisplayItem> selectedItems, OnPointsDeleteListener listener) {
this.app = app;
this.gpx = gpxFile;
this.selectedItems = selectedItems;

View file

@ -1,15 +1,16 @@
package net.osmand.plus.myplaces;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Typeface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.EditText;
@ -17,56 +18,127 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.ListPopupWindow;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.data.FavouritePoint;
import net.osmand.plus.FavouritesDbHelper;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayGroup;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
import net.osmand.plus.mapmarkers.MapMarkersHelper;
import net.osmand.plus.mapmarkers.MapMarkersGroup;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItemType;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.EditFavoriteGroupDialogFragment.FavoriteColorAdapter;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.SavingTrackHelper;
import net.osmand.plus.activities.TrackActivity;
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithCompoundButton;
import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.FontCache;
import net.osmand.plus.mapmarkers.MapMarkersGroup;
import net.osmand.plus.mapmarkers.MapMarkersHelper;
import net.osmand.plus.measurementtool.OptionsDividerItem;
import net.osmand.plus.myplaces.DeletePointsTask.OnPointsDeleteListener;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.track.TrackMenuFragment;
import net.osmand.util.Algorithms;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static net.osmand.plus.settings.bottomsheets.BooleanPreferenceBottomSheet.getCustomButtonView;
import static net.osmand.plus.settings.bottomsheets.BooleanPreferenceBottomSheet.updateCustomButtonView;
public class EditTrackGroupDialogFragment extends MenuBottomSheetDialogFragment implements OnPointsDeleteListener {
public class EditTrackGroupDialogFragment extends MenuBottomSheetDialogFragment {
public static final String TAG = EditTrackGroupDialogFragment.class.getSimpleName();
private OsmandApplication app;
private GpxDisplayGroup group;
@Override
public void createMenuItems(Bundle savedInstanceState) {
final OsmandApplication app = getMyApplication();
app = requiredMyApplication();
if (group == null) {
return;
}
items.add(new TitleItem(getCategoryName(app, group.getName())));
BaseBottomSheetItem editNameItem = new SimpleBottomSheetItem.Builder()
.setIcon(getContentIcon(R.drawable.ic_action_edit_dark))
.setTitle(getString(R.string.edit_name))
.setLayoutId(R.layout.bottom_sheet_item_simple)
SelectedGpxFile selectedGpxFile = app.getSelectedGpxHelper().getSelectedFileByPath(group.getGpx().path);
if (group.getType() == GpxDisplayItemType.TRACK_POINTS && selectedGpxFile != null) {
items.add(createShowOnMapItem(selectedGpxFile));
}
items.add(createEditNameItem());
items.add(new OptionsDividerItem(app));
// items.add(createCopyToMarkersItem());
items.add(createCopyToFavoritesItem());
items.add(new OptionsDividerItem(app));
items.add(createDeleteGroupItem());
}
private BaseBottomSheetItem createShowOnMapItem(final SelectedGpxFile selectedGpxFile) {
final String name = Algorithms.isEmpty(group.getName()) ? null : group.getName();
boolean checked = !selectedGpxFile.getHiddenGroups().contains(name);
final ApplicationMode mode = app.getSettings().getApplicationMode();
final BottomSheetItemWithCompoundButton[] showOnMapItem = new BottomSheetItemWithCompoundButton[1];
showOnMapItem[0] = (BottomSheetItemWithCompoundButton) new BottomSheetItemWithCompoundButton.Builder()
.setCompoundButtonColorId(mode.getIconColorInfo().getColor(nightMode))
.setChecked(checked)
.setTitle(getString(R.string.shared_string_show_on_map))
.setCustomView(getCustomButtonView(app, mode, checked, nightMode))
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Activity activity = getActivity();
boolean checked = !showOnMapItem[0].isChecked();
if (checked) {
selectedGpxFile.removeHiddenGroups(name);
} else {
selectedGpxFile.addHiddenGroups(name);
}
app.getSelectedGpxHelper().updateSelectedGpxFile(selectedGpxFile);
showOnMapItem[0].setChecked(checked);
updateCustomButtonView(app, mode, v, checked, nightMode);
FragmentActivity activity = getActivity();
if (activity instanceof MapActivity) {
((MapActivity) activity).refreshMap();
}
}
})
.create();
return showOnMapItem[0];
}
private BaseBottomSheetItem createEditNameItem() {
return new SimpleBottomSheetItem.Builder()
.setIcon(getContentIcon(R.drawable.ic_action_name_field))
.setTitle(getString(R.string.shared_string_rename))
.setLayoutId(R.layout.bottom_sheet_item_simple)
.setLayoutId(R.layout.bottom_sheet_item_simple_pad_32dp)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final FragmentActivity activity = getActivity();
if (activity != null) {
AlertDialog.Builder b = new AlertDialog.Builder(activity);
b.setTitle(R.string.favorite_group_name);
@ -86,11 +158,8 @@ public class EditTrackGroupDialogFragment extends MenuBottomSheetDialogFragment
String name = nameEditText.getText().toString();
boolean nameChanged = !Algorithms.objectEquals(group.getName(), name);
if (nameChanged) {
TrackActivity trackActivity = getTrackActivity();
if (trackActivity != null) {
new UpdateGpxCategoryTask(trackActivity, group, name)
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
new UpdateGpxCategoryTask(activity, group, name)
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
dismiss();
}
@ -100,20 +169,118 @@ public class EditTrackGroupDialogFragment extends MenuBottomSheetDialogFragment
}
})
.create();
items.add(editNameItem);
}
private BaseBottomSheetItem createCopyToMarkersItem() {
return new SimpleBottomSheetItem.Builder()
.setIcon(getContentIcon(R.drawable.ic_action_copy))
.setTitle(getString(R.string.copy_to_map_markers))
.setLayoutId(R.layout.bottom_sheet_item_simple)
.setLayoutId(R.layout.bottom_sheet_item_simple_pad_32dp)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// MapMarkersHelper markersHelper = app.getMapMarkersHelper();
// MapMarkersGroup markersGroup = markersHelper.getMarkersGroup(group);
// if (markersGroup != null) {
// markersHelper.removeMarkersGroup(markersGroup);
// } else {
// markersHelper.addOrEnableGroup(group);
// }
}
})
.create();
}
private BaseBottomSheetItem createCopyToFavoritesItem() {
return new SimpleBottomSheetItem.Builder()
.setIcon(getContentIcon(R.drawable.ic_action_copy))
.setTitle(getString(R.string.copy_to_map_favorites))
.setLayoutId(R.layout.bottom_sheet_item_simple)
.setLayoutId(R.layout.bottom_sheet_item_simple_pad_32dp)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
saveGroupToFavorites();
}
})
.create();
}
private void saveGroupToFavorites() {
FragmentActivity activity = getActivity();
if (activity != null) {
AlertDialog.Builder b = new AlertDialog.Builder(activity);
final EditText editText = new EditText(activity);
String name = group.getModifiableList().iterator().next().group.getName();
if (name.indexOf('\n') > 0) {
name = name.substring(0, name.indexOf('\n'));
}
editText.setText(name);
int leftMargin = AndroidUtils.dpToPx(activity, 16f);
int topMargin = AndroidUtils.dpToPx(activity, 8f);
editText.setPadding(leftMargin, topMargin, leftMargin, topMargin);
b.setTitle(R.string.save_as_favorites_points);
b.setView(editText);
b.setPositiveButton(R.string.shared_string_save, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String category = editText.getText().toString();
FavouritesDbHelper favouritesDbHelper = app.getFavorites();
for (GpxDisplayItem item : group.getModifiableList()) {
if (item.locationStart != null) {
FavouritePoint fp = FavouritePoint.fromWpt(item.locationStart, app, category);
if (!Algorithms.isEmpty(item.description)) {
fp.setDescription(item.description);
}
favouritesDbHelper.addFavourite(fp, false);
}
}
favouritesDbHelper.saveCurrentPointsIntoFile();
dismiss();
}
});
b.setNegativeButton(R.string.shared_string_cancel, null);
b.show();
}
}
private BaseBottomSheetItem createDeleteGroupItem() {
String delete = app.getString(R.string.shared_string_delete);
Typeface typeface = FontCache.getRobotoMedium(app);
return new SimpleBottomSheetItem.Builder()
.setTitleColorId(R.color.color_osm_edit_delete)
.setIcon(getIcon(R.drawable.ic_action_delete_dark, R.color.color_osm_edit_delete))
.setTitle(UiUtilities.createCustomFontSpannable(typeface, delete, delete))
.setLayoutId(R.layout.bottom_sheet_item_simple_pad_32dp)
.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
deleteGroupItems();
}
})
.create();
}
private void deleteGroupItems() {
Set<GpxDisplayItem> items = new HashSet<>(group.getModifiableList());
new DeletePointsTask(app, group.getGpx(), items, this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private BaseBottomSheetItem createChangeColorItem() {
final int themeRes = nightMode ? R.style.OsmandDarkTheme : R.style.OsmandLightTheme;
final View changeColorView = View.inflate(new ContextThemeWrapper(getContext(), themeRes),
R.layout.change_fav_color, null);
((ImageView) changeColorView.findViewById(R.id.change_color_icon))
.setImageDrawable(getContentIcon(R.drawable.ic_action_appearance));
updateColorView((ImageView) changeColorView.findViewById(R.id.colorImage));
BaseBottomSheetItem changeColorItem = new BaseBottomSheetItem.Builder()
return new BaseBottomSheetItem.Builder()
.setCustomView(changeColorView)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Activity activity = getActivity();
final FragmentActivity activity = getActivity();
if (activity != null) {
final ListPopupWindow popup = new ListPopupWindow(activity);
popup.setAnchorView(v);
@ -135,11 +302,8 @@ public class EditTrackGroupDialogFragment extends MenuBottomSheetDialogFragment
Integer color = colorAdapter.getItem(position);
if (color != null) {
if (color != group.getColor()) {
TrackActivity trackActivity = getTrackActivity();
if (trackActivity != null) {
new UpdateGpxCategoryTask(trackActivity, group, color)
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
new UpdateGpxCategoryTask(activity, group, color)
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
popup.dismiss();
@ -151,8 +315,6 @@ public class EditTrackGroupDialogFragment extends MenuBottomSheetDialogFragment
}
})
.create();
items.add(changeColorItem);
}
@Override
@ -163,15 +325,6 @@ public class EditTrackGroupDialogFragment extends MenuBottomSheetDialogFragment
}
}
@Nullable
private TrackActivity getTrackActivity() {
Activity activity = getActivity();
if (activity != null && activity instanceof TrackActivity) {
return (TrackActivity) activity;
}
return null;
}
private static String getCategoryName(@NonNull Context ctx, String category) {
return Algorithms.isEmpty(category) ? ctx.getString(R.string.shared_string_waypoints) : category;
}
@ -181,24 +334,38 @@ public class EditTrackGroupDialogFragment extends MenuBottomSheetDialogFragment
if (color == 0) {
colorImageView.setImageDrawable(getContentIcon(R.drawable.ic_action_circle));
} else {
colorImageView.setImageDrawable(getMyApplication().getUIUtilities().getPaintedIcon(R.drawable.ic_action_circle, color));
colorImageView.setImageDrawable(app.getUIUtilities().getPaintedIcon(R.drawable.ic_action_circle, color));
}
}
public static void showInstance(FragmentManager fragmentManager, GpxDisplayGroup group) {
EditTrackGroupDialogFragment f = (EditTrackGroupDialogFragment) fragmentManager
.findFragmentByTag(EditTrackGroupDialogFragment.TAG);
if (f == null ) {
f = new EditTrackGroupDialogFragment();
f.group = group;
f.show(fragmentManager, EditTrackGroupDialogFragment.TAG);
public static void showInstance(FragmentManager fragmentManager, GpxDisplayGroup group, Fragment target) {
if (!fragmentManager.isStateSaved() && fragmentManager.findFragmentByTag(TAG) == null) {
EditTrackGroupDialogFragment fragment = new EditTrackGroupDialogFragment();
fragment.group = group;
fragment.setRetainInstance(true);
fragment.setTargetFragment(target, 0);
fragment.show(fragmentManager, TAG);
}
}
@Override
public void onPointsDeletionStarted() {
}
@Override
public void onPointsDeleted() {
Fragment fragment = getTargetFragment();
if (fragment instanceof TrackMenuFragment) {
((TrackMenuFragment) fragment).updateContent();
}
dismiss();
}
private static class UpdateGpxCategoryTask extends AsyncTask<Void, Void, Void> {
private OsmandApplication app;
private WeakReference<TrackActivity> activityRef;
private WeakReference<FragmentActivity> activityRef;
private GpxDisplayGroup group;
@ -208,20 +375,20 @@ public class EditTrackGroupDialogFragment extends MenuBottomSheetDialogFragment
private ProgressDialog progressDialog;
private boolean wasUpdated = false;
private UpdateGpxCategoryTask(@NonNull TrackActivity activity, @NonNull GpxDisplayGroup group) {
private UpdateGpxCategoryTask(@NonNull FragmentActivity activity, @NonNull GpxDisplayGroup group) {
this.app = (OsmandApplication) activity.getApplication();
activityRef = new WeakReference<>(activity);
this.group = group;
}
UpdateGpxCategoryTask(@NonNull TrackActivity activity, @NonNull GpxDisplayGroup group,
UpdateGpxCategoryTask(@NonNull FragmentActivity activity, @NonNull GpxDisplayGroup group,
@NonNull String newCategory) {
this(activity, group);
this.newCategory = newCategory;
}
UpdateGpxCategoryTask(@NonNull TrackActivity activity, @NonNull GpxDisplayGroup group,
UpdateGpxCategoryTask(@NonNull FragmentActivity activity, @NonNull GpxDisplayGroup group,
@NonNull Integer newColor) {
this(activity, group);
this.newColor = newColor;
@ -229,7 +396,7 @@ public class EditTrackGroupDialogFragment extends MenuBottomSheetDialogFragment
@Override
protected void onPreExecute() {
TrackActivity activity = activityRef.get();
FragmentActivity activity = activityRef.get();
if (activity != null) {
progressDialog = new ProgressDialog(activity);
progressDialog.setTitle(EditTrackGroupDialogFragment.getCategoryName(app, group.getName()));
@ -293,9 +460,15 @@ public class EditTrackGroupDialogFragment extends MenuBottomSheetDialogFragment
progressDialog.dismiss();
}
TrackActivity activity = activityRef.get();
if (activity != null) {
activity.loadGpx();
FragmentActivity activity = activityRef.get();
if (activity instanceof TrackActivity) {
((TrackActivity) activity).loadGpx();
} else if (activity instanceof MapActivity) {
MapActivity mapActivity = (MapActivity) activity;
TrackMenuFragment fragment = mapActivity.getTrackMenuFragment();
if (fragment != null) {
fragment.updateContent();
}
}
}

View file

@ -1007,7 +1007,7 @@ public class TrackPointFragment extends OsmandExpandableListFragment implements
public void onClick(View v) {
FragmentActivity activity = getActivity();
if (activity != null) {
EditTrackGroupDialogFragment.showInstance(activity.getSupportFragmentManager(), group);
EditTrackGroupDialogFragment.showInstance(activity.getSupportFragmentManager(), group, null);
}
}
});

View file

@ -122,14 +122,14 @@ public class BooleanPreferenceBottomSheet extends BasePreferenceBottomSheet {
return R.string.shared_string_close;
}
protected static View getCustomButtonView(OsmandApplication app, ApplicationMode mode, boolean checked, boolean nightMode) {
public static View getCustomButtonView(OsmandApplication app, ApplicationMode mode, boolean checked, boolean nightMode) {
View customView = UiUtilities.getInflater(app, nightMode).inflate(R.layout.bottom_sheet_item_preference_switch, null);
updateCustomButtonView(app, mode, customView, checked, nightMode);
return customView;
}
protected static void updateCustomButtonView(OsmandApplication app, ApplicationMode mode, View customView, boolean checked, boolean nightMode) {
public static void updateCustomButtonView(OsmandApplication app, ApplicationMode mode, View customView, boolean checked, boolean nightMode) {
Context themedCtx = UiUtilities.getThemedContext(app, nightMode);
View buttonView = customView.findViewById(R.id.button_container);

View file

@ -22,7 +22,6 @@ public class SegmentsCard extends BaseCard {
private TrackDisplayHelper displayHelper;
private GpxDisplayItemType[] filterTypes = new GpxDisplayItemType[] {GpxDisplayItemType.TRACK_SEGMENT};
private SegmentGPXAdapter adapter;
private SegmentActionsListener listener;
public SegmentsCard(@NonNull MapActivity mapActivity, @NonNull TrackDisplayHelper displayHelper,

View file

@ -112,10 +112,16 @@ public class TrackAppearanceFragment extends ContextMenuScrollFragment implement
return 0;
}
@Override
public float getMiddleStateKoef() {
return 0.5f;
}
@Override
public int getInitialMenuState() {
return MenuState.HALF_SCREEN;
}
public TrackDrawInfo getTrackDrawInfo() {
return trackDrawInfo;
}

View file

@ -1,14 +1,9 @@
package net.osmand.plus.track;
import android.app.Activity;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
import net.osmand.data.QuadRect;
import net.osmand.plus.GPXDatabase.GpxDataItem;
import net.osmand.plus.GpxSelectionHelper;
@ -17,10 +12,6 @@ import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItemType;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.measurementtool.GpxData;
import net.osmand.plus.settings.backend.OsmandSettings;
import java.io.File;
import java.util.ArrayList;
@ -163,21 +154,4 @@ public class TrackDisplayHelper {
}
return list;
}
public void addNewGpxData(Activity activity) {
GPXFile gpxFile = getGpx();
GpxData gpxData = new GpxData(gpxFile);
WptPt pointToShow = gpxFile != null ? gpxFile.findPointToShow() : null;
if (pointToShow != null) {
LatLon location = new LatLon(pointToShow.getLatitude(), pointToShow.getLongitude());
final OsmandSettings settings = app.getSettings();
settings.setMapLocationToShow(location.getLatitude(), location.getLongitude(),
settings.getLastKnownMapZoom(),
new PointDescription(PointDescription.POINT_TYPE_WPT, activity.getString(R.string.add_line)),
false,
gpxData
);
MapActivity.launchMapActivityMoveToTop(activity);
}
}
}

View file

@ -1,21 +1,27 @@
package net.osmand.plus.track;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.DialogInterface;
import android.content.res.ColorStateList;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
@ -33,6 +39,7 @@ import net.osmand.GPXUtilities.TrkSegment;
import net.osmand.Location;
import net.osmand.PlatformUtil;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
import net.osmand.data.QuadRect;
import net.osmand.data.RotatedTileBox;
import net.osmand.plus.GpxDbHelper;
@ -61,6 +68,7 @@ import net.osmand.plus.measurementtool.GpxData;
import net.osmand.plus.measurementtool.MeasurementEditingContext;
import net.osmand.plus.measurementtool.MeasurementToolFragment;
import net.osmand.plus.myplaces.AvailableGPXFragment.GpxInfo;
import net.osmand.plus.myplaces.DeletePointsTask.OnPointsDeleteListener;
import net.osmand.plus.myplaces.MoveGpxFileBottomSheet;
import net.osmand.plus.myplaces.MoveGpxFileBottomSheet.OnTrackFileMoveListener;
import net.osmand.plus.myplaces.SegmentActionsListener;
@ -70,6 +78,7 @@ import net.osmand.plus.osmedit.OsmEditingPlugin;
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener;
import net.osmand.plus.track.SaveGpxAsyncTask.SaveGpxListener;
import net.osmand.plus.views.AddGpxPointBottomSheetHelper.NewGpxPoint;
import net.osmand.plus.widgets.IconPopupMenu;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
@ -94,9 +103,12 @@ import static net.osmand.plus.track.OptionsCard.RENAME_BUTTON_INDEX;
import static net.osmand.plus.track.OptionsCard.SHARE_BUTTON_INDEX;
import static net.osmand.plus.track.OptionsCard.SHOW_ON_MAP_BUTTON_INDEX;
import static net.osmand.plus.track.OptionsCard.UPLOAD_OSM_BUTTON_INDEX;
import static net.osmand.plus.track.TrackPointsCard.ADD_WAYPOINT_INDEX;
import static net.osmand.plus.track.TrackPointsCard.DELETE_WAYPOINTS_INDEX;
public class TrackMenuFragment extends ContextMenuScrollFragment implements CardListener,
SegmentActionsListener, RenameCallback, OnTrackFileMoveListener, OsmAndLocationListener, OsmAndCompassListener {
SegmentActionsListener, RenameCallback, OnTrackFileMoveListener, OnPointsDeleteListener,
OsmAndLocationListener, OsmAndCompassListener {
public static final String TAG = TrackMenuFragment.class.getName();
private static final Log log = PlatformUtil.getLog(TrackMenuFragment.class);
@ -105,37 +117,46 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
private TrackDisplayHelper displayHelper;
private SelectedGpxFile selectedGpxFile;
private View routeMenuTopShadowAll;
private TextView headerTitle;
private ImageView headerIcon;
private BottomNavigationView bottomNav;
private TrackMenuType menuType = TrackMenuType.OVERVIEW;
private SegmentsCard segmentsCard;
private OptionsCard optionsCard;
private DescriptionCard descriptionCard;
private OverviewCard overviewCard;
private TrackPointsCard pointsCard;
private TextView headerTitle;
private ImageView headerIcon;
private View toolbarContainer;
private View searchContainer;
private ImageView searchButton;
private EditText searchEditText;
private TextView toolbarTextView;
private View routeMenuTopShadowAll;
private BottomNavigationView bottomNav;
private String gpxTitle;
private TrackChartPoints trackChartPoints;
private int menuTitleHeight;
private String gpxTitle;
private UpdateLocationViewCache updateLocationViewCache;
private Location lastLocation = null;
private Float heading;
private Location lastLocation;
private UpdateLocationViewCache updateLocationViewCache;
private boolean locationUpdateStarted;
private int menuTitleHeight;
private int toolbarHeightPx;
public enum TrackMenuType {
OVERVIEW(R.id.action_overview, R.string.shared_string_overview),
TRACK(R.id.action_track, R.string.shared_string_gpx_tracks),
POINTS(R.id.action_points, R.string.shared_string_gpx_points),
OPTIONS(R.id.action_options, R.string.shared_string_options);
TrackMenuType(@DrawableRes int iconId, @StringRes int titleId) {
this.iconId = iconId;
TrackMenuType(int menuItemId, @StringRes int titleId) {
this.menuItemId = menuItemId;
this.titleId = titleId;
}
public final int iconId;
public final int menuItemId;
public final int titleId;
}
@ -156,7 +177,7 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
@Override
public int getToolbarHeight() {
return 0;
return toolbarHeightPx;
}
public float getMiddleStateKoef() {
@ -183,6 +204,7 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
app = requireMyApplication();
GpxDbHelper gpxDbHelper = app.getGpxDbHelper();
displayHelper = new TrackDisplayHelper(app);
updateLocationViewCache = app.getUIUtilities().getUpdateLocationViewCache();
Bundle arguments = getArguments();
if (arguments != null) {
@ -200,6 +222,7 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
String fileName = Algorithms.getFileWithoutDirs(getGpx().path);
gpxTitle = GpxUiHelper.getGpxTitle(fileName);
}
toolbarHeightPx = getResources().getDimensionPixelSize(R.dimen.dashboard_map_toolbar);
}
public GPXFile getGpx() {
@ -214,7 +237,10 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
routeMenuTopShadowAll = view.findViewById(R.id.route_menu_top_shadow_all);
headerTitle = view.findViewById(R.id.title);
headerIcon = view.findViewById(R.id.icon_view);
updateLocationViewCache = app.getUIUtilities().getUpdateLocationViewCache();
toolbarContainer = view.findViewById(R.id.context_menu_toolbar_container);
toolbarTextView = view.findViewById(R.id.toolbar_title);
searchButton = view.findViewById(R.id.search_button);
searchContainer = view.findViewById(R.id.search_container);
if (isPortrait()) {
AndroidUiHelper.updateVisibility(getTopShadow(), true);
@ -226,6 +252,7 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
}
setupCards();
setupToolbar();
updateHeader();
setupButtons(view);
enterTrackAppearanceMode();
@ -261,6 +288,74 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
boolean isOptions = menuType == TrackMenuType.OPTIONS;
setHeaderTitle(isOptions ? app.getString(menuType.titleId) : gpxTitle, !isOptions);
}
if (menuType == TrackMenuType.POINTS) {
AndroidUiHelper.updateVisibility(searchButton, true);
} else {
AndroidUiHelper.updateVisibility(toolbarTextView, true);
AndroidUiHelper.updateVisibility(searchButton, false);
AndroidUiHelper.updateVisibility(searchContainer, false);
}
}
private void setupToolbar() {
toolbarTextView.setText(gpxTitle);
ImageView closeButton = toolbarContainer.findViewById(R.id.close_button);
closeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (menuType == TrackMenuType.POINTS) {
AndroidUiHelper.updateVisibility(toolbarTextView, true);
AndroidUiHelper.updateVisibility(searchButton, true);
AndroidUiHelper.updateVisibility(searchContainer, false);
}
openMenuHeaderOnly();
}
});
closeButton.setImageResource(AndroidUtils.getNavigationIconResId(toolbarContainer.getContext()));
searchButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
AndroidUiHelper.updateVisibility(searchContainer, true);
AndroidUiHelper.updateVisibility(searchButton, false);
AndroidUiHelper.updateVisibility(toolbarTextView, false);
}
});
searchEditText = toolbarContainer.findViewById(R.id.searchEditText);
searchEditText.setHint(R.string.search_poi_filter);
searchEditText.addTextChangedListener(
new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (pointsCard != null) {
pointsCard.filter(s.toString());
}
}
}
);
ImageView clearButton = toolbarContainer.findViewById(R.id.clearButton);
clearButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!Algorithms.isEmpty(searchEditText.getText())) {
searchEditText.setText("");
searchEditText.setSelection(0);
}
if (pointsCard != null) {
pointsCard.updateContent();
}
}
});
}
private void setupCards() {
@ -296,13 +391,25 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
if (descriptionCard != null && descriptionCard.getView() != null) {
ViewGroup parent = ((ViewGroup) descriptionCard.getView().getParent());
if (parent != null) {
cardsContainer.removeView(descriptionCard.getView());
parent.removeView(descriptionCard.getView());
}
cardsContainer.addView(descriptionCard.getView());
} else {
descriptionCard = new DescriptionCard(getMapActivity(), displayHelper.getGpx());
cardsContainer.addView(descriptionCard.build(mapActivity));
}
} else if (menuType == TrackMenuType.POINTS) {
if (pointsCard != null && pointsCard.getView() != null) {
ViewGroup parent = (ViewGroup) pointsCard.getView().getParent();
if (parent != null) {
parent.removeAllViews();
}
cardsContainer.addView(pointsCard.getView());
} else {
pointsCard = new TrackPointsCard(mapActivity, displayHelper);
pointsCard.setListener(this);
cardsContainer.addView(pointsCard.build(mapActivity));
}
}
}
}
@ -318,12 +425,14 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
protected void setViewY(int y, boolean animated, boolean adjustMapPos) {
super.setViewY(y, animated, adjustMapPos);
updateStatusBarColor();
updateToolbar(y, animated);
}
@Override
protected void updateMainViewLayout(int posY) {
super.updateMainViewLayout(posY);
updateStatusBarColor();
updateToolbar(posY, true);
}
@Override
@ -484,7 +593,7 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
if (Build.VERSION.SDK_INT >= 23 && !nightMode) {
view.setSystemUiVisibility(view.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
return nightMode ? R.color.divider_color_dark : R.color.divider_color_light;
return nightMode ? R.color.status_bar_color_dark : R.color.status_bar_color_light;
} else {
if (Build.VERSION.SDK_INT >= 23 && !nightMode) {
view.setSystemUiVisibility(view.getSystemUiVisibility() & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
@ -522,8 +631,8 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
if (mapActivity == null) {
return;
}
final GPXFile gpxFile = getGpx();
if (card instanceof OptionsCard || card instanceof OverviewCard) {
final GPXFile gpxFile = getGpx();
if (buttonIndex == SHOW_ON_MAP_BUTTON_INDEX) {
boolean gpxFileSelected = !isGpxFileSelected(app, gpxFile);
app.getSelectedGpxHelper().selectGpxFile(gpxFile, gpxFileSelected, false);
@ -615,6 +724,25 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
});
builder.show();
}
} else if (card instanceof TrackPointsCard) {
if (buttonIndex == ADD_WAYPOINT_INDEX) {
PointDescription pointDescription = new PointDescription(PointDescription.POINT_TYPE_WPT, app.getString(R.string.add_waypoint));
QuadRect rect = displayHelper.getRect();
NewGpxPoint newGpxPoint = new NewGpxPoint(gpxFile, pointDescription, rect);
mapActivity.getMapView().fitRectToMap(rect.left, rect.right, rect.top, rect.bottom,
(int) rect.width(), (int) rect.height(), 0);
mapActivity.getMapLayers().getContextMenuLayer().enterAddGpxPointMode(newGpxPoint);
hide();
} else if (buttonIndex == DELETE_WAYPOINTS_INDEX) {
TrackPointsCard pointsCard = (TrackPointsCard) card;
if (pointsCard.isSelectionMode()) {
pointsCard.deleteItemsAction();
} else {
pointsCard.setSelectionMode(true);
}
}
}
}
@ -627,6 +755,34 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
return y;
}
public void updateToolbar(int y, boolean animated) {
final MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
if (toolbarContainer != null && isPortrait()) {
if (animated) {
final float toolbarAlpha = getToolbarAlpha(y);
if (toolbarAlpha > 0) {
updateVisibility(toolbarContainer, true);
}
toolbarContainer.animate().alpha(toolbarAlpha)
.setDuration(ContextMenuFragment.ANIMATION_DURATION)
.setInterpolator(new DecelerateInterpolator())
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
updateVisibility(toolbarContainer, toolbarAlpha);
mapActivity.updateStatusBarColor();
}
})
.start();
} else {
updateToolbarVisibility(toolbarContainer, y);
mapActivity.updateStatusBarColor();
}
}
}
}
@Override
protected void onHeaderClick() {
adjustMapPosition(getViewY());
@ -664,7 +820,7 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
for (TrackMenuType type : TrackMenuType.values()) {
if (type.iconId == item.getItemId()) {
if (type.menuItemId == item.getItemId()) {
menuType = type;
setupCards();
updateHeader();
@ -687,6 +843,9 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
if (descriptionCard != null) {
descriptionCard.updateContent();
}
if (pointsCard != null) {
pointsCard.updateContent();
}
setupCards();
}
@ -700,6 +859,18 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
}
@Override
public void onPointsDeletionStarted() {
}
@Override
public void onPointsDeleted() {
if (pointsCard != null) {
pointsCard.onPointsDeleted();
}
}
@Override
public void onPointSelected(TrkSegment segment, double lat, double lon) {
if (trackChartPoints == null) {
@ -729,7 +900,7 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
TrackDetailsMenu trackDetailsMenu = getMapActivity().getTrackDetailsMenu();
trackDetailsMenu.setGpxItem(gpxItem);
trackDetailsMenu.show();
close();
hide();
}
@Override
@ -783,7 +954,7 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
private void editSegment(TrkSegment segment) {
GPXFile gpxFile = getGpx();
openPlanRoute(new GpxData(gpxFile));
close();
hide();
}
public void openPlanRoute(GpxData gpxData) {
@ -834,12 +1005,24 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private void close() {
private void hide() {
try {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
FragmentManager fragmentManager = mapActivity.getSupportFragmentManager();
fragmentManager.beginTransaction().remove(this).commitAllowingStateLoss();
fragmentManager.beginTransaction().hide(this).commit();
}
} catch (Exception e) {
log.error(e);
}
}
public void show() {
try {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
FragmentManager fragmentManager = mapActivity.getSupportFragmentManager();
fragmentManager.beginTransaction().show(this).commit();
}
} catch (Exception e) {
log.error(e);
@ -859,7 +1042,7 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
mapActivity.getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragmentContainer, fragment, fragment.getFragmentTag())
.replace(R.id.fragmentContainer, fragment, TAG)
.addToBackStack(fragment.getFragmentTag())
.commitAllowingStateLoss();
return true;

View file

@ -0,0 +1,639 @@
package net.osmand.plus.track;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.OnChildClickListener;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import net.osmand.AndroidUtils;
import net.osmand.Collator;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.OsmAndCollator;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayGroup;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItemType;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.OsmandBaseExpandableListAdapter;
import net.osmand.plus.base.PointImageDrawable;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.myplaces.DeletePointsTask;
import net.osmand.plus.myplaces.DeletePointsTask.OnPointsDeleteListener;
import net.osmand.plus.myplaces.EditTrackGroupDialogFragment;
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
import net.osmand.util.Algorithms;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
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.Map.Entry;
import java.util.Set;
public class TrackPointsCard extends BaseCard implements OnChildClickListener, OnPointsDeleteListener {
public static final int ADD_WAYPOINT_INDEX = 0;
public static final int DELETE_WAYPOINTS_INDEX = 1;
private final TrackDisplayHelper displayHelper;
private final GpxDisplayItemType[] filterTypes = new GpxDisplayItemType[] {GpxDisplayItemType.TRACK_POINTS, GpxDisplayItemType.TRACK_ROUTE_POINTS};
private final Set<Integer> selectedGroups = new LinkedHashSet<>();
private final LinkedHashMap<GpxDisplayItemType, Set<GpxDisplayItem>> selectedItems = new LinkedHashMap<>();
private boolean selectionMode;
private final PointGPXAdapter adapter;
private ExpandableListView listView;
public TrackPointsCard(@NonNull MapActivity mapActivity, @NonNull TrackDisplayHelper displayHelper) {
super(mapActivity);
this.displayHelper = displayHelper;
adapter = new PointGPXAdapter();
}
public boolean isSelectionMode() {
return selectionMode;
}
public void setSelectionMode(boolean selectionMode) {
this.selectionMode = selectionMode;
adapter.notifyDataSetInvalidated();
}
@Override
public int getCardLayoutId() {
return R.layout.track_points_card;
}
@Override
protected void updateContent() {
listView = view.findViewById(android.R.id.list);
listView.setOnChildClickListener(this);
adapter.setFilterResults(null);
adapter.synchronizeGroups(getOriginalGroups());
if (listView.getAdapter() == null) {
listView.setAdapter(adapter);
}
if (!adapter.isEmpty() && listView.getFooterViewsCount() == 0) {
LayoutInflater inflater = UiUtilities.getInflater(mapActivity, nightMode);
listView.addFooterView(inflater.inflate(R.layout.list_shadow_footer, listView, false));
addActions(inflater);
}
expandAllGroups();
}
private void addActions(LayoutInflater inflater) {
View view = inflater.inflate(R.layout.preference_category_with_descr, listView, false);
TextView title = view.findViewById(android.R.id.title);
title.setText(R.string.shared_string_actions);
AndroidUiHelper.updateVisibility(view.findViewById(android.R.id.icon), false);
AndroidUiHelper.updateVisibility(view.findViewById(android.R.id.summary), false);
listView.addFooterView(view);
addWaypointAction(inflater);
deleteWaypointAction(inflater);
}
private void addWaypointAction(LayoutInflater inflater) {
View view = inflater.inflate(R.layout.preference_button, listView, false);
TextView addWaypointTitle = view.findViewById(android.R.id.title);
ImageView addWaypointIcon = view.findViewById(android.R.id.icon);
addWaypointTitle.setText(R.string.add_waypoint);
addWaypointIcon.setImageDrawable(getContentIcon(R.drawable.ic_action_name_field));
AndroidUiHelper.updateVisibility(view.findViewById(R.id.divider), true);
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
CardListener listener = getListener();
if (listener != null) {
listener.onCardButtonPressed(TrackPointsCard.this, ADD_WAYPOINT_INDEX);
}
}
});
listView.addFooterView(view);
}
private void deleteWaypointAction(LayoutInflater inflater) {
View view = inflater.inflate(R.layout.preference_button, listView, false);
TextView deleteWaypointsTitle = view.findViewById(android.R.id.title);
ImageView deleteWaypointsIcon = view.findViewById(android.R.id.icon);
deleteWaypointsTitle.setText(R.string.delete_waypoints);
deleteWaypointsIcon.setImageDrawable(getColoredIcon(R.drawable.ic_action_delete_dark, R.color.color_osm_edit_delete));
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
CardListener listener = getListener();
if (listener != null) {
listener.onCardButtonPressed(TrackPointsCard.this, DELETE_WAYPOINTS_INDEX);
}
}
});
listView.addFooterView(view);
}
private void expandAllGroups() {
for (int i = 0; i < adapter.getGroupCount(); i++) {
listView.expandGroup(i);
}
}
private List<GpxDisplayGroup> getOriginalGroups() {
return displayHelper.getOriginalGroups(filterTypes);
}
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
return true;
}
public void deleteItemsAction() {
int size = getSelectedItemsCount();
if (size > 0) {
AlertDialog.Builder b = new AlertDialog.Builder(mapActivity);
b.setMessage(app.getString(R.string.points_delete_multiple, size));
b.setPositiveButton(R.string.shared_string_delete, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
deleteItems();
setSelectionMode(false);
adapter.notifyDataSetInvalidated();
}
});
b.setNegativeButton(R.string.shared_string_cancel, null);
b.show();
}
}
private void deleteItems() {
new DeletePointsTask(app, displayHelper.getGpx(), getSelectedItems(), this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private Set<GpxDisplayItem> getSelectedItems() {
Set<GpxDisplayItem> result = new LinkedHashSet<>();
for (Set<GpxDisplayItem> set : selectedItems.values()) {
if (set != null) {
result.addAll(set);
}
}
return result;
}
private void updateSelectionMode() {
int size = getSelectedItemsCount();
app.showToastMessage(size + " " + app.getString(R.string.shared_string_selected_lowercase));
}
private int getSelectedItemsCount() {
int count = 0;
for (Set<GpxDisplayItem> set : selectedItems.values()) {
if (set != null) {
count += set.size();
}
}
return count;
}
@Override
public void onPointsDeletionStarted() {
}
@Override
public void onPointsDeleted() {
selectedItems.clear();
selectedGroups.clear();
adapter.synchronizeGroups(getOriginalGroups());
}
public void filter(String text) {
adapter.getFilter().filter(text);
}
private class PointGPXAdapter extends OsmandBaseExpandableListAdapter implements Filterable {
private final List<GpxDisplayGroup> groups = new ArrayList<>();
private final Map<GpxDisplayGroup, List<GpxDisplayItem>> itemGroups = new LinkedHashMap<>();
private final Comparator<String> comparator;
private Filter pointsFilter;
private Set<?> filteredItems;
PointGPXAdapter() {
final Collator collator = OsmAndCollator.primaryCollator();
comparator = new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return collator.compare(s1, s2);
}
};
}
public void synchronizeGroups(@NonNull List<GpxDisplayGroup> displayGroups) {
groups.clear();
itemGroups.clear();
Set<?> filtered = filteredItems;
Collections.sort(displayGroups, new Comparator<GpxDisplayGroup>() {
@Override
public int compare(GpxDisplayGroup g1, GpxDisplayGroup g2) {
int i1 = g1.getType().ordinal();
int i2 = g2.getType().ordinal();
return i1 < i2 ? -1 : (i1 == i2 ? 0 : 1);
}
});
List<GpxDisplayGroup> trackPointsGroups = new ArrayList<>();
List<GpxDisplayGroup> routePointsGroups = new ArrayList<>();
for (GpxDisplayGroup group : displayGroups) {
if (group.getType() == GpxDisplayItemType.TRACK_POINTS) {
trackPointsGroups.add(group);
} else if (group.getType() == GpxDisplayItemType.TRACK_ROUTE_POINTS) {
routePointsGroups.add(group);
}
}
processDisplayGroups(trackPointsGroups, filtered);
processDisplayGroups(routePointsGroups, filtered);
notifyDataSetChanged();
}
private void processDisplayGroups(List<GpxDisplayGroup> displayGroups, Set<?> filteredItems) {
for (int i = 0; i < displayGroups.size(); i++) {
GpxDisplayGroup group = displayGroups.get(i);
if (group.getModifiableList().isEmpty()) {
continue;
}
Map<String, List<GpxDisplayItem>> itemsMap = collectItemsByCategory(group, i);
if (filteredItems != null) {
itemsMap = filterItems(itemsMap, filteredItems);
}
if (!Algorithms.isEmpty(itemsMap)) {
setCollectedItems(group, itemsMap);
}
}
}
private Map<String, List<GpxDisplayItem>> collectItemsByCategory(GpxDisplayGroup group, int index) {
Map<String, List<GpxDisplayItem>> itemsMap = new HashMap<>();
for (GpxDisplayItem item : group.getModifiableList()) {
String category;
if (item.locationStart != null) {
if (group.getType() == GpxDisplayItemType.TRACK_POINTS) {
category = item.locationStart.category;
if (Algorithms.isEmpty(category)) {
category = "";
}
} else {
category = app.getString(R.string.route_points) + " " + (index + 1);
}
} else {
category = "";
}
List<GpxDisplayItem> items = itemsMap.get(category);
if (items == null) {
items = new ArrayList<>();
itemsMap.put(category, items);
}
items.add(item);
}
return itemsMap;
}
private Map<String, List<GpxDisplayItem>> filterItems(Map<String, List<GpxDisplayItem>> itemsMap, Set<?> filteredItems) {
Map<String, List<GpxDisplayItem>> itemsMapFiltered = new HashMap<>();
for (Entry<String, List<GpxDisplayItem>> e : itemsMap.entrySet()) {
String category = e.getKey();
List<GpxDisplayItem> items = e.getValue();
if (filteredItems.contains(category)) {
itemsMapFiltered.put(category, items);
} else {
for (GpxDisplayItem i : items) {
if (filteredItems.contains(i)) {
List<GpxDisplayItem> itemsFiltered = itemsMapFiltered.get(category);
if (itemsFiltered == null) {
itemsFiltered = new ArrayList<>();
itemsMapFiltered.put(category, itemsFiltered);
}
itemsFiltered.add(i);
}
}
}
}
return itemsMapFiltered;
}
private void setCollectedItems(GpxDisplayGroup group, Map<String, List<GpxDisplayItem>> itemsMap) {
List<String> categories = new ArrayList<>(itemsMap.keySet());
Collections.sort(categories, comparator);
for (String category : categories) {
List<GpxDisplayItem> values = itemsMap.get(category);
GpxDisplayGroup headerGroup = group.cloneInstance();
headerGroup.setName(category);
for (GpxDisplayItem i : values) {
if (i.locationStart != null && i.locationStart.getColor() != 0) {
headerGroup.setColor(i.locationStart.getColor(group.getColor()));
break;
}
}
List<GpxDisplayItem> headerGroupItems = headerGroup.getModifiableList();
headerGroupItems.clear();
headerGroupItems.addAll(values);
itemGroups.put(headerGroup, values);
this.groups.add(headerGroup);
}
}
@Override
public int getGroupCount() {
return groups.size();
}
@Override
public GpxDisplayGroup getGroup(int groupPosition) {
return groups.get(groupPosition);
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public int getChildrenCount(int groupPosition) {
return itemGroups.get(groups.get(groupPosition)).size();
}
@Override
public GpxDisplayItem getChild(int groupPosition, int childPosition) {
return itemGroups.get(groups.get(groupPosition)).get(childPosition);
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return groupPosition * 10000 + childPosition;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
final GpxDisplayGroup group = getGroup(groupPosition);
View row = convertView;
if (row == null) {
LayoutInflater inflater = LayoutInflater.from(view.getContext());
row = inflater.inflate(R.layout.wpt_list_item, parent, false);
}
row.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listView.isGroupExpanded(groupPosition)) {
listView.collapseGroup(groupPosition);
} else {
listView.expandGroup(groupPosition);
}
}
});
String categoryName = group.getName();
if (TextUtils.isEmpty(categoryName)) {
categoryName = app.getString(R.string.shared_string_gpx_points);
}
SpannableStringBuilder text = new SpannableStringBuilder(categoryName)
.append(" ")
.append(String.valueOf(getChildrenCount(groupPosition)));
text.setSpan(new ForegroundColorSpan(AndroidUtils.getColorFromAttr(view.getContext(), R.attr.wikivoyage_primary_text_color)),
0, categoryName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text.setSpan(new ForegroundColorSpan(ContextCompat.getColor(app, R.color.wikivoyage_secondary_text)),
categoryName.length() + 1, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
TextView title = row.findViewById(R.id.label);
title.setText(text);
ImageView icon = row.findViewById(R.id.icon);
icon.setImageDrawable(getContentIcon(R.drawable.ic_action_folder));
boolean expanded = listView.isGroupExpanded(groupPosition);
ImageView expandImage = row.findViewById(R.id.expand_image);
expandImage.setImageDrawable(getContentIcon(expanded ? R.drawable.ic_action_arrow_up : R.drawable.ic_action_arrow_down));
final CheckBox checkBox = (CheckBox) row.findViewById(R.id.toggle_item);
if (selectionMode) {
checkBox.setChecked(selectedGroups.contains(groupPosition));
checkBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
List<GpxDisplayItem> items = itemGroups.get(group);
setGroupSelection(items, groupPosition, checkBox.isChecked());
adapter.notifyDataSetInvalidated();
updateSelectionMode();
}
});
AndroidUiHelper.updateVisibility(checkBox, true);
} else {
AndroidUiHelper.updateVisibility(checkBox, false);
}
ImageView options = (ImageView) row.findViewById(R.id.options);
options.setImageDrawable(getContentIcon(R.drawable.ic_overflow_menu_white));
options.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EditTrackGroupDialogFragment.showInstance(mapActivity.getSupportFragmentManager(),
group, mapActivity.getTrackMenuFragment());
}
});
AndroidUiHelper.updateVisibility(expandImage, true);
AndroidUiHelper.updateVisibility(row.findViewById(R.id.divider), true);
AndroidUiHelper.updateVisibility(row.findViewById(R.id.description), false);
AndroidUiHelper.updateVisibility(row.findViewById(R.id.list_divider), false);
AndroidUiHelper.updateVisibility(row.findViewById(R.id.group_divider), true);
return row;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
View row = convertView;
if (row == null) {
LayoutInflater inflater = LayoutInflater.from(view.getContext());
row = inflater.inflate(R.layout.wpt_list_item, parent, false);
}
final GpxDisplayGroup group = getGroup(groupPosition);
final GpxDisplayItem gpxItem = getChild(groupPosition, childPosition);
TextView title = row.findViewById(R.id.label);
title.setText(gpxItem.name);
TextView description = row.findViewById(R.id.description);
if (!Algorithms.isEmpty(gpxItem.description)) {
description.setText(gpxItem.description);
AndroidUiHelper.updateVisibility(description, true);
} else {
AndroidUiHelper.updateVisibility(description, false);
}
final CheckBox checkBox = (CheckBox) row.findViewById(R.id.toggle_item);
if (selectionMode) {
checkBox.setVisibility(View.VISIBLE);
checkBox.setChecked(selectedItems.get(group.getType()) != null && selectedItems.get(group.getType()).contains(gpxItem));
checkBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (checkBox.isChecked()) {
Set<GpxDisplayItem> set = selectedItems.get(group.getType());
if (set != null) {
set.add(gpxItem);
} else {
set = new LinkedHashSet<>();
set.add(gpxItem);
selectedItems.put(group.getType(), set);
}
} else {
Set<GpxDisplayItem> set = selectedItems.get(group.getType());
if (set != null) {
set.remove(gpxItem);
}
}
updateSelectionMode();
}
});
AndroidUiHelper.updateVisibility(checkBox, true);
AndroidUiHelper.updateVisibility(row.findViewById(R.id.icon), false);
} else {
ImageView icon = row.findViewById(R.id.icon);
if (GpxDisplayItemType.TRACK_POINTS == group.getType()) {
WptPt wpt = gpxItem.locationStart;
int groupColor = wpt.getColor(group.getColor());
if (groupColor == 0) {
groupColor = ContextCompat.getColor(app, R.color.gpx_color_point);
}
icon.setImageDrawable(PointImageDrawable.getFromWpt(app, groupColor, false, wpt));
} else {
icon.setImageDrawable(getContentIcon(R.drawable.ic_action_marker_dark));
}
AndroidUiHelper.updateVisibility(icon, true);
AndroidUiHelper.updateVisibility(checkBox, false);
}
AndroidUiHelper.updateVisibility(row.findViewById(R.id.divider), false);
AndroidUiHelper.updateVisibility(row.findViewById(R.id.options), false);
AndroidUiHelper.updateVisibility(row.findViewById(R.id.list_divider), true);
return row;
}
private void setGroupSelection(List<GpxDisplayItem> items, int groupPosition, boolean select) {
GpxDisplayGroup group = groups.get(groupPosition);
if (select) {
selectedGroups.add(groupPosition);
if (items != null) {
Set<GpxDisplayItem> set = selectedItems.get(group.getType());
if (set != null) {
set.addAll(items);
} else {
set = new LinkedHashSet<>(items);
selectedItems.put(group.getType(), set);
}
}
} else {
selectedGroups.remove(groupPosition);
selectedItems.remove(group.getType());
}
}
@Override
public Filter getFilter() {
if (pointsFilter == null) {
pointsFilter = new PointsFilter();
}
return pointsFilter;
}
public void setFilterResults(Set<?> values) {
this.filteredItems = values;
}
}
public class PointsFilter extends Filter {
@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();
List<GpxDisplayGroup> groups = getOriginalGroups();
if (groups != null) {
for (GpxDisplayGroup g : groups) {
for (GpxDisplayItem i : g.getModifiableList()) {
if (i.name.toLowerCase().contains(cs)) {
filter.add(i);
} else if (i.locationStart != null && !TextUtils.isEmpty(i.locationStart.category)
&& i.locationStart.category.toLowerCase().contains(cs)) {
filter.add(i.locationStart.category);
}
}
}
}
results.values = filter;
results.count = filter.size();
}
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
synchronized (adapter) {
adapter.setFilterResults((Set<?>) results.values);
List<GpxDisplayGroup> groups = getOriginalGroups();
if (groups != null) {
adapter.synchronizeGroups(groups);
}
}
adapter.notifyDataSetChanged();
expandAllGroups();
}
}
}

View file

@ -6,19 +6,20 @@ import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
import net.osmand.data.QuadRect;
import net.osmand.data.RotatedTileBox;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.TrackActivity;
import net.osmand.plus.mapcontextmenu.MapContextMenu;
import net.osmand.plus.mapcontextmenu.editors.RtePtEditor;
import net.osmand.plus.mapcontextmenu.editors.WptPtEditor;
import net.osmand.plus.mapcontextmenu.editors.WptPtEditor.OnDismissListener;
import net.osmand.plus.track.TrackMenuFragment;
import net.osmand.plus.views.layers.ContextMenuLayer;
public class AddGpxPointBottomSheetHelper implements OnDismissListener {
@ -73,7 +74,7 @@ public class AddGpxPointBottomSheetHelper implements OnDismissListener {
public void onClick(View v) {
hide();
contextMenuLayer.cancelAddGpxPoint();
openTrackActivity();
onClose();
}
});
}
@ -140,7 +141,16 @@ public class AddGpxPointBottomSheetHelper implements OnDismissListener {
if (contextMenu.isVisible() && contextMenu.isClosable()) {
contextMenu.close();
}
openTrackActivity();
onClose();
}
private void onClose() {
TrackMenuFragment fragment = mapActivity.getTrackMenuFragment();
if (fragment != null) {
fragment.show();
} else {
openTrackActivity();
}
}
private void openTrackActivity() {

View file

@ -574,7 +574,6 @@ public class ContextMenuLayer extends OsmandMapLayer {
public void cancelAddGpxPoint() {
cancelApplyingNewMarkerPosition = true;
quitAddGpxPoint();
activity.getContextMenu().show();
applyingMarkerLatLon = null;
}

View file

@ -516,7 +516,7 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
for (WptPt wpt : getListStarPoints(g)) {
if (wpt.lat >= latLonBounds.bottom && wpt.lat <= latLonBounds.top
&& wpt.lon >= latLonBounds.left && wpt.lon <= latLonBounds.right
&& wpt != contextMenuLayer.getMoveableObject()) {
&& wpt != contextMenuLayer.getMoveableObject() && !isPointHidden(g, wpt)) {
pointFileMap.put(wpt, g);
MapMarker marker = null;
if (synced) {
@ -777,6 +777,14 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
return g.getGpxFile().getPoints();
}
private boolean isPointHidden(SelectedGpxFile selectedGpxFile, WptPt point) {
if (!Algorithms.isEmpty(selectedGpxFile.getHiddenGroups())) {
return selectedGpxFile.getHiddenGroups().contains(point.category);
} else {
return false;
}
}
private boolean calculateBelongs(int ex, int ey, int objx, int objy, int radius) {
return (Math.abs(objx - ex) <= radius && Math.abs(objy - ey) <= radius);
}
@ -790,6 +798,9 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
List<WptPt> pts = getListStarPoints(g);
// int fcolor = g.getColor() == 0 ? clr : g.getColor();
for (WptPt n : pts) {
if (isPointHidden(g, n)) {
continue;
}
int x = (int) tb.getPixXFromLatLon(n.lat, n.lon);
int y = (int) tb.getPixYFromLatLon(n.lat, n.lon);
if (calculateBelongs(ex, ey, x, y, r)) {