Merge pull request #10389 from osmandapp/RtlConfigureScreenPopUp

Fix "Configure screen – menu RTL"
This commit is contained in:
Vitaliy 2020-12-14 00:32:57 +02:00 committed by GitHub
commit 85ff622dc8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 531 additions and 364 deletions

View file

@ -12,13 +12,13 @@
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/content_padding_half"
android:layout_marginStart="@dimen/content_padding_half"
tools:src="@drawable/ic_action_info_dark"
android:tint="?attr/primary_icon_color"/>
tools:src="@drawable/ic_action_info_dark" />
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="?android:textColorPrimary"
android:layout_gravity="center_vertical"
android:paddingLeft="@dimen/content_padding"
@ -30,4 +30,14 @@
android:textSize="@dimen/default_list_text_size"
tools:text="Title" />
<androidx.appcompat.widget.AppCompatRadioButton
android:id="@+id/radio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:focusable="false"
android:clickable="false" />
</LinearLayout>

View file

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group
android:id="@+id/single_selection_group"
android:orderInCategory="1"
android:checkableBehavior="single"
android:menuCategory="alternative"
android:visible="false">
</group>
<group
android:id="@+id/button_group"
android:orderInCategory="2"
android:checkableBehavior="none"
android:menuCategory="container">
<item
android:id="@+id/action_show"
android:icon="@drawable/ic_action_view"
android:title="@string/shared_string_show"/>
<item
android:id="@+id/action_hide"
android:icon="@drawable/ic_action_hide"
android:title="@string/shared_string_hide"/>
<item
android:id="@+id/action_collapse"
android:icon="@drawable/ic_action_widget_collapse"
android:title="@string/shared_string_collapse"/>
</group>
</menu>

View file

@ -1,103 +0,0 @@
package net.osmand.plus;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.osmand.AndroidUtils;
import static net.osmand.plus.SimplePopUpMenuItemAdapter.SimplePopUpMenuItem;
import java.util.List;
public class SimplePopUpMenuItemAdapter
extends ArrayAdapter<SimplePopUpMenuItem> {
private List<SimplePopUpMenuItem> items;
public SimplePopUpMenuItemAdapter(@NonNull Context context, int resource,
List<SimplePopUpMenuItem> items) {
super(context, resource);
this.items = items;
}
@Override
public int getCount() {
return items.size();
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(getContext());
if (convertView == null) {
convertView = inflater.inflate(R.layout.popup_menu_item, parent, false);
}
SimplePopUpMenuItem item = getItem(position);
if (item != null) {
TextView tvTitle = convertView.findViewById(R.id.title);
tvTitle.setText(item.title);
ImageView ivIcon = convertView.findViewById(R.id.icon);
Drawable icon = item.icon;
if (icon != null) {
ivIcon.setImageDrawable(icon);
} else {
ivIcon.setVisibility(View.GONE);
}
if (item.selected) {
convertView.setBackgroundColor(UiUtilities.getColorWithAlpha(
AndroidUtils.getColorFromAttr(getContext(), R.attr.active_color_basic), 0.1f));
}
}
return convertView;
}
@Nullable
@Override
public SimplePopUpMenuItem getItem(int position) {
return items.get(position);
}
public static class SimplePopUpMenuItem {
private CharSequence title;
private Drawable icon;
private View.OnClickListener onClickListener;
boolean selected;
public SimplePopUpMenuItem(CharSequence title, Drawable icon) {
this.title = title;
this.icon = icon;
}
public SimplePopUpMenuItem(CharSequence title, Drawable icon, View.OnClickListener onClickListener) {
this(title, icon);
this.onClickListener = onClickListener;
}
public SimplePopUpMenuItem(CharSequence title, Drawable icon, View.OnClickListener onClickListener,
boolean selected) {
this(title, icon, onClickListener);
this.selected = selected;
}
public CharSequence getTitle() {
return title;
}
public Drawable getIcon() {
return icon;
}
public View.OnClickListener getOnClickListener() {
return onClickListener;
}
}
}

View file

@ -21,7 +21,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
@ -34,7 +33,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.ListPopupWindow;
import androidx.appcompat.widget.SwitchCompat;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
@ -60,13 +58,8 @@ import net.osmand.plus.widgets.style.CustomTypefaceSpan;
import org.apache.commons.logging.Log;
import java.util.ArrayList;
import java.util.List;
import gnu.trove.map.hash.TLongObjectHashMap;
import static net.osmand.plus.SimplePopUpMenuItemAdapter.SimplePopUpMenuItem;
public class UiUtilities {
private static final Log LOG = PlatformUtil.getLog(UiUtilities.class);
@ -768,59 +761,4 @@ public class UiUtilities {
}
return spannable;
}
public static ListPopupWindow createListPopupWindow(Context themedCtx,
View v, int minWidth,
List<SimplePopUpMenuItem> items,
final AdapterView.OnItemClickListener listener) {
int contentPadding = themedCtx.getResources().getDimensionPixelSize(R.dimen.content_padding);
int contentPaddingHalf = themedCtx.getResources().getDimensionPixelSize(R.dimen.content_padding_half);
int defaultListTextSize = themedCtx.getResources().getDimensionPixelSize(R.dimen.default_list_text_size);
int standardIconSize = themedCtx.getResources().getDimensionPixelSize(R.dimen.standard_icon_size);
boolean hasIcon = false;
List<String> titles = new ArrayList<>();
for (SimplePopUpMenuItem item : items) {
titles.add(String.valueOf(item.getTitle()));
hasIcon = hasIcon || item.getIcon() != null;
}
float itemWidth = AndroidUtils.getTextMaxWidth(defaultListTextSize, titles) + contentPadding * 2;
float iconPartWidth = hasIcon ? standardIconSize + contentPaddingHalf : 0;
int totalWidth = (int) (Math.max(itemWidth, minWidth) + iconPartWidth);
SimplePopUpMenuItemAdapter adapter =
new SimplePopUpMenuItemAdapter(themedCtx, R.layout.popup_menu_item, items);
final ListPopupWindow listPopupWindow = new ListPopupWindow(themedCtx);
listPopupWindow.setAnchorView(v);
listPopupWindow.setContentWidth((int) (totalWidth));
listPopupWindow.setDropDownGravity(Gravity.END | Gravity.TOP);
listPopupWindow.setVerticalOffset(-v.getHeight() + contentPaddingHalf);
listPopupWindow.setModal(true);
listPopupWindow.setAdapter(adapter);
listPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (listener != null) {
listener.onItemClick(parent, view, position, id);
}
listPopupWindow.dismiss();
}
});
return listPopupWindow;
}
public static void showPopUpMenu(View v, final List<SimplePopUpMenuItemAdapter.SimplePopUpMenuItem> items) {
UiUtilities.createListPopupWindow(
v.getContext(), v, v.getWidth(), items, new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position < items.size()) {
View.OnClickListener listener = items.get(position).getOnClickListener();
if (listener != null) {
listener.onClick(view);
}
}
}
}).show();
}
}

View file

@ -4,6 +4,7 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
@ -47,6 +48,8 @@ import net.osmand.plus.helpers.GpxUiHelper.OrderedLineDataSet;
import net.osmand.plus.views.layers.GPXLayer;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarController;
import net.osmand.plus.widgets.popup.PopUpMenuHelper;
import net.osmand.plus.widgets.popup.PopUpMenuItem;
import net.osmand.util.MapUtils;
import java.util.ArrayList;
@ -54,8 +57,6 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static net.osmand.plus.SimplePopUpMenuItemAdapter.SimplePopUpMenuItem;
public class TrackDetailsMenu {
private static final int MAX_DISTANCE_LOCATION_PROJECTION = 20; // in meters
@ -773,22 +774,26 @@ public class TrackDetailsMenu {
yAxis.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Context themedContext = UiUtilities.getThemedContext(v.getContext(), nightMode);
List<SimplePopUpMenuItem> items = new ArrayList<>();
List<PopUpMenuItem> items = new ArrayList<>();
for (GPXDataSetType[] types : availableTypes) {
items.add(new SimplePopUpMenuItem(
GPXDataSetType.getName(app, types),
GPXDataSetType.getImageDrawable(app, types)));
String title = GPXDataSetType.getName(app, types);
Drawable icon = GPXDataSetType.getImageDrawable(app, types);
items.add(new PopUpMenuItem.Builder(app)
.setTitle(title)
.setIcon(icon)
.create());
}
UiUtilities.createListPopupWindow(
themedContext, v, v.getWidth(), items, new AdapterView.OnItemClickListener() {
AdapterView.OnItemClickListener listener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
GpxDisplayItem gpxItem = getGpxItem();
gpxItem.chartTypes = availableTypes.get(position);
update();
}
}).show();
};
new PopUpMenuHelper.Builder(v, items, nightMode)
.setListener(listener)
.show();
}
});
yAxisArrow.setVisibility(View.VISIBLE);
@ -816,25 +821,26 @@ public class TrackDetailsMenu {
xAxis.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Context themedContext = UiUtilities.getThemedContext(v.getContext(), nightMode);
List<SimplePopUpMenuItem> items = new ArrayList<>();
List<PopUpMenuItem> items = new ArrayList<>();
for (GPXDataSetAxisType type : GPXDataSetAxisType.values()) {
items.add(new SimplePopUpMenuItem(
app.getString(type.getStringId()), type.getImageDrawable(app)));
items.add(new PopUpMenuItem.Builder(app)
.setTitleId(type.getStringId())
.setIcon(type.getImageDrawable(app))
.create());
}
UiUtilities.createListPopupWindow(themedContext,
v, v.getWidth(), items, new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
GpxDisplayItem gpxItem = getGpxItem();
if (gpxItem != null) {
gpxItem.chartAxisType = GPXDataSetAxisType.values()[position];
gpxItem.chartHighlightPos = -1;
gpxItem.chartMatrix = null;
update();
}
}
}).show();
new PopUpMenuHelper.Builder(v, items, nightMode)
.setListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
GpxDisplayItem gpxItem = getGpxItem();
if (gpxItem != null) {
gpxItem.chartAxisType = GPXDataSetAxisType.values()[position];
gpxItem.chartHighlightPos = -1;
gpxItem.chartMatrix = null;
update();
}
}
}).show();
}
});
xAxisArrow.setVisibility(View.VISIBLE);

