Improve display of transport routes badges in context menu

This commit is contained in:
Chumva 2018-09-25 15:37:51 +03:00
parent cadc1fc57b
commit 4a6c5c28c2
5 changed files with 206 additions and 87 deletions

View file

@ -72,53 +72,73 @@
</LinearLayout>
<GridView
android:id="@+id/transport_stop_routes_grid"
<LinearLayout
android:id="@+id/transport_badges_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnWidth="@dimen/context_menu_transport_grid_item_width"
android:horizontalSpacing="@dimen/context_menu_transport_grid_spacing"
android:numColumns="auto_fit"
android:paddingBottom="@dimen/context_menu_transport_grid_spacing"
android:orientation="vertical"
android:paddingLeft="@dimen/context_menu_padding_margin_default"
android:paddingRight="@dimen/context_menu_padding_margin_default"
android:paddingTop="@dimen/context_menu_transport_padding_top"
android:verticalSpacing="@dimen/context_menu_transport_grid_spacing"
android:visibility="gone"/>
android:paddingRight="@dimen/context_menu_padding_margin_default">
<LinearLayout
android:id="@+id/nearby_routes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/context_menu_direction_margin"
android:layout_marginTop="@dimen/context_menu_padding_margin_tiny"
android:gravity="top"
android:orientation="horizontal"
android:paddingLeft="@dimen/context_menu_padding_margin_default"
android:paddingRight="@dimen/context_menu_padding_margin_default"
android:paddingTop="3dp">
<GridView
android:id="@+id/transport_stop_routes_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnWidth="@dimen/context_menu_transport_grid_item_width"
android:horizontalSpacing="@dimen/context_menu_transport_grid_spacing"
android:numColumns="auto_fit"
android:paddingBottom="@dimen/context_menu_transport_grid_spacing"
android:paddingTop="@dimen/context_menu_transport_padding_top"
android:verticalSpacing="@dimen/context_menu_transport_grid_spacing"
android:visibility="gone" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/nearby_routes_within_text_view"
android:id="@+id/local_routes_more_text_view"
style="@style/TextAppearance.ContextMenuSubtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/context_menu_padding_margin_small"
android:layout_marginRight="@dimen/context_menu_padding_margin_small"
android:text="@string/more_transport_on_stop_hint"
android:textSize="@dimen/default_sub_text_size"
osmand:typeface="@string/font_roboto_medium"/>
android:visibility="gone"
osmand:typeface="@string/font_roboto_medium" />
<GridView
android:id="@+id/transport_stop_nearby_routes_grid"
android:layout_width="match_parent"
<LinearLayout
android:id="@+id/nearby_routes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:columnWidth="@dimen/context_menu_transport_grid_item_width"
android:horizontalSpacing="@dimen/context_menu_transport_grid_spacing"
android:numColumns="auto_fit"
android:verticalSpacing="@dimen/context_menu_transport_grid_spacing"
android:visibility="gone"/>
android:layout_marginBottom="@dimen/context_menu_direction_margin"
android:layout_marginTop="@dimen/context_menu_padding_margin_tiny"
android:gravity="top"
android:orientation="horizontal"
android:paddingTop="3dp">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/nearby_routes_within_text_view"
style="@style/TextAppearance.ContextMenuSubtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/context_menu_padding_margin_small"
android:layout_marginRight="@dimen/context_menu_padding_margin_small"
android:textSize="@dimen/default_sub_text_size"
osmand:typeface="@string/font_roboto_medium" />
<GridView
android:id="@+id/transport_stop_nearby_routes_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:columnWidth="@dimen/context_menu_transport_grid_item_width"
android:horizontalSpacing="@dimen/context_menu_transport_grid_spacing"
android:numColumns="auto_fit"
android:verticalSpacing="@dimen/context_menu_transport_grid_spacing"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
<LinearLayout

View file

