diff --git a/android/res/drawable/dot_divider.xml b/android/res/drawable/dot_divider.xml
new file mode 100644
index 0000000000..a235724a66
--- /dev/null
+++ b/android/res/drawable/dot_divider.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/android/res/layout/routing_bottom_panel_transit.xml b/android/res/layout/routing_bottom_panel_transit.xml
index 2d969265be..e27cec65fc 100644
--- a/android/res/layout/routing_bottom_panel_transit.xml
+++ b/android/res/layout/routing_bottom_panel_transit.xml
@@ -9,7 +9,7 @@
android:paddingStart="@dimen/margin_base"
android:paddingRight="@dimen/margin_base"
android:paddingEnd="@dimen/margin_base"
- android:paddingBottom="@dimen/margin_base"
+ android:paddingBottom="@dimen/margin_half"
android:paddingTop="@dimen/margin_half_plus">
2dp
4dp
8dp
- 2dp
+ 4dp
20dp
+ 104dp
48dp
diff --git a/android/src/com/mapswithme/maps/routing/RoutingBottomMenuController.java b/android/src/com/mapswithme/maps/routing/RoutingBottomMenuController.java
index dac66fae34..e7eeec66dd 100644
--- a/android/src/com/mapswithme/maps/routing/RoutingBottomMenuController.java
+++ b/android/src/com/mapswithme/maps/routing/RoutingBottomMenuController.java
@@ -1,6 +1,7 @@
package com.mapswithme.maps.routing;
import android.app.Activity;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.location.Location;
@@ -30,7 +31,8 @@ import com.mapswithme.maps.taxi.TaxiInfo;
import com.mapswithme.maps.taxi.TaxiLinks;
import com.mapswithme.maps.taxi.TaxiManager;
import com.mapswithme.maps.widget.DotPager;
-import com.mapswithme.maps.widget.recycler.TagLayoutManager;
+import com.mapswithme.maps.widget.recycler.DotDividerItemDecoration;
+import com.mapswithme.maps.widget.recycler.MultilineLayoutManager;
import com.mapswithme.util.Graphics;
import com.mapswithme.util.UiUtils;
import com.mapswithme.util.Utils;
@@ -72,7 +74,8 @@ final class RoutingBottomMenuController implements View.OnClickListener
private final View mActionButton;
@NonNull
private final ImageView mActionIcon;
-
+ @NonNull
+ private final DotDividerItemDecoration mTransitViewDecorator;
@Nullable
private TaxiInfo mTaxiInfo;
@Nullable
@@ -138,6 +141,10 @@ final class RoutingBottomMenuController implements View.OnClickListener
mActionIcon = (ImageView) mActionButton.findViewById(R.id.iv__icon);
UiUtils.hide(mAltitudeChartFrame, mTaxiFrame, mActionFrame);
mListener = listener;
+ Drawable dividerDrawable = ContextCompat.getDrawable(mContext, R.drawable.dot_divider);
+ Resources res = mContext.getResources();
+ mTransitViewDecorator = new DotDividerItemDecoration(dividerDrawable, res.getDimensionPixelSize(R.dimen.margin_base),
+ res.getDimensionPixelSize(R.dimen.margin_half));
}
void showAltitudeChartAndRoutingDetails()
@@ -188,9 +195,10 @@ final class RoutingBottomMenuController implements View.OnClickListener
UiUtils.show(mTransitFrame);
RecyclerView rv = (RecyclerView) mTransitFrame.findViewById(R.id.transit_recycler_view);
TransitStepAdapter adapter = new TransitStepAdapter();
- rv.setLayoutManager(new TagLayoutManager());
+ rv.setLayoutManager(new MultilineLayoutManager());
rv.setNestedScrollingEnabled(false);
- // TODO: make dot decorator.
+ rv.removeItemDecoration(mTransitViewDecorator);
+ rv.addItemDecoration(mTransitViewDecorator);
rv.setAdapter(adapter);
adapter.setItems(info.getTransitSteps());
diff --git a/android/src/com/mapswithme/maps/routing/TransitStepView.java b/android/src/com/mapswithme/maps/routing/TransitStepView.java
index e54e9fdd9b..f41a2d7c48 100644
--- a/android/src/com/mapswithme/maps/routing/TransitStepView.java
+++ b/android/src/com/mapswithme/maps/routing/TransitStepView.java
@@ -1,7 +1,6 @@
package com.mapswithme.maps.routing;
import android.content.Context;
-import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -11,22 +10,25 @@ import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.ColorInt;
+import android.support.annotation.Dimension;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.v4.graphics.drawable.DrawableCompat;
+import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;
-import android.util.TypedValue;
import android.view.View;
import com.mapswithme.maps.R;
+import com.mapswithme.maps.widget.recycler.MultilineLayoutManager;
+import com.mapswithme.util.ThemeUtils;
/**
* Represents a specific transit step. It displays a transit info, such as a number, color, etc., for
* the specific transit type: pedestrian, rail, metro, etc.
*/
-public class TransitStepView extends View
+public class TransitStepView extends View implements MultilineLayoutManager.SqueezingInterface
{
@Nullable
private Drawable mDrawable;
@@ -39,10 +41,13 @@ public class TransitStepView extends View
@NonNull
private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@NonNull
- private final Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private final TextPaint mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
private int mBackgroundCornerRadius;
@Nullable
- private TransitStepInfo mStepInfo;
+ private String mText;
+ @SuppressWarnings("NullableProblems")
+ @NonNull
+ private TransitStepType mStepType;
public TransitStepView(Context context, @Nullable AttributeSet attrs)
{
@@ -73,14 +78,16 @@ public class TransitStepView extends View
mTextPaint.setTextSize(textSize);
mTextPaint.setColor(textColor);
mDrawable = a.getDrawable(R.styleable.TransitStepView_android_drawable);
+ mStepType = TransitStepType.PEDESTRIAN;
a.recycle();
}
public void setTransitStepInfo(@NonNull TransitStepInfo info)
{
- mStepInfo = info;
- mDrawable = getResources().getDrawable(mStepInfo.getType().getDrawable());
- mBackgroundPaint.setColor(mStepInfo.getColor());
+ mStepType = info.getType();
+ mDrawable = getResources().getDrawable(mStepType.getDrawable());
+ mBackgroundPaint.setColor(info.getColor());
+ mText = info.getNumber();
invalidate();
requestLayout();
}
@@ -96,11 +103,10 @@ public class TransitStepView extends View
width += mDrawable.getIntrinsicWidth();
}
- if (mStepInfo != null && !TextUtils.isEmpty(mStepInfo.getNumber()))
+ if (!TextUtils.isEmpty(mText))
{
- String text = mStepInfo.getNumber();
- mTextPaint.getTextBounds(text, 0, text.length(), mTextBounds);
- width += (mDrawable != null ? getPaddingLeft(): 0) + mTextPaint.measureText(text);
+ mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBounds);
+ width += (mDrawable != null ? getPaddingLeft() : 0) + mTextPaint.measureText(mText);
if (height == 0)
height = getPaddingTop() + mTextBounds.height() + getPaddingBottom();
}
@@ -110,6 +116,19 @@ public class TransitStepView extends View
setMeasuredDimension(width, height);
}
+ @Override
+ public void squeezeTo(@Dimension int width)
+ {
+ int tSize = width - 2 * getPaddingLeft() - getPaddingRight() - mDrawableBounds.width();
+ mText = TextUtils.ellipsize(mText, mTextPaint, tSize, TextUtils.TruncateAt.END).toString();
+ }
+
+ @Override
+ public int getMinimumAcceptableSize()
+ {
+ return getResources().getDimensionPixelSize(R.dimen.routing_transit_setp_min_acceptable_with);
+ }
+
private void calculateDrawableBounds(int height, @NonNull Drawable drawable)
{
// If the clear view height, i.e. without top/bottom padding, is greater than the drawable height
@@ -120,7 +139,7 @@ public class TransitStepView extends View
vPad = (clearHeight - drawable.getIntrinsicHeight()) / 2;
mDrawableBounds.set(getPaddingLeft(), getPaddingTop() + vPad,
drawable.getIntrinsicWidth() + getPaddingLeft(),
- getTop() + vPad + drawable.getIntrinsicHeight());
+ getPaddingTop() + vPad + drawable.getIntrinsicHeight());
}
@Override
@@ -132,31 +151,25 @@ public class TransitStepView extends View
mBackgroundPaint);
}
- if (mDrawable != null && mStepInfo != null)
- drawDrawable(mStepInfo.getType(), mDrawable, canvas);
+ if (mDrawable != null)
+ drawDrawable(getContext(), mStepType, mDrawable, canvas);
- if (mStepInfo != null && !TextUtils.isEmpty(mStepInfo.getNumber()))
+ if (!TextUtils.isEmpty(mText))
{
- String text = mStepInfo.getNumber();
int yPos = (int) ((canvas.getHeight() / 2) - ((mTextPaint.descent() + mTextPaint.ascent()) / 2)) ;
int xPos = mDrawable != null ? mDrawable.getBounds().right + getPaddingLeft()
: getPaddingLeft();
- canvas.drawText(text, xPos, yPos, mTextPaint);
+ canvas.drawText(mText, xPos, yPos, mTextPaint);
}
}
- private void drawDrawable(@NonNull TransitStepType type,
+ private void drawDrawable(@NonNull Context context, @NonNull TransitStepType type,
@NonNull Drawable drawable, @NonNull Canvas canvas)
{
if (type == TransitStepType.PEDESTRIAN)
{
- TypedValue typedValue = new TypedValue();
- Resources.Theme theme = getContext().getTheme();
- if (theme.resolveAttribute(R.attr.iconTint, typedValue, true))
- {
- drawable.mutate();
- DrawableCompat.setTint(drawable, typedValue.data);
- }
+ drawable.mutate();
+ DrawableCompat.setTint(drawable, ThemeUtils.getColor(context, R.attr.iconTint));
}
drawable.setBounds(mDrawableBounds);
drawable.draw(canvas);
diff --git a/android/src/com/mapswithme/maps/widget/recycler/DotDividerItemDecoration.java b/android/src/com/mapswithme/maps/widget/recycler/DotDividerItemDecoration.java
new file mode 100644
index 0000000000..7f8f6f6cb9
--- /dev/null
+++ b/android/src/com/mapswithme/maps/widget/recycler/DotDividerItemDecoration.java
@@ -0,0 +1,59 @@
+package com.mapswithme.maps.widget.recycler;
+
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.Dimension;
+import android.support.annotation.NonNull;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+public class DotDividerItemDecoration extends RecyclerView.ItemDecoration
+{
+ @Dimension
+ private final int mHorizontalMargin;
+ @Dimension
+ private final int mVerticalMargin;
+ @NonNull
+ private final Drawable mDivider;
+
+ public DotDividerItemDecoration(@NonNull Drawable divider, @Dimension int horizontalMargin,
+ @Dimension int verticalMargin)
+ {
+ mDivider = divider;
+ mHorizontalMargin = horizontalMargin;
+ mVerticalMargin = verticalMargin;
+ }
+
+ @Override
+ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state)
+ {
+ super.getItemOffsets(outRect, view, parent, state);
+ outRect.right = mHorizontalMargin;
+ outRect.bottom = mVerticalMargin;
+ }
+
+ @Override
+ public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state)
+ {
+ if (state.isMeasuring())
+ return;
+
+ int childCount = parent.getChildCount();
+ for (int i = 0; i < childCount - 1; i++)
+ {
+ View child = parent.getChildAt(i);
+
+ int centerX = mHorizontalMargin / 2 + child.getRight();
+ int centerY = child.getHeight() / 2 + child.getTop();
+ int left = centerX - mDivider.getIntrinsicWidth() / 2;
+ int right = left + mDivider.getIntrinsicWidth();
+ int top = centerY - mDivider.getIntrinsicHeight() / 2;
+ int bottom = top + mDivider.getIntrinsicHeight();
+
+ mDivider.setBounds(left, top, right, bottom);
+
+ mDivider.draw(c);
+ }
+ }
+}
diff --git a/android/src/com/mapswithme/maps/widget/recycler/MultilineLayoutManager.java b/android/src/com/mapswithme/maps/widget/recycler/MultilineLayoutManager.java
new file mode 100644
index 0000000000..8b5fbcd3f4
--- /dev/null
+++ b/android/src/com/mapswithme/maps/widget/recycler/MultilineLayoutManager.java
@@ -0,0 +1,84 @@
+package com.mapswithme.maps.widget.recycler;
+
+import android.support.annotation.Dimension;
+import android.support.annotation.NonNull;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+public class MultilineLayoutManager extends RecyclerView.LayoutManager
+{
+ public MultilineLayoutManager()
+ {
+ setAutoMeasureEnabled(true);
+ }
+
+ @Override
+ public RecyclerView.LayoutParams generateDefaultLayoutParams()
+ {
+ return new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT,
+ RecyclerView.LayoutParams.WRAP_CONTENT);
+ }
+
+ @Override
+ public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state)
+ {
+ detachAndScrapAttachedViews(recycler);
+
+ int widthUsed = 0;
+ int heightUsed = 0;
+ int lineHeight = 0;
+ int itemsCountOneLine = 0;
+ for (int i = 0; i < getItemCount(); i++)
+ {
+ View child = recycler.getViewForPosition(i);
+ addView(child);
+ measureChildWithMargins(child, widthUsed, heightUsed);
+ int width = getDecoratedMeasuredWidth(child);
+ if (width > getWidth() - widthUsed)
+ width = squeezeChildIntoLine(widthUsed, heightUsed, child);
+ int height = getDecoratedMeasuredHeight(child);
+ lineHeight = Math.max(lineHeight, height);
+ if (widthUsed + width > getWidth())
+ {
+ widthUsed = 0;
+ if (itemsCountOneLine > 0)
+ {
+ itemsCountOneLine = 0;
+ heightUsed += lineHeight;
+ child.forceLayout();
+ measureChildWithMargins(child, widthUsed, heightUsed);
+ width = getDecoratedMeasuredWidth(child);
+ if (width > getWidth() - widthUsed)
+ width = squeezeChildIntoLine(widthUsed, heightUsed, child);
+ height = getDecoratedMeasuredHeight(child);
+ }
+ lineHeight = 0;
+ }
+ layoutDecorated(child, widthUsed, heightUsed, widthUsed + width, heightUsed + height);
+ widthUsed += width;
+ itemsCountOneLine++;
+ }
+ }
+
+ private int squeezeChildIntoLine(int widthUsed, int heightUsed, @NonNull View child)
+ {
+ if (!(child instanceof SqueezingInterface))
+ return getDecoratedMeasuredWidth(child);
+
+ int availableWidth = getWidth() - widthUsed - getDecoratedRight(child);
+ if (availableWidth > ((SqueezingInterface) child).getMinimumAcceptableSize())
+ {
+ ((SqueezingInterface) child).squeezeTo(availableWidth);
+ child.forceLayout();
+ measureChildWithMargins(child, widthUsed, heightUsed);
+ }
+ return getDecoratedMeasuredWidth(child);
+ }
+
+ public interface SqueezingInterface
+ {
+ void squeezeTo(@Dimension int width);
+ @Dimension
+ int getMinimumAcceptableSize();
+ }
+}