View file

@ -20,7 +20,6 @@ import net.osmand.IndexConstants;
import net.osmand.OsmAndCollator;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.helpers.GpxTrackAdapter;
@ -30,6 +29,8 @@ import net.osmand.plus.helpers.enums.TracksSortByMode;
import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter;
import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter.HorizontalSelectionAdapterListener;
import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter.HorizontalSelectionItem;
import net.osmand.plus.widgets.popup.PopUpMenuHelper;
import net.osmand.plus.widgets.popup.PopUpMenuItem;
import java.io.File;
import java.util.ArrayList;
@ -39,7 +40,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static net.osmand.plus.SimplePopUpMenuItemAdapter.SimplePopUpMenuItem;
import static net.osmand.plus.helpers.GpxUiHelper.getSortedGPXFilesInfo;
import static net.osmand.util.Algorithms.collectDirs;
@ -118,12 +118,12 @@ public class SelectFileBottomSheet extends MenuBottomSheetDialogFragment {
sortButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final List<SimplePopUpMenuItem> items = new ArrayList<>();
final List<PopUpMenuItem> items = new ArrayList<>();
for (final TracksSortByMode mode : TracksSortByMode.values()) {
items.add(new SimplePopUpMenuItem(
getString(mode.getNameId()),
app.getUIUtilities().getThemedIcon(mode.getIconId()),
new View.OnClickListener() {
items.add(new PopUpMenuItem.Builder(app)
.setTitleId(mode.getNameId())
.setIcon(app.getUIUtilities().getThemedIcon(mode.getIconId()))
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sortByMode = mode;
@ -135,10 +135,12 @@ public class SelectFileBottomSheet extends MenuBottomSheetDialogFragment {
sortFileList();
adapter.notifyDataSetChanged();
}
}, sortByMode == mode
));
})
.setSelected(sortByMode == mode)
.create());
}
UiUtilities.showPopUpMenu(v, items);
new PopUpMenuHelper.Builder(v, items, nightMode)
.show();
}
});

View file

