diff --git a/android/jni/app/organicmaps/Framework.cpp b/android/jni/app/organicmaps/Framework.cpp
index 407e73e852..4fd22617f4 100644
--- a/android/jni/app/organicmaps/Framework.cpp
+++ b/android/jni/app/organicmaps/Framework.cpp
@@ -1425,6 +1425,7 @@ Java_app_organicmaps_Framework_nativeSetRouter(JNIEnv * env, jclass, jint router
case 1: type = Type::Pedestrian; break;
case 2: type = Type::Bicycle; break;
case 3: type = Type::Transit; break;
+ case 4: type = Type::Ruler; break;
default: assert(false); break;
}
g_framework->GetRoutingManager().SetRouter(type);
diff --git a/android/res/drawable/ic_ruler_route.xml b/android/res/drawable/ic_ruler_route.xml
new file mode 100644
index 0000000000..c502863276
--- /dev/null
+++ b/android/res/drawable/ic_ruler_route.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
diff --git a/android/res/layout/routing_bottom_panel_transit.xml b/android/res/layout/routing_bottom_panel_transit.xml
index 22156f22ad..cce2c490be 100644
--- a/android/res/layout/routing_bottom_panel_transit.xml
+++ b/android/res/layout/routing_bottom_panel_transit.xml
@@ -46,7 +46,7 @@
android:id="@+id/transit_recycler_view"
android:layout_marginTop="@dimen/margin_half_plus"
android:layout_alignParentStart="true"
- android:layout_below="@id/total_distance"
+ android:layout_below="@id/total_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
diff --git a/android/res/layout/routing_plan.xml b/android/res/layout/routing_plan.xml
index 1ca805f769..23382f782f 100644
--- a/android/res/layout/routing_plan.xml
+++ b/android/res/layout/routing_plan.xml
@@ -73,6 +73,14 @@
android:layout_marginEnd="12dp"
tools:button="@drawable/ic_bike"
tools:buttonTint="?iconTintLight" />
+
+
+
+
diff --git a/android/res/values/font_sizes.xml b/android/res/values/font_sizes.xml
index 63aee99c7a..c118412a70 100644
--- a/android/res/values/font_sizes.xml
+++ b/android/res/values/font_sizes.xml
@@ -51,6 +51,7 @@
20sp
16sp
14sp
+ 20sp
56sp
17sp
diff --git a/android/res/values/themes-attrs.xml b/android/res/values/themes-attrs.xml
index a5bd6ca2cb..d5b1c19b8c 100644
--- a/android/res/values/themes-attrs.xml
+++ b/android/res/values/themes-attrs.xml
@@ -42,6 +42,7 @@
+
diff --git a/android/res/values/themes-base.xml b/android/res/values/themes-base.xml
index da9956219d..79aeb84d0d 100644
--- a/android/res/values/themes-base.xml
+++ b/android/res/values/themes-base.xml
@@ -87,6 +87,7 @@
- @drawable/back_arrow
- @color/black_4
+ - @color/black_4
- @drawable/dot_divider
- @drawable/ic_layers_traffic_active
- @drawable/ic_layers_subway_active
@@ -221,6 +222,7 @@
- @drawable/back_arrow
- @color/white_4
+ - @color/white_4
- @drawable/dot_divider_night
- @drawable/ic_layers_traffic_active_night
- @drawable/ic_layers_subway_active_night
diff --git a/android/src/app/organicmaps/Framework.java b/android/src/app/organicmaps/Framework.java
index 1b84662aab..7cbb8d1ab5 100644
--- a/android/src/app/organicmaps/Framework.java
+++ b/android/src/app/organicmaps/Framework.java
@@ -46,7 +46,7 @@ public class Framework
public static final int MAP_STYLE_VEHICLE_DARK = 4;
@Retention(RetentionPolicy.SOURCE)
- @IntDef({ ROUTER_TYPE_VEHICLE, ROUTER_TYPE_PEDESTRIAN, ROUTER_TYPE_BICYCLE, ROUTER_TYPE_TRANSIT })
+ @IntDef({ ROUTER_TYPE_VEHICLE, ROUTER_TYPE_PEDESTRIAN, ROUTER_TYPE_BICYCLE, ROUTER_TYPE_TRANSIT, ROUTER_TYPE_RULER })
public @interface RouterType {}
@@ -54,6 +54,7 @@ public class Framework
public static final int ROUTER_TYPE_PEDESTRIAN = 1;
public static final int ROUTER_TYPE_BICYCLE = 2;
public static final int ROUTER_TYPE_TRANSIT = 3;
+ public static final int ROUTER_TYPE_RULER = 4;
@Retention(RetentionPolicy.SOURCE)
@IntDef({DO_AFTER_UPDATE_NOTHING, DO_AFTER_UPDATE_AUTO_UPDATE, DO_AFTER_UPDATE_ASK_FOR_UPDATE})
diff --git a/android/src/app/organicmaps/routing/RoutingBottomMenuController.java b/android/src/app/organicmaps/routing/RoutingBottomMenuController.java
index 35ab883c59..90c31c84a0 100644
--- a/android/src/app/organicmaps/routing/RoutingBottomMenuController.java
+++ b/android/src/app/organicmaps/routing/RoutingBottomMenuController.java
@@ -29,13 +29,17 @@ import androidx.recyclerview.widget.RecyclerView;
import app.organicmaps.Framework;
import app.organicmaps.R;
+import app.organicmaps.bookmarks.data.DistanceAndAzimut;
import app.organicmaps.location.LocationHelper;
+import app.organicmaps.util.Distance;
import app.organicmaps.widget.recycler.DotDividerItemDecoration;
import app.organicmaps.widget.recycler.MultilineLayoutManager;
import app.organicmaps.util.Graphics;
import app.organicmaps.util.ThemeUtils;
import app.organicmaps.util.UiUtils;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Locale;
final class RoutingBottomMenuController implements View.OnClickListener
@@ -135,9 +139,11 @@ final class RoutingBottomMenuController implements View.OnClickListener
void showAltitudeChartAndRoutingDetails()
{
- UiUtils.hide(mError, mActionFrame, mTransitFrame);
+ UiUtils.hide(mError, mActionFrame, mAltitudeChart, mAltitudeDifference, mTransitFrame);
- showRouteAltitudeChart();
+ if (!RoutingController.get().isVehicleRouterType() &&
+ !RoutingController.get().isRulerRouterType())
+ showRouteAltitudeChart();
showRoutingDetails();
UiUtils.show(mAltitudeChartFrame);
}
@@ -172,6 +178,53 @@ final class RoutingBottomMenuController implements View.OnClickListener
distanceView.setText(info.getTotalPedestrianDistance() + " " + info.getTotalPedestrianDistanceUnits());
}
+ @SuppressLint("SetTextI18n")
+ void showRulerInfo(@NonNull RouteMarkData[] points, Distance totalLength)
+ {
+ UiUtils.hide(mError, mAltitudeChartFrame, mActionFrame, mAltitudeChartFrame);
+ showStartButton(false);
+ UiUtils.show(mTransitFrame);
+ RecyclerView rv = mTransitFrame.findViewById(R.id.transit_recycler_view);
+ if (points.length > 2)
+ {
+ UiUtils.show(rv);
+ TransitStepAdapter adapter = new TransitStepAdapter();
+ rv.setLayoutManager(new MultilineLayoutManager());
+ rv.setNestedScrollingEnabled(false);
+ rv.removeItemDecoration(mTransitViewDecorator);
+ rv.addItemDecoration(mTransitViewDecorator);
+ rv.setAdapter(adapter);
+ adapter.setItems(pointsToRulerSteps(points));
+ }
+ else
+ UiUtils.hide(rv); // Show only distance between start and finish
+
+ TextView totalTimeView = mTransitFrame.findViewById(R.id.total_time);
+ totalTimeView.setText(mContext.getString(R.string.placepage_distance) + ": " +
+ totalLength.mDistanceStr + " " + totalLength.getUnitsStr(mContext));
+
+ UiUtils.hide(mTransitFrame, R.id.dot);
+ UiUtils.hide(mTransitFrame, R.id.pedestrian_icon);
+ UiUtils.hide(mTransitFrame, R.id.total_distance);
+ }
+
+ // Create steps info to use in TransitStepAdapter.
+ private List pointsToRulerSteps(RouteMarkData[] points)
+ {
+ List transitSteps = new LinkedList<>();
+ for (int i = 1; i < points.length; i++)
+ {
+ RouteMarkData segmentStart = points[i - 1];
+ RouteMarkData segmentEnd = points[i];
+ DistanceAndAzimut dist = Framework.nativeGetDistanceAndAzimuthFromLatLon(segmentStart.mLat, segmentStart.mLon, segmentEnd.mLat, segmentEnd.mLon, 0);
+ if (i > 1)
+ transitSteps.add(TransitStepInfo.intermediatePoint(i - 2));
+ transitSteps.add(TransitStepInfo.ruler(dist.getDistance().mDistanceStr, dist.getDistance().getUnitsStr(mContext)));
+ }
+
+ return transitSteps;
+ }
+
void showAddStartFrame()
{
UiUtils.hide(mError, mTransitFrame);
@@ -206,15 +259,17 @@ final class RoutingBottomMenuController implements View.OnClickListener
UiUtils.hide(mActionFrame);
}
- void setStartButton()
+ void setStartButton(boolean show)
{
- mStart.setText(mContext.getText(R.string.p2p_start));
- mStart.setOnClickListener(v -> {
- if (mListener != null)
- mListener.onRoutingStart();
- });
+ if (show) {
+ mStart.setText(mContext.getText(R.string.p2p_start));
+ mStart.setOnClickListener(v -> {
+ if (mListener != null)
+ mListener.onRoutingStart();
+ });
+ }
- showStartButton(true);
+ showStartButton(show);
}
private void showError(@NonNull String message)
diff --git a/android/src/app/organicmaps/routing/RoutingController.java b/android/src/app/organicmaps/routing/RoutingController.java
index 2461fb5664..5ac320a141 100644
--- a/android/src/app/organicmaps/routing/RoutingController.java
+++ b/android/src/app/organicmaps/routing/RoutingController.java
@@ -603,6 +603,11 @@ public class RoutingController implements Initializable
return mLastRouterType == Framework.ROUTER_TYPE_VEHICLE;
}
+ boolean isRulerRouterType()
+ {
+ return mLastRouterType == Framework.ROUTER_TYPE_RULER;
+ }
+
public boolean isNavigating()
{
return mState == State.NAVIGATION;
@@ -815,22 +820,14 @@ public class RoutingController implements Initializable
}
if (isSamePoint)
- {
- Logger.d(TAG, "setEndPoint: skip the same end point");
return false;
- }
if (point != null && point.sameAs(startPoint))
{
if (endPoint == null)
- {
- Logger.d(TAG, "setEndPoint: skip because end point is empty");
return false;
- }
- Logger.d(TAG, "setEndPoint: swap with starting point");
startPoint = endPoint;
-
}
endPoint = point;
diff --git a/android/src/app/organicmaps/routing/RoutingPlanController.java b/android/src/app/organicmaps/routing/RoutingPlanController.java
index f3ca006bf4..8c895613cd 100644
--- a/android/src/app/organicmaps/routing/RoutingPlanController.java
+++ b/android/src/app/organicmaps/routing/RoutingPlanController.java
@@ -39,6 +39,8 @@ public class RoutingPlanController extends ToolbarController
private final WheelProgressView mProgressTransit;
@NonNull
private final WheelProgressView mProgressBicycle;
+ @NonNull
+ private final WheelProgressView mProgressRuler;
// @NonNull
// private final WheelProgressView mProgressTaxi;
@@ -93,6 +95,7 @@ public class RoutingPlanController extends ToolbarController
mProgressPedestrian = progressFrame.findViewById(R.id.progress_pedestrian);
mProgressTransit = progressFrame.findViewById(R.id.progress_transit);
mProgressBicycle = progressFrame.findViewById(R.id.progress_bicycle);
+ mProgressRuler = progressFrame.findViewById(R.id.progress_ruler);
// mProgressTaxi = (WheelProgressView) progressFrame.findViewById(R.id.progress_taxi);
mRoutingBottomMenuController = RoutingBottomMenuController.newInstance(requireActivity(), mFrame, listener);
@@ -128,12 +131,13 @@ public class RoutingPlanController extends ToolbarController
{
setupRouterButton(R.id.vehicle, R.drawable.ic_car, this::onVehicleModeSelected);
setupRouterButton(R.id.pedestrian, R.drawable.ic_pedestrian, this::onPedestrianModeSelected);
- setupRouterButton(R.id.bicycle, R.drawable.ic_bike, this::onBicycleModeSelected);
// setupRouterButton(R.id.taxi, R.drawable.ic_taxi, this::onTaxiModeSelected);
- setupRouterButton(R.id.transit, R.drawable.ic_transit, v -> onTransitModeSelected());
+ setupRouterButton(R.id.transit, R.drawable.ic_transit, this::onTransitModeSelected);
+ setupRouterButton(R.id.bicycle, R.drawable.ic_bike, this::onBicycleModeSelected);
+ setupRouterButton(R.id.ruler, R.drawable.ic_ruler_route, this::onRulerModeSelected);
}
- private void onTransitModeSelected()
+ private void onTransitModeSelected(@NonNull View v)
{
RoutingController.get().setRouterType(Framework.ROUTER_TYPE_TRANSIT);
}
@@ -143,6 +147,11 @@ public class RoutingPlanController extends ToolbarController
RoutingController.get().setRouterType(Framework.ROUTER_TYPE_BICYCLE);
}
+ private void onRulerModeSelected(@NonNull View v)
+ {
+ RoutingController.get().setRouterType(Framework.ROUTER_TYPE_RULER);
+ }
+
private void onPedestrianModeSelected(@NonNull View v)
{
RoutingController.get().setRouterType(Framework.ROUTER_TYPE_PEDESTRIAN);
@@ -188,39 +197,53 @@ public class RoutingPlanController extends ToolbarController
return;
}
- mRoutingBottomMenuController.setStartButton();
+ if (isRulerType())
+ {
+ RoutingInfo routingInfo = RoutingController.get().getCachedRoutingInfo();
+ if (routingInfo != null)
+ mRoutingBottomMenuController.showRulerInfo(Framework.nativeGetRoutePoints(), routingInfo.distToTarget);
+ return;
+ }
+
+ boolean showStartButton = !RoutingController.get().isRulerRouterType();
+ mRoutingBottomMenuController.setStartButton(showStartButton);
mRoutingBottomMenuController.showAltitudeChartAndRoutingDetails();
}
public void updateBuildProgress(int progress, @Framework.RouterType int router)
{
UiUtils.invisible(mProgressVehicle, mProgressPedestrian, mProgressTransit,
- mProgressBicycle);
+ mProgressBicycle, mProgressRuler);
WheelProgressView progressView;
- if (router == Framework.ROUTER_TYPE_VEHICLE)
+ switch(router)
{
+ case Framework.ROUTER_TYPE_VEHICLE:
mRouterTypes.check(R.id.vehicle);
progressView = mProgressVehicle;
- }
- else if (router == Framework.ROUTER_TYPE_PEDESTRIAN)
- {
+ break;
+ case Framework.ROUTER_TYPE_PEDESTRIAN:
mRouterTypes.check(R.id.pedestrian);
progressView = mProgressPedestrian;
- }
-// else if (router == Framework.ROUTER_TYPE_TAXI)
-// {
-// mRouterTypes.check(R.id.taxi);
-// progressView = mProgressTaxi;
-// }
- else if (router == Framework.ROUTER_TYPE_TRANSIT)
- {
+ break;
+ //case Framework.ROUTER_TYPE_TAXI:
+ // {
+ // mRouterTypes.check(R.id.taxi);
+ // progressView = mProgressTaxi;
+ // }
+ case Framework.ROUTER_TYPE_TRANSIT:
mRouterTypes.check(R.id.transit);
progressView = mProgressTransit;
- }
- else
- {
+ break;
+ case Framework.ROUTER_TYPE_BICYCLE:
mRouterTypes.check(R.id.bicycle);
progressView = mProgressBicycle;
+ break;
+ case Framework.ROUTER_TYPE_RULER:
+ mRouterTypes.check(R.id.ruler);
+ progressView = mProgressRuler;
+ break;
+ default:
+ throw new IllegalArgumentException("unknown router: " + router);
}
RoutingToolbarButton button = mRouterTypes
@@ -246,6 +269,11 @@ public class RoutingPlanController extends ToolbarController
return RoutingController.get().isTransitType();
}
+ private boolean isRulerType()
+ {
+ return RoutingController.get().isRulerRouterType();
+ }
+
void saveRoutingPanelState(@NonNull Bundle outState)
{
mRoutingBottomMenuController.saveRoutingPanelState(outState);
diff --git a/android/src/app/organicmaps/routing/TransitStepInfo.java b/android/src/app/organicmaps/routing/TransitStepInfo.java
index 64b3a517fb..9bcff82c4d 100644
--- a/android/src/app/organicmaps/routing/TransitStepInfo.java
+++ b/android/src/app/organicmaps/routing/TransitStepInfo.java
@@ -18,10 +18,11 @@ public class TransitStepInfo
private static final int TRANSIT_TYPE_TRAIN = 3;
private static final int TRANSIT_TYPE_LIGHT_RAIL = 4;
private static final int TRANSIT_TYPE_MONORAIL = 5;
+ private static final int TRANSIT_TYPE_RULER = 6;
@Retention(RetentionPolicy.SOURCE)
@IntDef({ TRANSIT_TYPE_INTERMEDIATE_POINT, TRANSIT_TYPE_PEDESTRIAN, TRANSIT_TYPE_SUBWAY,
- TRANSIT_TYPE_TRAIN, TRANSIT_TYPE_LIGHT_RAIL, TRANSIT_TYPE_MONORAIL })
+ TRANSIT_TYPE_TRAIN, TRANSIT_TYPE_LIGHT_RAIL, TRANSIT_TYPE_MONORAIL, TRANSIT_TYPE_RULER})
@interface TransitType {}
@NonNull
@@ -48,6 +49,18 @@ public class TransitStepInfo
mIntermediateIndex = intermediateIndex;
}
+ @NonNull
+ public static TransitStepInfo intermediatePoint(int intermediateIndex)
+ {
+ return new TransitStepInfo(TRANSIT_TYPE_INTERMEDIATE_POINT, null, null, 0, null, 0, intermediateIndex);
+ }
+
+ @NonNull
+ public static TransitStepInfo ruler(@NonNull String distance, @NonNull String distanceUnits)
+ {
+ return new TransitStepInfo(TRANSIT_TYPE_RULER, distance, distanceUnits, 0, null, 0, -1);
+ }
+
@NonNull
public TransitStepType getType()
{
diff --git a/android/src/app/organicmaps/routing/TransitStepType.java b/android/src/app/organicmaps/routing/TransitStepType.java
index 4aea7389b8..bf1ffd9a6d 100644
--- a/android/src/app/organicmaps/routing/TransitStepType.java
+++ b/android/src/app/organicmaps/routing/TransitStepType.java
@@ -12,7 +12,8 @@ public enum TransitStepType
SUBWAY(R.drawable.ic_20px_route_planning_metro),
TRAIN(R.drawable.ic_20px_route_planning_train),
LIGHT_RAIL(R.drawable.ic_20px_route_planning_lightrail),
- MONORAIL(R.drawable.ic_20px_route_planning_monorail);
+ MONORAIL(R.drawable.ic_20px_route_planning_monorail),
+ RULER(R.drawable.ic_ruler_route);
@DrawableRes
private final int mDrawable;
diff --git a/android/src/app/organicmaps/routing/TransitStepView.java b/android/src/app/organicmaps/routing/TransitStepView.java
index 5955557530..87d5116828 100644
--- a/android/src/app/organicmaps/routing/TransitStepView.java
+++ b/android/src/app/organicmaps/routing/TransitStepView.java
@@ -85,6 +85,12 @@ public class TransitStepView extends View implements MultilineLayoutManager.Sque
mDrawable = null;
mText = String.valueOf(info.getIntermediateIndex() + 1);
}
+ else if (mStepType == TransitStepType.RULER)
+ {
+ mDrawable = null;
+ mText = info.getDistance() + " " + info.getDistanceUnits();
+ mTextPaint.setColor(Color.BLACK);
+ }
else
{
mDrawable = ResourcesCompat.getDrawable(getResources(), mStepType.getDrawable(), null);
@@ -101,6 +107,8 @@ public class TransitStepView extends View implements MultilineLayoutManager.Sque
{
case PEDESTRIAN:
return ThemeUtils.getColor(context, R.attr.transitPedestrianBackground);
+ case RULER:
+ return ThemeUtils.getColor(context, R.attr.transitRulerBackground);
case INTERMEDIATE_POINT:
return ThemeUtils.getColor(context, R.attr.colorPrimary);
default: