diff --git a/android/app/src/main/cpp/app/organicmaps/Framework.cpp b/android/app/src/main/cpp/app/organicmaps/Framework.cpp index 905a6b36fe..7b47eef574 100644 --- a/android/app/src/main/cpp/app/organicmaps/Framework.cpp +++ b/android/app/src/main/cpp/app/organicmaps/Framework.cpp @@ -1578,6 +1578,12 @@ Java_app_organicmaps_Framework_nativeAddRoutePoint(JNIEnv * env, jclass, jstring frm()->GetRoutingManager().AddRoutePoint(std::move(data)); } +JNIEXPORT void JNICALL +Java_app_organicmaps_Framework_nativeRemoveRoutePoints(JNIEnv * env, jclass) +{ + frm()->GetRoutingManager().RemoveRoutePoints(); +} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeRemoveRoutePoint(JNIEnv * env, jclass, jint markType, jint intermediateIndex) @@ -1627,6 +1633,13 @@ Java_app_organicmaps_Framework_nativeGetRoutePoints(JNIEnv * env, jclass) }); } +JNIEXPORT void JNICALL +Java_app_organicmaps_Framework_nativeMoveRoutePoint(JNIEnv * env, jclass, + jint currentIndex, jint targetIndex) +{ + frm()->GetRoutingManager().MoveRoutePoint(currentIndex, targetIndex); +} + JNIEXPORT jobject JNICALL Java_app_organicmaps_Framework_nativeGetTransitRouteInfo(JNIEnv * env, jclass) { diff --git a/android/app/src/main/java/app/organicmaps/Framework.java b/android/app/src/main/java/app/organicmaps/Framework.java index 349431f208..358c03014b 100644 --- a/android/app/src/main/java/app/organicmaps/Framework.java +++ b/android/app/src/main/java/app/organicmaps/Framework.java @@ -333,11 +333,20 @@ public class Framework public static native int nativeGetBestRouter(double srcLat, double srcLon, double dstLat, double dstLon); + public static void addRoutePoint(RouteMarkData point) + { + Framework.nativeAddRoutePoint(point.mTitle, point.mSubtitle, point.mPointType, + point.mIntermediateIndex, point.mIsMyPosition, + point.mLat, point.mLon); + } + public static native void nativeAddRoutePoint(String title, String subtitle, @RoutePointInfo.RouteMarkType int markType, int intermediateIndex, boolean isMyPosition, double lat, double lon); + public static native void nativeRemoveRoutePoints(); + public static native void nativeRemoveRoutePoint(@RoutePointInfo.RouteMarkType int markType, int intermediateIndex); @@ -346,6 +355,9 @@ public class Framework public static native boolean nativeCouldAddIntermediatePoint(); @NonNull public static native RouteMarkData[] nativeGetRoutePoints(); + + public static native void nativeMoveRoutePoint(int currentIndex, int targetIndex); + @NonNull public static native TransitRouteInfo nativeGetTransitRouteInfo(); /** diff --git a/android/app/src/main/java/app/organicmaps/MwmActivity.java b/android/app/src/main/java/app/organicmaps/MwmActivity.java index 8e2dff583d..37e97b821f 100644 --- a/android/app/src/main/java/app/organicmaps/MwmActivity.java +++ b/android/app/src/main/java/app/organicmaps/MwmActivity.java @@ -77,6 +77,7 @@ import app.organicmaps.maplayer.MapButtonsViewModel; import app.organicmaps.maplayer.ToggleMapLayerFragment; import app.organicmaps.maplayer.isolines.IsolinesManager; import app.organicmaps.maplayer.isolines.IsolinesState; +import app.organicmaps.routing.ManageRouteBottomSheet; import app.organicmaps.routing.NavigationController; import app.organicmaps.routing.NavigationService; import app.organicmaps.routing.RoutePointInfo; @@ -233,6 +234,8 @@ public class MwmActivity extends BaseMwmFragmentActivity @NonNull private DisplayManager mDisplayManager; + ManageRouteBottomSheet mManageRouteBottomSheet; + private boolean mRemoveDisplayListener = true; private int mLastUiMode = Configuration.UI_MODE_TYPE_UNDEFINED; @@ -2134,6 +2137,15 @@ public class MwmActivity extends BaseMwmFragmentActivity RoutingController.get().start(); } + @Override + public void onManageRouteOpen() + { + // Create and show 'Manage Route' Bottom Sheet panel. + mManageRouteBottomSheet = new ManageRouteBottomSheet(); + mManageRouteBottomSheet.setCancelable(false); + mManageRouteBottomSheet.show(getSupportFragmentManager(), "ManageRouteBottomSheet"); + } + private boolean requestBatterySaverPermission() { if (!PowerManagment.isSystemPowerSaveMode(this)) diff --git a/android/app/src/main/java/app/organicmaps/car/screens/permissions/RequestPermissionsScreenWithNotification.java b/android/app/src/main/java/app/organicmaps/car/screens/permissions/RequestPermissionsScreenWithNotification.java index c9412a899c..b916deaa76 100644 --- a/android/app/src/main/java/app/organicmaps/car/screens/permissions/RequestPermissionsScreenWithNotification.java +++ b/android/app/src/main/java/app/organicmaps/car/screens/permissions/RequestPermissionsScreenWithNotification.java @@ -113,7 +113,7 @@ public class RequestPermissionsScreenWithNotification extends BaseScreen impleme .setOngoing(true) .setShowWhen(false) .setOnlyAlertOnce(true) - .setSmallIcon(R.drawable.ic_my_location) + .setSmallIcon(R.drawable.ic_location_crosshair) .setColor(ContextCompat.getColor(getCarContext(), R.color.notification)) .setContentTitle(getCarContext().getString(R.string.aa_request_permission_notification)) .setContentIntent(pendingIntent); diff --git a/android/app/src/main/java/app/organicmaps/routing/ManageRouteAdapter.java b/android/app/src/main/java/app/organicmaps/routing/ManageRouteAdapter.java new file mode 100644 index 0000000000..4e6fa6c5a6 --- /dev/null +++ b/android/app/src/main/java/app/organicmaps/routing/ManageRouteAdapter.java @@ -0,0 +1,265 @@ +package app.organicmaps.routing; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.RectF; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.appcompat.content.res.AppCompatResources; +import androidx.recyclerview.widget.RecyclerView; + +import app.organicmaps.R; +import app.organicmaps.bookmarks.data.MapObject; +import app.organicmaps.util.StringUtils; +import app.organicmaps.util.UiUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; + +public class ManageRouteAdapter extends RecyclerView.Adapter +{ + Context mContext; + ArrayList mRoutePoints; + ManageRouteListener mManageRouteListener; + + public interface ManageRouteListener + { + void startDrag(RecyclerView.ViewHolder viewHolder); + void showMyLocationIcon(boolean showMyLocationIcon); + void onRoutePointDeleted(RecyclerView.ViewHolder viewHolder); + } + + public ManageRouteAdapter(Context context, RouteMarkData[] routeMarkData, ManageRouteListener listener) + { + mContext = context; + mRoutePoints = new ArrayList<>(Arrays.asList(routeMarkData)); + mManageRouteListener = listener; + + updateMyLocationIcon(); + } + + @NonNull + @Override + public ManageRouteViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) + { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.manage_route_list_item, + parent, false); + + return new ManageRouteViewHolder(view); + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public void onBindViewHolder(@NonNull ManageRouteViewHolder holder, int position) + { + // Set route point icon. + int iconId; + + switch (mRoutePoints.get(position).mPointType) + { + case RoutePointInfo.ROUTE_MARK_START: // Starting point. + if (mRoutePoints.get(position).mIsMyPosition) + iconId = R.drawable.ic_location_arrow_blue; + else + iconId = R.drawable.route_point_start; + break; + + case RoutePointInfo.ROUTE_MARK_INTERMEDIATE: // Intermediate stop. + TypedArray iconArray = mContext.getResources().obtainTypedArray(R.array.route_stop_icons); + iconId = iconArray.getResourceId(mRoutePoints.get(position).mIntermediateIndex, + R.drawable.route_point_20); + iconArray.recycle(); + break; + + case RoutePointInfo.ROUTE_MARK_FINISH: // Destination point. + iconId = R.drawable.route_point_finish; + break; + + default: // Unknown route type. + iconId = R.drawable.warning_icon; + break; + } + + // Set icon widget. + holder.mImageViewIcon.setImageDrawable(AppCompatResources.getDrawable(mContext, iconId)); + + // Set title & subtitle. + String title, subtitle; + + if (mRoutePoints.get(position).mIsMyPosition) + { + // My position point. + title = mContext.getString(R.string.core_my_position); + + if (mRoutePoints.get(position).mPointType != RoutePointInfo.ROUTE_MARK_START) + subtitle = mRoutePoints.get(position).mTitle; + else + { + // Hide my position coordinates if it's the starting point of the route. + subtitle = ""; + } + } + else + { + title = mRoutePoints.get(position).mTitle; + subtitle = mRoutePoints.get(position).mSubtitle; + } + + holder.mTextViewTitle.setText(title); + holder.mTextViewSubtitle.setText(subtitle); + UiUtils.showIf(subtitle != null && !subtitle.isEmpty(), holder.mTextViewSubtitle); + + // Show 'Delete' icon button only if we have intermediate stops. + UiUtils.showIf(mRoutePoints.size() > 2, holder.mImageViewDelete); + + // Detection of touch events on holder view. + holder.mItemView.setOnTouchListener((v, event) -> { + + if (event.getAction() == MotionEvent.ACTION_DOWN) + { + RectF deleteButtonRect = new RectF(holder.mImageViewDelete.getLeft(), + holder.mImageViewDelete.getTop(), + holder.mImageViewDelete.getRight(), + holder.mImageViewDelete.getBottom()); + + if (holder.mImageViewDelete.isShown() && deleteButtonRect.contains(event.getX(), event.getY())) + { + // User has clicked on the 'Delete' icon button. + mManageRouteListener.onRoutePointDeleted(holder); + } + else + { + // Call start drag listener on touch. + mManageRouteListener.startDrag(holder); + } + } + + return false; + }); + } + + @Override + public int getItemCount() + { + return mRoutePoints.size(); + } + + public void moveRoutePoint(int draggedItemIndex, int targetIndex) + { + if (draggedItemIndex == targetIndex) // Dragged to same spot. Do nothing. + return; + + Collections.swap(mRoutePoints, draggedItemIndex, targetIndex); + + updateRoutePointsData(); + + notifyItemMoved(draggedItemIndex, targetIndex); + } + + public void deleteRoutePoint(RecyclerView.ViewHolder viewHolder) + { + mRoutePoints.remove(viewHolder.getAbsoluteAdapterPosition()); + + updateRoutePointsData(); + + notifyItemRemoved(viewHolder.getAbsoluteAdapterPosition()); + } + + public void setMyLocationAsStartingPoint(MapObject myLocation) + { + String latLonString = StringUtils.formatUsingUsLocale("%.6f, %.6f", + myLocation.getLat(), + myLocation.getLon()); + + // Replace route point in first position with 'My Position". + mRoutePoints.set(0, new RouteMarkData(latLonString, "", RoutePointInfo.ROUTE_MARK_START, + 0, true, true, false, myLocation.getLat(), + myLocation.getLon())); + + // Update data. + updateRoutePointsData(); + + // Update adapter. + notifyItemChanged(0); + + // Show 'My location' crosshair button. + if (mManageRouteListener != null) + mManageRouteListener.showMyLocationIcon(true); + } + + private void updateMyLocationIcon() + { + boolean containsMyLocationPoint = false; + + for (RouteMarkData routePoint : mRoutePoints) + { + if (routePoint.mIsMyPosition) + { + containsMyLocationPoint = true; + break; + } + } + + if (mManageRouteListener != null) + mManageRouteListener.showMyLocationIcon(!containsMyLocationPoint); + } + + private void updateRoutePointsData() + { + assert(mRoutePoints.size() >= 2); + + // Set starting point. + mRoutePoints.get(0).mPointType = RoutePointInfo.ROUTE_MARK_START; + + // Set finish point. + mRoutePoints.get(mRoutePoints.size() - 1).mPointType = RoutePointInfo.ROUTE_MARK_FINISH; + + // Set intermediate point(s). + for (int pos = 1; pos < mRoutePoints.size() - 1; pos++) + { + mRoutePoints.get(pos).mPointType = RoutePointInfo.ROUTE_MARK_INTERMEDIATE; + mRoutePoints.get(pos).mIntermediateIndex = pos - 1; + } + } + + public ArrayList getRoutePoints() + { + return mRoutePoints; + } + + static class ManageRouteViewHolder extends RecyclerView.ViewHolder + { + @NonNull + public final View mItemView; + + @NonNull + public final ImageView mImageViewIcon; + + @NonNull + public final TextView mTextViewTitle; + + @NonNull + public final TextView mTextViewSubtitle; + + @NonNull + public final ImageView mImageViewDelete; + + ManageRouteViewHolder(@NonNull View itemView) + { + super(itemView); + mItemView = itemView; + mImageViewIcon = itemView.findViewById(R.id.type_icon); + mTextViewTitle = itemView.findViewById(R.id.title); + mTextViewSubtitle = itemView.findViewById(R.id.subtitle); + mImageViewDelete = itemView.findViewById(R.id.delete_icon); + } + } +} diff --git a/android/app/src/main/java/app/organicmaps/routing/ManageRouteBottomSheet.java b/android/app/src/main/java/app/organicmaps/routing/ManageRouteBottomSheet.java new file mode 100644 index 0000000000..0ca75f3c1d --- /dev/null +++ b/android/app/src/main/java/app/organicmaps/routing/ManageRouteBottomSheet.java @@ -0,0 +1,266 @@ +package app.organicmaps.routing; + +import android.app.Dialog; +import android.content.res.Resources; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.ItemTouchHelper; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import app.organicmaps.Framework; +import app.organicmaps.MwmApplication; +import app.organicmaps.R; +import app.organicmaps.bookmarks.data.MapObject; +import app.organicmaps.util.UiUtils; +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; +import com.google.android.material.divider.MaterialDividerItemDecoration; + +import java.util.ArrayList; + +import static androidx.recyclerview.widget.ItemTouchHelper.*; + +public class ManageRouteBottomSheet extends BottomSheetDialogFragment + implements View.OnClickListener, ManageRouteAdapter.ManageRouteListener +{ + ManageRouteAdapter mManageRouteAdapter; + ItemTouchHelper mTouchHelper; + ImageView mMyLocationImageView; + + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) + { + View v = inflater.inflate(R.layout.manage_route_bottom_sheet, container, false); + + Button cancelButton = v.findViewById(R.id.btn__cancel); + cancelButton.setOnClickListener(this); + + Button planButton = v.findViewById(R.id.btn__plan); + planButton.setOnClickListener(this); + + mMyLocationImageView = v.findViewById(R.id.image_my_location); + mMyLocationImageView.setOnClickListener(this); + + RecyclerView manageRouteList = v.findViewById(R.id.manage_route_list); + LinearLayoutManager layoutManager = new LinearLayoutManager(getContext()); + manageRouteList.setLayoutManager(layoutManager); + RecyclerView.ItemDecoration decoration = new MaterialDividerItemDecoration(getContext(), + layoutManager.getOrientation()); + manageRouteList.addItemDecoration(decoration); + + mManageRouteAdapter = new ManageRouteAdapter(getContext(), Framework.nativeGetRoutePoints(), this); + + manageRouteList.setAdapter(mManageRouteAdapter); + + // Enable drag & drop in route list. + mTouchHelper = new ItemTouchHelper(new ManageRouteItemTouchHelperCallback(mManageRouteAdapter, + getResources())); + mTouchHelper.attachToRecyclerView(manageRouteList); + + return v; + } + + @NonNull + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) + { + Dialog dialog = super.onCreateDialog(savedInstanceState); + + // Expand bottom sheet dialog. + dialog.setOnShowListener(dialogInterface -> { + + FrameLayout bottomSheet = ((BottomSheetDialog) dialogInterface).findViewById( + com.google.android.material.R.id.design_bottom_sheet); + + if (bottomSheet != null) + BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED); + }); + + // Set key listener to detect back button pressed. + dialog.setOnKeyListener((dialog1, keyCode, event) -> { + + if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) + { + // Dismiss the fragment + dismiss(); + return true; + } + + // Otherwise, do nothing else. + return false; + }); + + return dialog; + } + + @Override + public void onClick(View v) + { + int buttonId = v.getId(); + + if (buttonId == R.id.btn__cancel) + { + // Close dialog if 'Cancel' button is pressed. + dismiss(); + } + else if (buttonId == R.id.image_my_location) + { + // Get current location. + MapObject myLocation = MwmApplication.from(getContext()).getLocationHelper().getMyPosition(); + + // Set 'My Location' as starting point of the route. + if (myLocation != null) + mManageRouteAdapter.setMyLocationAsStartingPoint(myLocation); + } + else if (buttonId == R.id.btn__plan) + { + // Get route points from adapter. + ArrayList newRoutePoints = mManageRouteAdapter.getRoutePoints(); + + // Make sure that the new route contains at least 2 points (start and destination). + assert(newRoutePoints.size() >= 2); + + // Remove all existing route points. + Framework.nativeRemoveRoutePoints(); + + // First, add the destination point. + Framework.addRoutePoint(newRoutePoints.get(newRoutePoints.size() - 1)); + + // Secondly, add the starting point. + Framework.addRoutePoint(newRoutePoints.get(0)); + + // And then, add all intermediate points. + for (int pos = 1; pos < newRoutePoints.size() - 1; pos++) + Framework.addRoutePoint(newRoutePoints.get(pos)); + + // Intermediate route points are added sorted by distance. + // We have to make sure that they follow the requested order. + RouteMarkData[] finalRoutePoints = Framework.nativeGetRoutePoints(); + + for (int first = 1; first < newRoutePoints.size() - 1; first++) + { + int secondIndex = -1; + + for (int second = first; second < newRoutePoints.size() - 1; second++) + { + if (finalRoutePoints[first].equals(newRoutePoints.get(second))) + { + secondIndex = second; + break; + } + } + + if (secondIndex < 0) + { + // Something went bad. Intermediate point not found in the route points. + break; + } + + if (first != secondIndex) + { + // Intermediate point needs to be moved. + Framework.nativeMoveRoutePoint(secondIndex, first); + + // Refresh final route points. + finalRoutePoints = Framework.nativeGetRoutePoints(); + } + } + + // Launch route planning. + RoutingController.get().launchPlanning(); + + // Dismiss (close) manage route bottom sheet. + dismiss(); + } + } + + @Override + public void startDrag(RecyclerView.ViewHolder viewHolder) + { + // Start dragging. + mTouchHelper.startDrag(viewHolder); + } + + @Override + public void showMyLocationIcon(boolean showMyLocationIcon) + { + // Get current location. + MapObject myLocation = MwmApplication.from(getContext()).getLocationHelper().getMyPosition(); + + UiUtils.showIf(showMyLocationIcon && myLocation != null, mMyLocationImageView); + } + + @Override + public void onRoutePointDeleted(RecyclerView.ViewHolder viewHolder) + { + mManageRouteAdapter.deleteRoutePoint(viewHolder); + + mManageRouteAdapter.notifyDataSetChanged(); + } + + private static class ManageRouteItemTouchHelperCallback extends ItemTouchHelper.Callback + { + private final ManageRouteAdapter mManageRouteAdapter; + + public ManageRouteItemTouchHelperCallback(ManageRouteAdapter adapter, Resources resources) + { + mManageRouteAdapter = adapter; + } + + @Override + public int getMovementFlags(@NonNull RecyclerView recyclerView, + @NonNull RecyclerView.ViewHolder viewHolder) + { + // Enable up & down dragging. No left-right swiping is enabled. + return makeMovementFlags(UP | DOWN, 0); + } + + @Override + public boolean isLongPressDragEnabled() + { + return false; + } + + @Override + public boolean isItemViewSwipeEnabled() + { + return false; + } + + @Override + public boolean onMove(@NonNull RecyclerView recyclerView, + @NonNull RecyclerView.ViewHolder viewHolder, + @NonNull RecyclerView.ViewHolder target) + { + mManageRouteAdapter.moveRoutePoint(viewHolder.getAbsoluteAdapterPosition(), + target.getAbsoluteAdapterPosition()); + return true; + } + + @Override + public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) + { + } + + @Override + public void clearView(@NonNull RecyclerView recyclerView, + @NonNull RecyclerView.ViewHolder viewHolder) + { + super.clearView(recyclerView, viewHolder); + + // Called when dragging action has finished. + mManageRouteAdapter.notifyDataSetChanged(); + } + } +} diff --git a/android/app/src/main/java/app/organicmaps/routing/RouteMarkData.java b/android/app/src/main/java/app/organicmaps/routing/RouteMarkData.java index 8004267f80..33b1300e04 100644 --- a/android/app/src/main/java/app/organicmaps/routing/RouteMarkData.java +++ b/android/app/src/main/java/app/organicmaps/routing/RouteMarkData.java @@ -16,8 +16,8 @@ public class RouteMarkData @Nullable public final String mSubtitle; @RoutePointInfo.RouteMarkType - public final int mPointType; - public final int mIntermediateIndex; + public int mPointType; + public int mIntermediateIndex; public final boolean mIsVisible; public final boolean mIsMyPosition; public final boolean mIsPassed; @@ -39,4 +39,12 @@ public class RouteMarkData mLat = lat; mLon = lon; } + + public boolean equals(RouteMarkData other) + { + return mTitle != null && other.mTitle != null && + mTitle.compareTo(other.mTitle) == 0 && + mSubtitle != null && other.mSubtitle != null && + mSubtitle.compareTo(other.mSubtitle) == 0; + } } diff --git a/android/app/src/main/java/app/organicmaps/routing/RoutingBottomMenuController.java b/android/app/src/main/java/app/organicmaps/routing/RoutingBottomMenuController.java index 748cb17855..e9745a52b5 100644 --- a/android/app/src/main/java/app/organicmaps/routing/RoutingBottomMenuController.java +++ b/android/app/src/main/java/app/organicmaps/routing/RoutingBottomMenuController.java @@ -151,6 +151,8 @@ final class RoutingBottomMenuController implements View.OnClickListener Resources res = mContext.getResources(); mTransitViewDecorator = new DotDividerItemDecoration(dividerDrawable, res.getDimensionPixelSize(R.dimen.margin_base), res.getDimensionPixelSize(R.dimen.margin_half)); + Button manageRouteButton = altitudeChartFrame.findViewById(R.id.btn__manage_route); + manageRouteButton.setOnClickListener(this); } void showAltitudeChartAndRoutingDetails() @@ -253,7 +255,7 @@ final class RoutingBottomMenuController implements View.OnClickListener if (LocationHelper.from(mContext).getMyPosition() != null) { UiUtils.show(mActionButton); - Drawable icon = ContextCompat.getDrawable(mContext, R.drawable.ic_my_location); + Drawable icon = ContextCompat.getDrawable(mContext, R.drawable.ic_location_crosshair); int colorAccent = ContextCompat.getColor(mContext, UiUtils.getStyledResourceId(mContext, androidx.appcompat.R.attr.colorAccent)); mActionIcon.setImageDrawable(Graphics.tint(icon, colorAccent)); @@ -485,5 +487,7 @@ final class RoutingBottomMenuController implements View.OnClickListener int pointType = (Integer) mActionMessage.getTag(); mListener.onSearchRoutePoint(pointType); } + else if (id == R.id.btn__manage_route && mListener != null) + mListener.onManageRouteOpen(); } } diff --git a/android/app/src/main/java/app/organicmaps/routing/RoutingBottomMenuListener.java b/android/app/src/main/java/app/organicmaps/routing/RoutingBottomMenuListener.java index 70b2238a76..135f6b3213 100644 --- a/android/app/src/main/java/app/organicmaps/routing/RoutingBottomMenuListener.java +++ b/android/app/src/main/java/app/organicmaps/routing/RoutingBottomMenuListener.java @@ -5,4 +5,5 @@ public interface RoutingBottomMenuListener void onUseMyPositionAsStart(); void onSearchRoutePoint(@RoutePointInfo.RouteMarkType int type); void onRoutingStart(); + void onManageRouteOpen(); } diff --git a/android/app/src/main/java/app/organicmaps/routing/RoutingController.java b/android/app/src/main/java/app/organicmaps/routing/RoutingController.java index ac5df5fa8f..1abbf6fc4c 100644 --- a/android/app/src/main/java/app/organicmaps/routing/RoutingController.java +++ b/android/app/src/main/java/app/organicmaps/routing/RoutingController.java @@ -404,6 +404,17 @@ public class RoutingController resetToPlanningStateIfNavigating(); } + public void launchPlanning() + { + build(); + setState(State.PREPARE); + startPlanning(); + if (mContainer != null) + mContainer.updateMenu(); + if (mContainer != null) + mContainer.onResetToPlanningState(); + } + /** * @return False if not navigating, true otherwise */ diff --git a/android/app/src/main/res/drawable/ic_location_arrow_blue.xml b/android/app/src/main/res/drawable/ic_location_arrow_blue.xml new file mode 100644 index 0000000000..0be38e62d0 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_location_arrow_blue.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/ic_my_location.xml b/android/app/src/main/res/drawable/ic_location_crosshair.xml similarity index 100% rename from android/app/src/main/res/drawable/ic_my_location.xml rename to android/app/src/main/res/drawable/ic_location_crosshair.xml diff --git a/android/app/src/main/res/drawable/ic_location_crosshair_blue.xml b/android/app/src/main/res/drawable/ic_location_crosshair_blue.xml new file mode 100644 index 0000000000..aa23f65a1b --- /dev/null +++ b/android/app/src/main/res/drawable/ic_location_crosshair_blue.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/ic_manage_route.xml b/android/app/src/main/res/drawable/ic_manage_route.xml new file mode 100644 index 0000000000..fd1ba2b93d --- /dev/null +++ b/android/app/src/main/res/drawable/ic_manage_route.xml @@ -0,0 +1,28 @@ + + + + diff --git a/android/app/src/main/res/layout-land/altitude_chart_panel.xml b/android/app/src/main/res/layout-land/altitude_chart_panel.xml index d1080a5e53..1eac5978aa 100644 --- a/android/app/src/main/res/layout-land/altitude_chart_panel.xml +++ b/android/app/src/main/res/layout-land/altitude_chart_panel.xml @@ -63,6 +63,16 @@ tools:text="5 h 55 min • 1555km" tools:visibility="visible" /> +