@ -23,7 +23,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
@ -71,7 +70,6 @@ import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.SimplePopUpMenuItemAdapter.SimplePopUpMenuItem;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.OsmandBaseExpandableListAdapter;
@ -86,6 +84,8 @@ import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
import net.osmand.plus.osmedit.OsmEditingPlugin;
import net.osmand.plus.osmedit.oauth.OsmOAuthHelper.OsmAuthorizationListener;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.widgets.popup.PopUpMenuItem;
import net.osmand.plus.widgets.popup.PopUpMenuHelper;
import java.io.File;
import java.text.DateFormat;
@ -576,13 +576,14 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
if (itemId == R.id.action_sort) {
Activity activity = getActivity();
if (activity != null) {
boolean nightMode = app.getSettings().isLightContent();
View menuSortItemView = getActivity().findViewById(R.id.action_sort);
final List<SimplePopUpMenuItem> items = new ArrayList<>();
final List<PopUpMenuItem> items = new ArrayList<>();
for (final TracksSortByMode mode : TracksSortByMode.values()) {
items.add(new SimplePopUpMenuItem(
getString(mode.getNameId()),
app.getUIUtilities().getThemedIcon(mode.getIconId()),
new View.OnClickListener() {
items.add(new PopUpMenuItem.Builder(app)
.setTitleId(mode.getNameId())
.setIcon(app.getUIUtilities().getThemedIcon(mode.getIconId()))
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
updateTracksSort(mode);
@ -590,10 +591,12 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
: R.color.active_buttons_and_links_text_dark;
item.setIcon(getIcon(mode.getIconId(), iconColorId));
}
}, sortByMode == mode
));
})
.setSelected(sortByMode == mode)
.create()
);
}
UiUtilities.showPopUpMenu(menuSortItemView, items);
new PopUpMenuHelper.Builder(menuSortItemView, items, nightMode).show();
}
}
return super.onOptionsItemSelected(item);
@ -1489,51 +1492,55 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
}
private void openPopUpMenu(View v, final GpxInfo gpxInfo) {
final List<SimplePopUpMenuItem> items = new ArrayList<>();
boolean nightMode = app.getSettings().isLightContent();
final List<PopUpMenuItem> items = new ArrayList<>();
UiUtilities iconsCache = getMyApplication().getUIUtilities();
items.add(new SimplePopUpMenuItem(
getString(R.string.shared_string_show_on_map),
iconsCache.getThemedIcon(R.drawable.ic_show_on_map),
new View.OnClickListener() {
items.add(new PopUpMenuItem.Builder(app)
.setTitleId(R.string.shared_string_show_on_map)
.setIcon(iconsCache.getThemedIcon(R.drawable.ic_show_on_map))
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showGpxOnMap(gpxInfo);
}
}
));
})
.create()
);
GPXTrackAnalysis analysis;
if ((analysis = getGpxTrackAnalysis(gpxInfo, app, null)) != null) {
if (analysis.totalDistance != 0 && !gpxInfo.currentlyRecordingTrack) {
items.add(new SimplePopUpMenuItem(
getString(R.string.analyze_on_map),
iconsCache.getThemedIcon(R.drawable.ic_action_info_dark),
new View.OnClickListener() {
items.add(new PopUpMenuItem.Builder(app)
.setTitleId(R.string.analyze_on_map)
.setIcon(iconsCache.getThemedIcon(R.drawable.ic_action_info_dark))
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new OpenGpxDetailsTask(gpxInfo).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
));
})
.create()
);
}
}
items.add(new SimplePopUpMenuItem(
getString(R.string.shared_string_move),
iconsCache.getThemedIcon(R.drawable.ic_action_folder_stroke),
new View.OnClickListener() {
items.add(new PopUpMenuItem.Builder(app)
.setTitleId(R.string.shared_string_move)
.setIcon(iconsCache.getThemedIcon(R.drawable.ic_action_folder_stroke))
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
moveGpx(gpxInfo);
}
}
));
})
.create()
);
items.add(new SimplePopUpMenuItem(
getString(R.string.shared_string_rename),
iconsCache.getThemedIcon(R.drawable.ic_action_edit_dark),
new View.OnClickListener() {
items.add(new PopUpMenuItem.Builder(app)
.setTitleId(R.string.shared_string_rename)
.setIcon(iconsCache.getThemedIcon(R.drawable.ic_action_edit_dark))
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FileUtils.renameFile(getActivity(), gpxInfo.file, new RenameCallback() {
@ -1544,14 +1551,15 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
}
});
}
}
));
})
.create()
);
Drawable shareIcon = iconsCache.getThemedIcon((R.drawable.ic_action_gshare_dark));
items.add(new SimplePopUpMenuItem(
getString(R.string.shared_string_share),
AndroidUtils.getDrawableForDirection(app, shareIcon),
new View.OnClickListener() {
items.add(new PopUpMenuItem.Builder(app)
.setTitleId(R.string.shared_string_share)
.setIcon(AndroidUtils.getDrawableForDirection(app, shareIcon))
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final Uri fileUri = AndroidUtils.getUriForFile(getMyApplication(), gpxInfo.file);
@ -1561,27 +1569,29 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(sendIntent);
}
}
));
})
.create()
);
final OsmEditingPlugin osmEditingPlugin = OsmandPlugin.getEnabledPlugin(OsmEditingPlugin.class);
if (osmEditingPlugin != null && osmEditingPlugin.isActive()) {
items.add(new SimplePopUpMenuItem(
getString(R.string.shared_string_export),
iconsCache.getThemedIcon(R.drawable.ic_action_export),
new View.OnClickListener() {
items.add(new PopUpMenuItem.Builder(app)
.setTitleId(R.string.shared_string_export)
.setIcon(iconsCache.getThemedIcon(R.drawable.ic_action_export))
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
osmEditingPlugin.sendGPXFiles(getActivity(), AvailableGPXFragment.this, gpxInfo);
}
}
));
})
.create()
);
}
items.add(new SimplePopUpMenuItem(
getString(R.string.shared_string_delete),
iconsCache.getThemedIcon(R.drawable.ic_action_delete_dark),
new View.OnClickListener() {
items.add(new PopUpMenuItem.Builder(app)
.setTitleId(R.string.shared_string_delete)
.setIcon(iconsCache.getThemedIcon(R.drawable.ic_action_delete_dark))
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
@ -1596,21 +1606,10 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
builder.setNegativeButton(R.string.shared_string_cancel, null);
builder.show();
}
}
));
UiUtilities.createListPopupWindow(
getContext(), v, v.getWidth(), items, new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position < items.size()) {
View.OnClickListener listener = items.get(position).getOnClickListener();
if (listener != null) {
listener.onClick(view);
}
}
}
}).show();
})
.create()
);
new PopUpMenuHelper.Builder(v, items, nightMode).show();
}
public class DeleteGpxTask extends AsyncTask<GpxInfo, GpxInfo, String> {

View file

@ -33,7 +33,6 @@ import net.osmand.data.RotatedTileBox;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.SimplePopUpMenuItemAdapter.SimplePopUpMenuItem;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.UiUtilities.DialogButtonType;
import net.osmand.plus.activities.MapActivity;
@ -64,6 +63,8 @@ import net.osmand.plus.routing.RouteProvider.GPXRouteParamsBuilder;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.views.layers.MapControlsLayer;
import net.osmand.plus.widgets.popup.PopUpMenuHelper;
import net.osmand.plus.widgets.popup.PopUpMenuItem;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
@ -613,11 +614,12 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca
sortButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
List<SimplePopUpMenuItem> items = new ArrayList<>();
List<PopUpMenuItem> items = new ArrayList<>();
for (final TracksSortByMode mode : TracksSortByMode.values()) {
items.add(new SimplePopUpMenuItem(getString(mode.getNameId()),
app.getUIUtilities().getThemedIcon(mode.getIconId()),
new View.OnClickListener() {
items.add(new PopUpMenuItem.Builder(app)
.setTitleId(mode.getNameId())
.setIcon(app.getUIUtilities().getThemedIcon(mode.getIconId()))
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sortByMode = mode;
@ -626,10 +628,12 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca
tracksCard.setSortByMode(mode);
}
}
}, sortByMode == mode
));
})
.setSelected(sortByMode == mode)
.create()
);
}
UiUtilities.showPopUpMenu(v, items);
new PopUpMenuHelper.Builder(v, items, isNightMode()).show();
}
});
}