@ -11,6 +11,7 @@
Thx - Hardy
-->
<string name="more_transport_on_stop_hint">There is more transport on this stop.</string>
<string name="ask_for_location_permission">Please give OsmAnd permission for location to continue.</string>
<string name="thank_you_for_feedback">Thank you for feedback</string>
<string name="poi_cannot_be_found">Node or way cannot be found.</string>

View file

@ -344,6 +344,13 @@ public class AndroidUtils {
: ctx.getResources().getColor(R.color.secondary_text_light));
}
public static int getTextWidth(float textSize, String text) {
Paint paint = new Paint();
paint.setTextSize(textSize);
return (int) paint.measureText(text);
}
public static int dpToPx(Context ctx, float dp) {
Resources r = ctx.getResources();
return (int) TypedValue.applyDimension(

View file

@ -9,6 +9,7 @@ import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat;
@ -80,7 +81,7 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
public static final int CURRENT_Y_UNDEFINED = Integer.MAX_VALUE;
private static final int MAX_TRANSPORT_ROUTES_BADGES = 6;
private static final String TRANSPORT_BADGE_MORE_ITEM = "...";
private View view;
private InterceptorLinearLayout mainView;
@ -92,6 +93,13 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
private View topButtonContainer;
private LockableScrollView menuScrollView;
private LinearLayout nearbyRoutesLayout;
private LinearLayout routesBadgesContainer;
private GridView localTransportStopRoutesGrid;
private GridView nearbyTransportStopRoutesGrid;
private TextView nearbyRoutesWithinTv;
private TextView localRoutesMoreTv;
private View zoomButtonsView;
private ImageButton zoomInButtonView;
private ImageButton zoomOutButtonView;
@ -137,6 +145,8 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
private int screenOrientation;
private boolean created;
private boolean transportBadgesCreated;
private UpdateLocationViewCache updateLocationViewCache;
@Override
@ -495,32 +505,19 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
zoomButtonsView.setVisibility(View.GONE);
}
GridView localTransportStopRoutesGrid = (GridView) view.findViewById(R.id.transport_stop_routes_grid);
GridView nearbyTransportStopRoutesGrid = (GridView) view.findViewById(R.id.transport_stop_nearby_routes_grid);
TextView nearbRoutesWithinTv = (TextView) view.findViewById(R.id.nearby_routes_within_text_view);
LinearLayout nearbyRoutesLayout = (LinearLayout) view.findViewById(R.id.nearby_routes);
localTransportStopRoutesGrid = (GridView) view.findViewById(R.id.transport_stop_routes_grid);
nearbyTransportStopRoutesGrid = (GridView) view.findViewById(R.id.transport_stop_nearby_routes_grid);
nearbyRoutesWithinTv = (TextView) view.findViewById(R.id.nearby_routes_within_text_view);
localRoutesMoreTv = (TextView) view.findViewById(R.id.local_routes_more_text_view);
nearbyRoutesLayout = (LinearLayout) view.findViewById(R.id.nearby_routes);
routesBadgesContainer = (LinearLayout) view.findViewById(R.id.transport_badges_container);
List<TransportStopRoute> localTransportStopRoutes = menu.getLocalTransportStopRoutes();
List<TransportStopRoute> nearbyTransportStopRoutes = menu.getNearbyTransportStopRoutes();
if (nightMode) {
nearbRoutesWithinTv.setTextColor(ContextCompat.getColor(getContext(), R.color.ctx_menu_bottom_view_secondary_text_color_dark));
nearbyRoutesWithinTv.setTextColor(ContextCompat.getColor(getContext(), R.color.ctx_menu_bottom_view_secondary_text_color_dark));
localRoutesMoreTv.setTextColor(ContextCompat.getColor(getContext(), R.color.ctx_menu_bottom_view_secondary_text_color_dark));
} else {
nearbRoutesWithinTv.setTextColor(ContextCompat.getColor(getContext(), R.color.ctx_menu_nearby_routes_text_color_dark));
}
if (localTransportStopRoutes != null && localTransportStopRoutes.size() > 0) {
localTransportStopRoutesGrid.setAdapter(createTransportStopRouteAdapter(localTransportStopRoutes));
localTransportStopRoutesGrid.setVisibility(View.VISIBLE);
} else {
localTransportStopRoutesGrid.setVisibility(View.GONE);
}
if (nearbyTransportStopRoutes != null && nearbyTransportStopRoutes.size() > 0) {
String nearInDistance = getMyApplication().getString(R.string.transport_nearby_routes) + " "
+ OsmAndFormatter.getFormattedDistance(TransportStopController.SHOW_STOPS_RADIUS_METERS, getMyApplication()) +":";
nearbRoutesWithinTv.setText(nearInDistance);
nearbyTransportStopRoutesGrid.setAdapter(createTransportStopRouteAdapter(nearbyTransportStopRoutes));
nearbyTransportStopRoutesGrid.setVisibility(View.VISIBLE);
} else {
nearbyRoutesLayout.setVisibility(View.GONE);
nearbyRoutesWithinTv.setTextColor(ContextCompat.getColor(getContext(), R.color.ctx_menu_nearby_routes_text_color_dark));
localRoutesMoreTv.setTextColor(ContextCompat.getColor(getContext(), R.color.ctx_menu_nearby_routes_text_color_dark));
}
View buttonsBottomBorder = view.findViewById(R.id.buttons_bottom_border);
@ -631,6 +628,9 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
@Override
public void onLayoutChange(View view, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) {
if (!transportBadgesCreated) {
createTransportBadges();
}
if (forceUpdateLayout || bottom != oldBottom) {
forceUpdateLayout = false;
processScreenHeight(view.getParent());
@ -643,20 +643,35 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
return view;
}
private TransportStopRouteAdapter createTransportStopRouteAdapter(List<TransportStopRoute> routes) {
final TransportStopRouteAdapter adapter = new TransportStopRouteAdapter(getMyApplication(), filterTransportRoutes(routes), nightMode);
private TransportStopRouteAdapter createTransportStopRouteAdapter(List<TransportStopRoute> routes, boolean needMoreItem) {
List<Object> items = new ArrayList<Object>(routes);
if (needMoreItem) {
items.add(TRANSPORT_BADGE_MORE_ITEM);
}
final TransportStopRouteAdapter adapter = new TransportStopRouteAdapter(getMyApplication(), items, nightMode);
adapter.setListener(new TransportStopRouteAdapter.OnClickListener() {
@Override
public void onClick(int position) {
TransportStopRoute route = adapter.getItem(position);
if (route != null) {
PointDescription pd = new PointDescription(PointDescription.POINT_TYPE_TRANSPORT_ROUTE,
route.getDescription(getMapActivity().getMyApplication(), false));
menu.show(menu.getLatLon(), pd, route);
TransportStopsLayer stopsLayer = getMapActivity().getMapLayers().getTransportStopsLayer();
stopsLayer.setRoute(route);
int cz = route.calculateZoom(0, getMapActivity().getMapView().getCurrentRotatedTileBox());
getMapActivity().changeZoom(cz - getMapActivity().getMapView().getZoom());
Object object = adapter.getItem(position);
if (object != null) {
if (object instanceof TransportStopRoute) {
TransportStopRoute route = (TransportStopRoute) object;
PointDescription pd = new PointDescription(PointDescription.POINT_TYPE_TRANSPORT_ROUTE,
route.getDescription(getMapActivity().getMyApplication(), false));
menu.show(menu.getLatLon(), pd, route);
TransportStopsLayer stopsLayer = getMapActivity().getMapLayers().getTransportStopsLayer();
stopsLayer.setRoute(route);
int cz = route.calculateZoom(0, getMapActivity().getMapView().getCurrentRotatedTileBox());
getMapActivity().changeZoom(cz - getMapActivity().getMapView().getZoom());
} else if (object instanceof String) {
if (object.equals(TRANSPORT_BADGE_MORE_ITEM)) {
if (menu.isLandscapeLayout()) {
changeMenuState(getFullScreenTopPosY(), false, false);
} else {
openMenuFullScreen();
}
}
}
}
}
});
@ -669,9 +684,6 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
if (!containsRef(filteredRoutes, route.route)) {
filteredRoutes.add(route);
}
if (filteredRoutes.size() >= MAX_TRANSPORT_ROUTES_BADGES) {
break;
}
}
return filteredRoutes;
}
@ -1273,6 +1285,76 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
}
}
private void createTransportBadges() {
if (!transportBadgesCreated) {
List<TransportStopRoute> localTransportStopRoutes = filterTransportRoutes(menu.getLocalTransportStopRoutes());
List<TransportStopRoute> nearbyTransportStopRoutes = filterTransportRoutes(menu.getNearbyTransportStopRoutes());
int localColumnsPerRow = getRoutesBadgesColumnsPerRow(null);
int maxLocalRows = (int) Math.round(Math.ceil((double) localTransportStopRoutes.size() / localColumnsPerRow));
updateLocalRoutesBadges(localTransportStopRoutes, localColumnsPerRow);
updateNearbyRoutesBadges(maxLocalRows, nearbyTransportStopRoutes);
transportBadgesCreated = true;
}
}
private void updateLocalRoutesBadges(List<TransportStopRoute> localTransportStopRoutes, int localColumnsPerRow) {
int localRoutesSize = localTransportStopRoutes.size();
if (localRoutesSize > 0) {
int maxLocalBadges = localColumnsPerRow * 5;
TransportStopRouteAdapter adapter;
if (localRoutesSize > maxLocalBadges) {
adapter = createTransportStopRouteAdapter(localTransportStopRoutes.subList(0, maxLocalBadges), false);
localRoutesMoreTv.setVisibility(View.VISIBLE);
} else {
adapter = createTransportStopRouteAdapter(localTransportStopRoutes, false);
localRoutesMoreTv.setVisibility(View.GONE);
}
localTransportStopRoutesGrid.setAdapter(adapter);
localTransportStopRoutesGrid.setVisibility(View.VISIBLE);
} else {
localTransportStopRoutesGrid.setVisibility(View.GONE);
localRoutesMoreTv.setVisibility(View.GONE);
}
}
private void updateNearbyRoutesBadges(int maxLocalRows, List<TransportStopRoute> nearbyTransportStopRoutes) {
int nearbyRoutesSize = nearbyTransportStopRoutes.size();
boolean moreLocalItems = localRoutesMoreTv.getVisibility() == View.VISIBLE;
if (maxLocalRows <= 5 && !moreLocalItems && nearbyRoutesSize > 0) {
String nearInDistance = getString(R.string.transport_nearby_routes) + " "
+ OsmAndFormatter.getFormattedDistance(TransportStopController.SHOW_STOPS_RADIUS_METERS, getMyApplication()) + ":";
nearbyRoutesWithinTv.setText(nearInDistance);
int nearbyColumnsPerRow = getRoutesBadgesColumnsPerRow(nearInDistance);
int maxNearbyRows = Math.min(3, 6 - maxLocalRows);
int nearbyMaxItems = maxNearbyRows * nearbyColumnsPerRow - 1;
TransportStopRouteAdapter adapter;
if (nearbyRoutesSize > nearbyMaxItems) {
adapter = createTransportStopRouteAdapter(nearbyTransportStopRoutes.subList(0, nearbyMaxItems), true);
} else {
adapter = createTransportStopRouteAdapter(nearbyTransportStopRoutes, false);
}
nearbyTransportStopRoutesGrid.setAdapter(adapter);
nearbyTransportStopRoutesGrid.setVisibility(View.VISIBLE);
} else {
nearbyRoutesLayout.setVisibility(View.GONE);
}
}
private int getRoutesBadgesColumnsPerRow(@Nullable String nearInDistance) {
double badgeWidth = getResources().getDimension(R.dimen.context_menu_transport_grid_item_width);
double gridSpacing = getResources().getDimension(R.dimen.context_menu_transport_grid_spacing);
double gridPadding = getResources().getDimension(R.dimen.context_menu_padding_margin_default);
int availableSpace;
if (nearInDistance == null) {
availableSpace = (int) (routesBadgesContainer.getWidth() - gridPadding * 2);
} else {
int textWidth = AndroidUtils.getTextWidth(getResources().getDimensionPixelSize(R.dimen.default_sub_text_size), nearInDistance);
double paddingTv = getResources().getDimension(R.dimen.context_menu_padding_margin_small);
availableSpace = (int) (routesBadgesContainer.getWidth() - gridPadding * 2 - paddingTv - textWidth);
}
return (int) ((availableSpace + gridSpacing) / (badgeWidth + gridSpacing));
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void runLayoutListener() {
if (view != null) {

View file

@ -3,6 +3,7 @@ package net.osmand.plus.mapcontextmenu;
import android.graphics.drawable.GradientDrawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -16,13 +17,13 @@ import net.osmand.plus.transport.TransportStopRoute;
import java.util.List;
public class TransportStopRouteAdapter extends ArrayAdapter<TransportStopRoute> {
public class TransportStopRouteAdapter extends ArrayAdapter<Object> {
private boolean nightMode;
private OnClickListener listener;
private OsmandApplication app;
public TransportStopRouteAdapter(@NonNull OsmandApplication application, @NonNull List<TransportStopRoute> objects, boolean nightMode) {
public TransportStopRouteAdapter(@NonNull OsmandApplication application, @NonNull List<Object> objects, boolean nightMode) {
super(application, 0, objects);
this.nightMode = nightMode;
this.app = application;
@ -38,25 +39,33 @@ public class TransportStopRouteAdapter extends ArrayAdapter<TransportStopRoute>
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.transport_stop_route_item, parent, false);
}
TransportStopRoute transportStopRoute = getItem(position);
if (transportStopRoute != null) {
Object object = getItem(position);
if (object != null) {
String routeRef = "";
int bgColor = 0;
if (object instanceof TransportStopRoute) {
TransportStopRoute transportStopRoute = (TransportStopRoute) object;
routeRef = getAdjustedRouteRef(transportStopRoute.route.getRef());
bgColor = transportStopRoute.getColor(app, nightMode);
} else if (object instanceof String) {
routeRef = (String) object;
bgColor = ContextCompat.getColor(app, R.color.route_info_unchecked_mode_icon_color);
}
TextView transportStopRouteTextView = (TextView) convertView.findViewById(R.id.transport_stop_route_text);
transportStopRouteTextView.setText(getAdjustedRouteRef(transportStopRoute.route.getRef()));
transportStopRouteTextView.setText(routeRef);
GradientDrawable gradientDrawableBg = (GradientDrawable) transportStopRouteTextView.getBackground();
int bgColor = transportStopRoute.getColor(app, nightMode);
gradientDrawableBg.setColor(bgColor);
transportStopRouteTextView.setTextColor(UiUtilities.getContrastColor(app, bgColor, true));
}
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null) {
listener.onClick(position);
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null) {
listener.onClick(position);
}
}
}
});
});
}
return convertView;
}
@ -65,7 +74,7 @@ public class TransportStopRouteAdapter extends ArrayAdapter<TransportStopRoute>
if (ref != null) {
int charPos = ref.lastIndexOf(':');
if (charPos != -1) {
ref = ref.substring(0, charPos);
ref = ref.substring(0, charPos);
}
if (ref.length() > 4) {
ref = ref.substring(0, 4);