View file

@ -1,9 +1,7 @@
package net.osmand.plus.views.mapwidgets;
import android.content.Context;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
@ -11,6 +9,7 @@ import android.widget.LinearLayout;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.core.content.ContextCompat;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.ContextMenuAdapter;
@ -29,12 +28,16 @@ import net.osmand.plus.views.layers.MapQuickActionLayer;
import net.osmand.plus.views.OsmandMapLayer.DrawSettings;
import net.osmand.plus.views.mapwidgets.widgets.TextInfoWidget;
import net.osmand.plus.views.mapwidgets.widgetstates.WidgetState;
import net.osmand.plus.widgets.IconPopupMenu;
import net.osmand.plus.widgets.popup.PopUpMenuItem;
import net.osmand.plus.widgets.popup.PopUpMenuHelper;
import net.osmand.plus.widgets.popup.PopUpMenuHelper.PopUpMenuWidthType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
@ -513,6 +516,7 @@ public class MapWidgetRegistry {
final String desc = mapActivity.getString(R.string.shared_string_collapse);
final boolean nightMode = app.getDaynightHelper().isNightModeForMapControls();
final int currentModeColorRes = mode.getIconColorInfo().getColor(nightMode);
final int currentModeColor = ContextCompat.getColor(app, currentModeColorRes);
ContextMenuItem.ItemBuilder itemBuilder = new ContextMenuItem.ItemBuilder()
.setIcon(r.getDrawableMenu())
.setSelected(selected)
@ -530,14 +534,8 @@ public class MapWidgetRegistry {
return false;
}
View textWrapper = view.findViewById(R.id.text_wrapper);
IconPopupMenu popup = new IconPopupMenu(view.getContext(), textWrapper);
MenuInflater inflater = popup.getMenuInflater();
final Menu menu = popup.getMenu();
inflater.inflate(R.menu.widget_visibility_menu, menu);
List<PopUpMenuItem> items = new ArrayList<>();
UiUtilities ic = app.getUIUtilities();
menu.findItem(R.id.action_show).setIcon(ic.getThemedIcon(R.drawable.ic_action_view));
menu.findItem(R.id.action_hide).setIcon(ic.getThemedIcon(R.drawable.ic_action_hide));
menu.findItem(R.id.action_collapse).setIcon(ic.getThemedIcon(R.drawable.ic_action_widget_collapse));
final int[] menuIconIds = r.getDrawableMenuIds();
final int[] menuTitleIds = r.getMessageIds();
@ -549,57 +547,77 @@ public class MapWidgetRegistry {
for (int i = 0; i < menuIconIds.length; i++) {
int iconId = menuIconIds[i];
int titleId = menuTitleIds[i];
int id = menuItemIds[i];
MenuItem menuItem = menu.add(R.id.single_selection_group, id, i, titleId)
.setChecked(id == checkedId);
menuItem.setIcon(menuItem.isChecked() && selected
? ic.getIcon(iconId, currentModeColorRes) : ic.getThemedIcon(iconId));
final int id = menuItemIds[i];
boolean isChecked = id == checkedId;
String title = app.getString(titleId);
Drawable icon = isChecked && selected ? ic.getIcon(iconId, currentModeColorRes) : ic.getThemedIcon(iconId);
items.add(new PopUpMenuItem.Builder(app)
.setTitle(title)
.setIcon(icon)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
r.changeState(id);
MapInfoLayer mil = mapActivity.getMapLayers().getMapInfoLayer();
if (mil != null) {
mil.recreateControls();
}
ContextMenuItem item = adapter.getItem(pos);
item.setIcon(r.getDrawableMenu());
if (r.getMessage() != null) {
item.setTitle(r.getMessage());
} else {
item.setTitle(mapActivity.getResources().getString(r.getMessageId()));
}
adapter.notifyDataSetChanged();
}
})
.showCompoundBtn(currentModeColor)
.setSelected(isChecked)
.create());
}
menu.setGroupCheckable(R.id.single_selection_group, true, true);
menu.setGroupVisible(R.id.single_selection_group, true);
}
popup.setOnMenuItemClickListener(
new IconPopupMenu.OnMenuItemClickListener() {
// show
items.add(new PopUpMenuItem.Builder(app)
.setTitleId(R.string.shared_string_show)
.setIcon(ic.getThemedIcon(R.drawable.ic_action_view))
.setOnClickListener(new View.OnClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
int i = menuItem.getItemId();
if (i == R.id.action_show) {
setVisibility(adapter, pos, true, false);
return true;
} else if (i == R.id.action_hide) {
setVisibility(adapter, pos, false, false);
return true;
} else if (i == R.id.action_collapse) {
setVisibility(adapter, pos, true, true);
return true;
} else {
if (menuItemIds != null) {
for (int menuItemId : menuItemIds) {
if (menuItem.getItemId() == menuItemId) {
r.changeState(menuItemId);
MapInfoLayer mil = mapActivity.getMapLayers().getMapInfoLayer();
if (mil != null) {
mil.recreateControls();
}
ContextMenuItem item = adapter.getItem(pos);
item.setIcon(r.getDrawableMenu());
if (r.getMessage() != null) {
item.setTitle(r.getMessage());
} else {
item.setTitle(mapActivity.getResources().getString(r.getMessageId()));
}
adapter.notifyDataSetChanged();
return true;
}
}
}
}
return false;
public void onClick(View v) {
setVisibility(adapter, pos, true, false);
}
});
popup.show();
})
.create());
// hide
items.add(new PopUpMenuItem.Builder(app)
.setTitleId(R.string.shared_string_hide)
.setIcon(ic.getThemedIcon(R.drawable.ic_action_hide))
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setVisibility(adapter, pos, false, false);
}
})
.create());
// collapse
items.add(new PopUpMenuItem.Builder(app)
.setTitleId(R.string.shared_string_collapse)
.setIcon(ic.getThemedIcon(R.drawable.ic_action_widget_collapse))
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setVisibility(adapter, pos, true, true);
}
})
.create());
new PopUpMenuHelper.Builder(textWrapper, items, nightMode)
.setWidthType(PopUpMenuWidthType.STANDARD)
.show();
return false;
}

View file

@ -0,0 +1,83 @@
package net.osmand.plus.widgets.popup;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.osmand.AndroidUtils;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import java.util.List;
public class PopUpMenuArrayAdapter extends ArrayAdapter<PopUpMenuItem> {
private List<PopUpMenuItem> items;
private boolean nightMode;
public PopUpMenuArrayAdapter(@NonNull Context context,
int resource,
List<PopUpMenuItem> items,
boolean nightMode) {
super(context, resource);
this.items = items;
this.nightMode = nightMode;
}
@Override
public int getCount() {
return items.size();
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(getContext());
if (convertView == null) {
convertView = inflater.inflate(R.layout.popup_menu_item, parent, false);
}
PopUpMenuItem item = getItem(position);
if (item != null) {
TextView tvTitle = convertView.findViewById(R.id.title);
tvTitle.setText(item.getTitle());
ImageView ivIcon = convertView.findViewById(R.id.icon);
Drawable icon = item.getIcon();
if (icon != null) {
ivIcon.setImageDrawable(icon);
} else {
ivIcon.setVisibility(View.GONE);
}
CompoundButton radio = convertView.findViewById(R.id.radio);
if (item.isShowCompoundBtn()) {
UiUtilities.setupCompoundButton(nightMode, item.getCompoundBtnColor(), radio);
radio.setVisibility(View.VISIBLE);
} else {
radio.setVisibility(View.GONE);
}
if (item.isSelected()) {
if (item.isShowCompoundBtn()) {
radio.setChecked(true);
} else {
convertView.setBackgroundColor(UiUtilities.getColorWithAlpha(
AndroidUtils.getColorFromAttr(getContext(), R.attr.active_color_basic), 0.1f));
}
}
}
return convertView;
}
@Nullable
@Override
public PopUpMenuItem getItem(int position) {
return items.get(position);
}
}

View file

@ -0,0 +1,138 @@
package net.osmand.plus.widgets.popup;
import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.widget.AdapterView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.ListPopupWindow;
import net.osmand.AndroidUtils;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import java.util.ArrayList;
import java.util.List;
public class PopUpMenuHelper {
private View anchorView;
private List<PopUpMenuItem> items;
private PopUpMenuWidthType widthType;
private AdapterView.OnItemClickListener listener;
private boolean nightMode;
private PopUpMenuHelper(@NonNull View anchorView,
@NonNull List<PopUpMenuItem> items,
PopUpMenuWidthType widthType,
AdapterView.OnItemClickListener listener,
boolean nightMode) {
this.anchorView = anchorView;
this.items = items;
this.widthType = widthType;
this.listener = listener;
this.nightMode = nightMode;
}
private void show() {
ListPopupWindow listPopupWindow = createPopUpWindow();
listPopupWindow.show();
}
private ListPopupWindow createPopUpWindow() {
Context ctx = UiUtilities.getThemedContext(anchorView.getContext(), nightMode);
int contentPadding = getDimensionPixelSize(ctx, R.dimen.content_padding);
int contentPaddingHalf = getDimensionPixelSize(ctx, R.dimen.content_padding_half);
int defaultListTextSize = getDimensionPixelSize(ctx, R.dimen.default_list_text_size);
int standardIconSize = getDimensionPixelSize(ctx, R.dimen.standard_icon_size);
boolean hasIcon = false;
List<String> titles = new ArrayList<>();
for (PopUpMenuItem item : items) {
titles.add(String.valueOf(item.getTitle()));
hasIcon = hasIcon || item.getIcon() != null;
}
float itemWidth = AndroidUtils.getTextMaxWidth(defaultListTextSize, titles) + contentPadding * 2;
float iconPartWidth = hasIcon ? standardIconSize + contentPaddingHalf : 0;
float compoundBtnWidth = contentPadding * 3;
int minWidth = widthType == PopUpMenuWidthType.AS_ANCHOR_VIEW ? anchorView.getWidth() : 0;
float additional;
if (widthType == PopUpMenuWidthType.STANDARD) {
additional = iconPartWidth + compoundBtnWidth;
} else {
additional = iconPartWidth;
}
int totalWidth =(int) (Math.max(itemWidth, minWidth) + additional);
PopUpMenuArrayAdapter adapter =
new PopUpMenuArrayAdapter(ctx, R.layout.popup_menu_item, items, nightMode);
final ListPopupWindow listPopupWindow = new ListPopupWindow(ctx);
listPopupWindow.setAnchorView(anchorView);
listPopupWindow.setContentWidth((int) (totalWidth));
listPopupWindow.setDropDownGravity(Gravity.START | Gravity.TOP);
listPopupWindow.setVerticalOffset(-anchorView.getHeight() + contentPaddingHalf);
listPopupWindow.setModal(true);
listPopupWindow.setAdapter(adapter);
listPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (listener != null) {
listener.onItemClick(parent, view, position, id);
}
listPopupWindow.dismiss();
}
});
return listPopupWindow;
}
private int getDimensionPixelSize(Context ctx, int dimensionResId) {
return ctx.getResources().getDimensionPixelSize(dimensionResId);
}
public enum PopUpMenuWidthType {
STANDARD,
AS_ANCHOR_VIEW
}
public static class Builder {
private View anchorView;
private List<PopUpMenuItem> items;
private AdapterView.OnItemClickListener listener;
private PopUpMenuWidthType widthType = PopUpMenuWidthType.AS_ANCHOR_VIEW;
private boolean nightMode;
public Builder(View anchorView, List<PopUpMenuItem> items, boolean nightMode) {
this.anchorView = anchorView;
this.items = items;
this.nightMode = nightMode;
}
public Builder setListener(AdapterView.OnItemClickListener listener) {
this.listener = listener;
return this;
}
public Builder setWidthType(@NonNull PopUpMenuWidthType widthType) {
this.widthType = widthType;
return this;
}
public void show() {
if (listener == null) {
listener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position < items.size()) {
View.OnClickListener listener = items.get(position).getOnClickListener();
if (listener != null) {
listener.onClick(view);
}
}
}
};
}
new PopUpMenuHelper(anchorView, items, widthType, listener, nightMode).show();
}
}
}

View file

@ -0,0 +1,100 @@
package net.osmand.plus.widgets.popup;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
import androidx.annotation.ColorInt;
public class PopUpMenuItem {
private CharSequence title;
private Drawable icon;
private View.OnClickListener onClickListener;
private boolean selected;
@ColorInt
private Integer compoundBtnColor;
private PopUpMenuItem(CharSequence title,
Drawable icon,
View.OnClickListener onClickListener,
boolean selected,
Integer compoundBtnColor) {
this.title = title;
this.icon = icon;
this.onClickListener = onClickListener;
this.selected = selected;
this.compoundBtnColor = compoundBtnColor;
}
public CharSequence getTitle() {
return title;
}
public Drawable getIcon() {
return icon;
}
public View.OnClickListener getOnClickListener() {
return onClickListener;
}
public boolean isShowCompoundBtn() {
return compoundBtnColor != null;
}
public Integer getCompoundBtnColor() {
return compoundBtnColor;
}
public boolean isSelected() {
return selected;
}
public static class Builder {
private Context ctx;
private CharSequence title;
private Drawable icon;
private View.OnClickListener onClickListener;
@ColorInt
private Integer compoundBtnColor;
private boolean selected;
public Builder(Context ctx) {
this.ctx = ctx;
}
public Builder setTitleId(int titleId) {
this.title = ctx.getString(titleId);
return this;
}
public Builder setTitle(CharSequence title) {
this.title = title;
return this;
}
public Builder setIcon(Drawable icon) {
this.icon = icon;
return this;
}
public Builder setOnClickListener(View.OnClickListener onClickListener) {
this.onClickListener = onClickListener;
return this;
}
public Builder showCompoundBtn(int compoundBtnColor) {
this.compoundBtnColor = compoundBtnColor;
return this;
}
public Builder setSelected(boolean selected) {
this.selected = selected;
return this;
}
public PopUpMenuItem create() {
return new PopUpMenuItem(title, icon, onClickListener, selected, compoundBtnColor);
}
}
}