Implement Track Selection and elevation info display on PP

Signed-off-by: kavikhalique <kavikhalique3@gmail.com>
This commit is contained in:
kavikhalique
2025-07-25 22:45:32 +05:30
committed by Konstantin Pastbin
parent ebb7c45d1a
commit f1628c70bc
41 changed files with 1181 additions and 436 deletions

View File

@@ -10,6 +10,8 @@ import androidx.core.content.ContextCompat;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
import app.organicmaps.sdk.bookmarks.data.ElevationInfo;
import app.organicmaps.sdk.bookmarks.data.Track;
import app.organicmaps.sdk.bookmarks.data.TrackStatistics;
import app.organicmaps.util.ThemeUtils;
import app.organicmaps.util.Utils;
import app.organicmaps.widget.placepage.AxisValueFormatter;
@@ -31,9 +33,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class ChartController implements OnChartValueSelectedListener,
BookmarkManager.OnElevationActivePointChangedListener,
BookmarkManager.OnElevationCurrentPositionChangedListener
public class ChartController implements OnChartValueSelectedListener
{
private static final int CHART_Y_LABEL_COUNT = 3;
private static final int CHART_X_LABEL_COUNT = 6;
@@ -42,6 +42,7 @@ public class ChartController implements OnChartValueSelectedListener,
private static final int CHART_AXIS_GRANULARITY = 100;
private static final float CUBIC_INTENSITY = 0.2f;
private static final int CURRENT_POSITION_OUT_OF_TRACK = -1;
private static final String ELEVATION_PROFILE_POINTS = "ELEVATION_PROFILE_POINTS";
@SuppressWarnings("NullableProblems")
@NonNull
@@ -62,6 +63,7 @@ public class ChartController implements OnChartValueSelectedListener,
private final Context mContext;
private long mTrackId = Utils.INVALID_ID;
private boolean mCurrentPositionOutOfTrack = true;
private boolean mInformSelectedActivePointToCore = true;
public ChartController(@NonNull Context context)
{
@@ -70,8 +72,6 @@ public class ChartController implements OnChartValueSelectedListener,
public void initialize(@NonNull View view)
{
BookmarkManager.INSTANCE.setElevationActivePointChangedListener(this);
BookmarkManager.INSTANCE.setElevationCurrentPositionChangedListener(this);
final Resources resources = mContext.getResources();
mChart = view.findViewById(R.id.elevation_profile_chart);
@@ -101,13 +101,6 @@ public class ChartController implements OnChartValueSelectedListener,
initAxises();
}
@SuppressWarnings("unused")
public void destroy()
{
BookmarkManager.INSTANCE.setElevationActivePointChangedListener(null);
BookmarkManager.INSTANCE.setElevationCurrentPositionChangedListener(null);
}
private void highlightChartCurrentLocation()
{
mChart.highlightValues(Collections.singletonList(getCurrentPosHighlight()),
@@ -142,15 +135,17 @@ public class ChartController implements OnChartValueSelectedListener,
mChart.getAxisRight().setEnabled(false);
}
public void setData(@NonNull ElevationInfo info)
public void setData(Track track)
{
mTrackId = info.getId();
mTrackId = track.getTrackId();
ElevationInfo info = track.getElevationInfo();
TrackStatistics stats = track.getTrackStatistics();
List<Entry> values = new ArrayList<>();
for (ElevationInfo.Point point : info.getPoints())
values.add(new Entry((float) point.getDistance(), point.getAltitude()));
values.add(new Entry((float) point.getDistance(), point.getAltitude(), point));
LineDataSet set = new LineDataSet(values, "Elevation_profile_points");
LineDataSet set = new LineDataSet(values, ELEVATION_PROFILE_POINTS);
set.setMode(LineDataSet.Mode.CUBIC_BEZIER);
set.setCubicIntensity(CUBIC_INTENSITY);
set.setDrawFilled(true);
@@ -173,8 +168,8 @@ public class ChartController implements OnChartValueSelectedListener,
mChart.setData(data);
mChart.animateX(CHART_ANIMATION_DURATION);
mMinAltitude.setText(Framework.nativeFormatAltitude(info.getMinAltitude()));
mMaxAltitude.setText(Framework.nativeFormatAltitude(info.getMaxAltitude()));
mMinAltitude.setText(Framework.nativeFormatAltitude(stats.getMinElevation()));
mMaxAltitude.setText(Framework.nativeFormatAltitude(stats.getMaxElevation()));
highlightActivePointManually();
}
@@ -192,7 +187,9 @@ public class ChartController implements OnChartValueSelectedListener,
if (mTrackId == Utils.INVALID_ID)
return;
BookmarkManager.INSTANCE.setElevationActivePoint(mTrackId, e.getX());
if (mInformSelectedActivePointToCore)
BookmarkManager.INSTANCE.setElevationActivePoint(mTrackId, e.getX(), (ElevationInfo.Point) e.getData());
mInformSelectedActivePointToCore = true;
}
@NonNull
@@ -211,7 +208,6 @@ public class ChartController implements OnChartValueSelectedListener,
highlightChartCurrentLocation();
}
@Override
public void onCurrentPositionChanged()
{
if (mTrackId == Utils.INVALID_ID)
@@ -222,7 +218,6 @@ public class ChartController implements OnChartValueSelectedListener,
highlightActivePointManually();
}
@Override
public void onElevationActivePointChanged()
{
if (mTrackId == Utils.INVALID_ID)
@@ -234,6 +229,7 @@ public class ChartController implements OnChartValueSelectedListener,
private void highlightActivePointManually()
{
Highlight highlight = getActivePoint();
mInformSelectedActivePointToCore = false;
mChart.highlightValue(highlight, true);
}

View File

@@ -2,6 +2,7 @@ package app.organicmaps.sdk.bookmarks.data;
import android.annotation.SuppressLint;
import android.os.Parcel;
import androidx.annotation.ColorInt;
import androidx.annotation.IntRange;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
@@ -110,6 +111,14 @@ public class Bookmark extends MapObject
mCategoryId = catId;
}
public void setIconColor(@ColorInt int color)
{
Icon icon = new Icon(PredefinedColors.getPredefinedColorIndex(color),
BookmarkManager.INSTANCE.getBookmarkIcon(mBookmarkId));
BookmarkManager.INSTANCE.notifyParametersUpdating(this, getName(), icon, getBookmarkDescription());
mIcon = icon;
}
public void setParams(@NonNull String title, @Nullable Icon icon, @NonNull String description)
{
BookmarkManager.INSTANCE.notifyParametersUpdating(this, title, icon, description);

View File

@@ -263,6 +263,12 @@ public enum BookmarkManager {
return nativeUpdateBookmarkPlacePage(bmkId);
}
@Nullable
public void updateTrackPlacePage(long trackId)
{
nativeUpdateTrackPlacePage(trackId);
}
@Nullable
public BookmarkInfo getBookmarkInfo(long bmkId)
{
@@ -729,9 +735,9 @@ public enum BookmarkManager {
return nativeGetElevationCurPositionDistance(trackId);
}
public void setElevationActivePoint(long trackId, double distance)
public void setElevationActivePoint(long trackId, double distance, ElevationInfo.Point point)
{
nativeSetElevationActivePoint(trackId, distance);
nativeSetElevationActivePoint(trackId, distance, point.getLatitude(), point.getLongitude());
}
public double getElevationActivePointDistance(long trackId)
@@ -739,9 +745,14 @@ public enum BookmarkManager {
return nativeGetElevationActivePointDistance(trackId);
}
private static native ElevationInfo.Point nativeGetElevationActivePointCoordinates(long trackId);
@Nullable
private native Bookmark nativeUpdateBookmarkPlacePage(long bmkId);
@Nullable
private native void nativeUpdateTrackPlacePage(long trackId);
@Nullable
private native BookmarkInfo nativeGetBookmarkInfo(long bmkId);
@@ -892,14 +903,25 @@ public enum BookmarkManager {
public static native void nativeRemoveElevationCurrentPositionChangedListener();
private static native void nativeSetElevationActivePoint(long trackId, double distanceInMeters);
private static native void nativeSetElevationActivePoint(long trackId, double distanceInMeters, double latitude,
double longitude);
private static native double nativeGetElevationActivePointDistance(long trackId);
public ElevationInfo.Point getElevationActivePointCoordinates(long trackId)
{
return nativeGetElevationActivePointCoordinates(trackId);
}
private static native void nativeSetElevationActiveChangedListener();
public static native void nativeRemoveElevationActiveChangedListener();
public static native ElevationInfo nativeGetTrackElevationInfo(long trackId);
public static native boolean nativeIsElevationInfoHasValue(long trackId);
public static native TrackStatistics nativeGetTrackStatistics(long trackId);
public interface BookmarksLoadingListener
{
default void onBookmarksLoadingStarted() {}

View File

@@ -15,42 +15,19 @@ import java.util.List;
@SuppressWarnings("unused")
public class ElevationInfo implements PlacePageData
{
private final long mId;
@NonNull
private final String mName;
@NonNull
private final List<Point> mPoints;
private final int mAscent;
private final int mDescent;
private final int mMinAltitude;
private final int mMaxAltitude;
private final int mDifficulty;
private final long mDuration;
public ElevationInfo(long trackId, @NonNull String name, @NonNull Point[] points, int ascent, int descent,
int minAltitude, int maxAltitude, int difficulty, long duration)
public ElevationInfo(@NonNull Point[] points, int difficulty)
{
mId = trackId;
mName = name;
mPoints = Arrays.asList(points);
mAscent = ascent;
mDescent = descent;
mMinAltitude = minAltitude;
mMaxAltitude = maxAltitude;
mDifficulty = difficulty;
mDuration = duration;
}
protected ElevationInfo(Parcel in)
{
mId = in.readLong();
mName = in.readString();
mAscent = in.readInt();
mDescent = in.readInt();
mMinAltitude = in.readInt();
mMaxAltitude = in.readInt();
mDifficulty = in.readInt();
mDuration = in.readLong();
mPoints = readPoints(in);
}
@@ -62,53 +39,17 @@ public class ElevationInfo implements PlacePageData
return points;
}
public long getId()
{
return mId;
}
@NonNull
public String getName()
{
return mName;
}
@NonNull
public List<Point> getPoints()
{
return Collections.unmodifiableList(mPoints);
}
public int getAscent()
{
return mAscent;
}
public int getDescent()
{
return mDescent;
}
public int getMinAltitude()
{
return mMinAltitude;
}
public int getMaxAltitude()
{
return mMaxAltitude;
}
public int getDifficulty()
{
return mDifficulty;
}
public long getDuration()
{
return mDuration;
}
@Override
public int describeContents()
{
@@ -118,14 +59,7 @@ public class ElevationInfo implements PlacePageData
@Override
public void writeToParcel(Parcel dest, int flags)
{
dest.writeLong(mId);
dest.writeString(mName);
dest.writeInt(mAscent);
dest.writeInt(mDescent);
dest.writeInt(mMinAltitude);
dest.writeInt(mMaxAltitude);
dest.writeInt(mDifficulty);
dest.writeLong(mDuration);
// All collections are deserialized AFTER non-collection and primitive type objects,
// so collections must be always serialized at the end.
dest.writeTypedList(mPoints);
@@ -138,17 +72,23 @@ public class ElevationInfo implements PlacePageData
{
private final double mDistance;
private final int mAltitude;
private final double mLatitude;
private final double mLongitude;
public Point(double distance, int altitude)
public Point(double distance, int altitude, double latitude, double longitude)
{
mDistance = distance;
mAltitude = altitude;
mLatitude = latitude;
mLongitude = longitude;
}
protected Point(Parcel in)
{
mDistance = in.readDouble();
mAltitude = in.readInt();
mLatitude = in.readDouble();
mLongitude = in.readDouble();
}
public static final Creator<Point> CREATOR = new Creator<>() {
@@ -175,6 +115,16 @@ public class ElevationInfo implements PlacePageData
return mAltitude;
}
public double getLatitude()
{
return mLatitude;
}
public double getLongitude()
{
return mLongitude;
}
@Override
public int describeContents()
{

View File

@@ -25,7 +25,7 @@ import java.util.Objects;
public class MapObject implements PlacePageData
{
@Retention(RetentionPolicy.SOURCE)
@IntDef({POI, API_POINT, BOOKMARK, MY_POSITION, SEARCH})
@IntDef({POI, API_POINT, BOOKMARK, MY_POSITION, SEARCH, TRACK})
public @interface MapObjectType
{}
@@ -34,6 +34,7 @@ public class MapObject implements PlacePageData
public static final int BOOKMARK = 2;
public static final int MY_POSITION = 3;
public static final int SEARCH = 4;
public static final int TRACK = 5;
@Retention(RetentionPolicy.SOURCE)
@IntDef({OPENING_MODE_PREVIEW, OPENING_MODE_PREVIEW_PLUS, OPENING_MODE_DETAILS, OPENING_MODE_FULL})
@@ -315,6 +316,11 @@ public class MapObject implements PlacePageData
return mMapObjectType == BOOKMARK;
}
public final boolean isTrack()
{
return mMapObjectType == TRACK;
}
@Nullable
public RoutePointInfo getRoutePointInfo()
{

View File

@@ -1,21 +1,32 @@
package app.organicmaps.sdk.bookmarks.data;
import androidx.annotation.IntRange;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import app.organicmaps.sdk.routing.RoutePointInfo;
import app.organicmaps.sdk.search.Popularity;
import app.organicmaps.sdk.util.Distance;
// Called from JNI.
@Keep
@SuppressWarnings("unused")
public class Track
public class Track extends MapObject
{
private final long mTrackId;
private final long mCategoryId;
private long mCategoryId;
private final String mName;
private final Distance mLength;
private final int mColor;
private int mColor;
@Nullable
private ElevationInfo mElevationInfo;
@Nullable
private TrackStatistics mTrackStatistics;
Track(long trackId, long categoryId, String name, Distance length, int color)
{
super(FeatureId.fromFeatureIdString("1:2:3"), TRACK, name, "", "", "", 0, 0, "", null, OPENING_MODE_PREVIEW_PLUS,
null, "", RoadWarningMarkType.UNKNOWN.ordinal(), null);
mTrackId = trackId;
mCategoryId = categoryId;
mName = name;
@@ -23,6 +34,34 @@ public class Track
mColor = color;
}
// used by JNI
Track(@NonNull FeatureId featureId, @IntRange(from = 0) long categoryId, @IntRange(from = 0) long trackId,
String title, @Nullable String secondaryTitle, @Nullable String subtitle, @Nullable String address,
@Nullable RoutePointInfo routePointInfo, @OpeningMode int openingMode, @NonNull Popularity popularity,
@NonNull String description, @Nullable String[] rawTypes, int color, Distance length, double lat, double lon)
{
super(featureId, TRACK, title, secondaryTitle, subtitle, address, lat, lon, "", routePointInfo, openingMode,
popularity, description, RoadWarningMarkType.UNKNOWN.ordinal(), rawTypes);
mTrackId = trackId;
mCategoryId = categoryId;
mColor = color;
mName = title;
mLength = length;
}
// modifying this categoryId will not change the core data
// its just for temporary changes
public void setCategoryId(@NonNull long categoryId)
{
mCategoryId = categoryId;
}
public void setColor(@NonNull int color)
{
mColor = color;
BookmarkManager.INSTANCE.changeTrackColor(getTrackId(), color);
}
public String getName()
{
return mName;
@@ -52,4 +91,25 @@ public class Track
{
return BookmarkManager.INSTANCE.getTrackDescription(mTrackId);
}
public ElevationInfo getElevationInfo()
{
if (mElevationInfo != null)
return mElevationInfo;
mElevationInfo = BookmarkManager.nativeGetTrackElevationInfo(mTrackId);
return mElevationInfo;
}
public boolean isElevationInfoHasValue()
{
return BookmarkManager.nativeIsElevationInfoHasValue(mTrackId);
}
public TrackStatistics getTrackStatistics()
{
if (mTrackStatistics != null)
return mTrackStatistics;
mTrackStatistics = BookmarkManager.nativeGetTrackStatistics(mTrackId);
return mTrackStatistics;
}
}

View File

@@ -0,0 +1,57 @@
package app.organicmaps.sdk.bookmarks.data;
import androidx.annotation.Keep;
// Used by JNI
@Keep
public class TrackStatistics
{
private final double m_length;
private final double m_duration;
private final double m_ascent;
private final double m_descent;
private final int m_minElevation;
private final int m_maxElevation;
@Keep
public TrackStatistics(double length, double duration, double ascent, double descent, int minElevation,
int maxElevation)
{
m_length = length;
m_duration = duration;
m_ascent = ascent;
m_descent = descent;
m_minElevation = minElevation;
m_maxElevation = maxElevation;
}
public double getLength()
{
return m_length;
}
public double getDuration()
{
return m_duration;
}
public double getAscent()
{
return m_ascent;
}
public double getDescent()
{
return m_descent;
}
public int getMinElevation()
{
return m_minElevation;
}
public int getMaxElevation()
{
return m_maxElevation;
}
}

View File

@@ -1,7 +1,7 @@
package app.organicmaps.widget.placepage;
import androidx.annotation.NonNull;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.util.StringUtils;
import com.github.mikephil.charting.charts.BarLineChartBase;
import com.github.mikephil.charting.formatter.DefaultValueFormatter;
@@ -20,6 +20,6 @@ public class AxisValueFormatter extends DefaultValueFormatter
@Override
public String getFormattedValue(float value)
{
return Framework.nativeFormatAltitude(value);
return StringUtils.nativeFormatDistance(value).toString(mChart.getContext());
}
}

View File

@@ -1,7 +1,6 @@
package app.organicmaps.widget.placepage;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
@@ -12,18 +11,19 @@ import app.organicmaps.ChartController;
import app.organicmaps.R;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.bookmarks.data.ElevationInfo;
import app.organicmaps.sdk.bookmarks.data.Track;
import app.organicmaps.sdk.bookmarks.data.TrackStatistics;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.sdk.widget.placepage.PlacePageData;
import app.organicmaps.util.Utils;
import java.util.Objects;
@SuppressWarnings("unused") // https://github.com/organicmaps/organicmaps/issues/2829
public class ElevationProfileViewRenderer implements PlacePageStateListener
{
// Must be correspond to map/elevation_info.hpp constants.
private static final int MAX_DIFFICULTY_LEVEL = 3;
private static final int UNKNOWN_DIFFICULTY = 0;
@NonNull
private final View[] mDifficultyLevels = new View[MAX_DIFFICULTY_LEVEL];
@SuppressWarnings("NullableProblems")
@NonNull
private NestedScrollView mScrollView;
@@ -45,8 +45,6 @@ public class ElevationProfileViewRenderer implements PlacePageStateListener
@SuppressWarnings("NullableProblems")
@NonNull
private TextView mTime;
@NonNull
private final View[] mDifficultyLevels = new View[MAX_DIFFICULTY_LEVEL];
@SuppressWarnings("NullableProblems")
@NonNull
private ChartController mChartController;
@@ -58,23 +56,7 @@ public class ElevationProfileViewRenderer implements PlacePageStateListener
@SuppressWarnings("NullableProblems")
@NonNull
private View mTimeContainer;
public void render(@NonNull PlacePageData data)
{
final Context context = mAscent.getContext();
mElevationInfo = (ElevationInfo) data;
mChartController.setData(mElevationInfo);
mTitle.setText(mElevationInfo.getName());
setDifficulty(mElevationInfo.getDifficulty());
mAscent.setText(formatDistance(context, mElevationInfo.getAscent()));
mDescent.setText(formatDistance(context, mElevationInfo.getDescent()));
mMaxAltitude.setText(formatDistance(context, mElevationInfo.getMaxAltitude()));
mMinAltitude.setText(formatDistance(context, mElevationInfo.getMinAltitude()));
UiUtils.hideIf(mElevationInfo.getDuration() == 0, mTimeContainer);
mTime.setText(
Utils.formatRoutingTime(mTitle.getContext(), (int) mElevationInfo.getDuration(), R.dimen.text_size_body_2));
}
private View mTitleContainer;
@NonNull
private static String formatDistance(final Context context, int distance)
@@ -82,6 +64,24 @@ public class ElevationProfileViewRenderer implements PlacePageStateListener
return Framework.nativeFormatAltitude(distance);
}
public void render(@NonNull Track track)
{
final Context context = mAscent.getContext();
TrackStatistics stats = track.getTrackStatistics();
mElevationInfo = track.getElevationInfo();
mChartController.setData(track);
UiUtils.hide(mTitleContainer);
mTitle.setText(track.getName());
setDifficulty(mElevationInfo.getDifficulty());
mAscent.setText(formatDistance(context, (int) stats.getAscent()));
mDescent.setText(formatDistance(context, (int) stats.getDescent()));
mMaxAltitude.setText(formatDistance(context, stats.getMaxElevation()));
mMinAltitude.setText(formatDistance(context, stats.getMinElevation()));
UiUtils.hide(mTimeContainer);
mTime.setText(Utils.formatRoutingTime(mAscent.getContext(), (int) stats.getDuration(), R.dimen.text_size_body_2));
}
public void initialize(@Nullable View view)
{
Objects.requireNonNull(view);
@@ -89,6 +89,7 @@ public class ElevationProfileViewRenderer implements PlacePageStateListener
mChartController.initialize(view);
mScrollView = (NestedScrollView) view;
mTitle = view.findViewById(R.id.title);
mTitleContainer = view.findViewById(R.id.title_container);
mAscent = view.findViewById(R.id.ascent);
mDescent = view.findViewById(R.id.descent);
mMaxAltitude = view.findViewById(R.id.max_altitude);
@@ -123,21 +124,13 @@ public class ElevationProfileViewRenderer implements PlacePageStateListener
mDifficultyLevels[i].setEnabled(true);
}
public void onSave(@NonNull Bundle outState)
public void onChartElevationActivePointChanged()
{
// outState.putParcelable(PlacePageUtils.EXTRA_PLACE_PAGE_DATA, mElevationInfo);
mChartController.onElevationActivePointChanged();
}
public void onRestore(@NonNull Bundle inState)
public void onChartCurrentPositionChanged()
{
// mElevationInfo = BundleCompat.getParcelable(inState, PlacePageUtils.EXTRA_PLACE_PAGE_DATA,
// ElevationInfo.class); if (mElevationInfo != null)
// render(mElevationInfo);
}
public void onHide()
{
mScrollView.scrollTo(0, 0);
mChartController.onHide();
mChartController.onCurrentPositionChanged();
}
}

View File

@@ -37,9 +37,6 @@ public class FloatingMarkerView extends RelativeLayout implements IMarker
private TextView mAltitudeView;
@SuppressWarnings("NullableProblems")
@NonNull
private TextView mDistanceTextView;
@SuppressWarnings("NullableProblems")
@NonNull
private TextView mDistanceValueView;
@SuppressWarnings("NullableProblems")
@NonNull
@@ -93,7 +90,6 @@ public class FloatingMarkerView extends RelativeLayout implements IMarker
mTextContentContainer = findViewById(R.id.floating_text_container);
mFloatingTriangle = findViewById(R.id.floating_triangle);
mImage = findViewById(R.id.image);
mDistanceTextView = findViewById(R.id.distance_text);
mAltitudeView = findViewById(R.id.altitude);
mDistanceValueView = findViewById(R.id.distance_value);
}
@@ -125,7 +121,7 @@ public class FloatingMarkerView extends RelativeLayout implements IMarker
public void updateOffsets(@NonNull Entry entry, @NonNull Highlight highlight)
{
updateVertical(entry);
final float halfImg = Math.abs(mImage.getWidth()) / 2f;
final float halfImg = mImage.getResources().getDimensionPixelSize(R.dimen.elevation_profile_marker_width) / 2f;
boolean isLeftToRightDirection = isInvertedOrder(highlight);
mOffset = isLeftToRightDirection ? -getWidth() + halfImg : -halfImg;
updateHorizontal(highlight);
@@ -184,7 +180,6 @@ public class FloatingMarkerView extends RelativeLayout implements IMarker
private void updatePointValues(@NonNull Entry entry)
{
mDistanceTextView.setText(R.string.elevation_profile_distance);
mDistanceValueView.setText(
StringUtils.nativeFormatDistance(entry.getX()).toString(mDistanceValueView.getContext()));
mAltitudeView.setText(Framework.nativeFormatAltitude(entry.getY()));

View File

@@ -34,6 +34,11 @@ public class PlacePageButtonFactory
titleId = R.string.delete;
yield R.drawable.ic_bookmarks_on;
}
case TRACK_DELETE ->
{
titleId = R.string.delete;
yield R.drawable.ic_delete;
}
case ROUTE_FROM ->
{
titleId = R.string.p2p_from_here;

View File

@@ -136,6 +136,7 @@ public final class PlacePageButtons extends Fragment implements Observer<List<Pl
BACK,
BOOKMARK_SAVE,
BOOKMARK_DELETE,
TRACK_DELETE,
ROUTE_FROM,
ROUTE_TO,
ROUTE_ADD,

View File

@@ -2,6 +2,7 @@ package app.organicmaps.widget.placepage;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.app.Dialog;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
@@ -30,6 +31,7 @@ import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
import app.organicmaps.sdk.bookmarks.data.MapObject;
import app.organicmaps.sdk.bookmarks.data.RoadWarningMarkType;
import app.organicmaps.sdk.bookmarks.data.Track;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.settings.RoadType;
import app.organicmaps.sdk.util.UiUtils;
@@ -38,6 +40,7 @@ import app.organicmaps.util.ThemeUtils;
import app.organicmaps.util.bottomsheet.MenuBottomSheetFragment;
import app.organicmaps.util.bottomsheet.MenuBottomSheetItem;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.shape.MaterialShapeDrawable;
import java.util.ArrayList;
import java.util.List;
@@ -74,6 +77,7 @@ public class PlacePageController
private ValueAnimator mCustomPeekHeightAnimator;
private PlacePageRouteSettingsListener mPlacePageRouteSettingsListener;
private Dialog mAlertDialog;
private final Observer<Integer> mPlacePageDistanceToTopObserver = new Observer<>() {
private float mPlacePageCornerRadius;
@@ -120,7 +124,6 @@ public class PlacePageController
bg.setCornerSize(mPlacePageCornerRadius);
}
};
private final BottomSheetBehavior.BottomSheetCallback mDefaultBottomSheetCallback =
new BottomSheetBehavior.BottomSheetCallback() {
@Override
@@ -145,6 +148,18 @@ public class PlacePageController
}
};
@NonNull
private static PlacePageButtons.ButtonType toPlacePageButton(@NonNull RoadWarningMarkType type)
{
return switch (type)
{
case DIRTY -> PlacePageButtons.ButtonType.ROUTE_AVOID_UNPAVED;
case FERRY -> PlacePageButtons.ButtonType.ROUTE_AVOID_FERRY;
case TOLL -> PlacePageButtons.ButtonType.ROUTE_AVOID_TOLL;
default -> throw new AssertionError("Unsupported road warning type: " + type);
};
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@@ -202,18 +217,6 @@ public class PlacePageController
ViewCompat.requestApplyInsets(mPlacePage);
}
@NonNull
private static PlacePageButtons.ButtonType toPlacePageButton(@NonNull RoadWarningMarkType type)
{
return switch (type)
{
case DIRTY -> PlacePageButtons.ButtonType.ROUTE_AVOID_UNPAVED;
case FERRY -> PlacePageButtons.ButtonType.ROUTE_AVOID_FERRY;
case TOLL -> PlacePageButtons.ButtonType.ROUTE_AVOID_TOLL;
default -> throw new AssertionError("Unsupported road warning type: " + type);
};
}
private void stopCustomPeekHeightAnimation()
{
if (mCustomPeekHeightAnimator != null && mCustomPeekHeightAnimator.isStarted())
@@ -415,6 +418,7 @@ public class PlacePageController
switch (item)
{
case BOOKMARK_SAVE, BOOKMARK_DELETE -> onBookmarkBtnClicked();
case TRACK_DELETE -> onTrackRemoveClicked();
case BACK -> onBackBtnClicked();
case ROUTE_FROM -> onRouteFromBtnClicked();
case ROUTE_TO -> onRouteToBtnClicked();
@@ -439,6 +443,48 @@ public class PlacePageController
BookmarkManager.INSTANCE.addNewBookmark(mMapObject.getLat(), mMapObject.getLon());
}
private void onTrackRemoveClicked()
{
// mMapObject is set to null when the place page closes
// We don't want users to interact with the buttons when the PP is closing
if (mMapObject == null)
return;
showTrackDeleteAlertDialog();
}
void showTrackDeleteAlertDialog()
{
if (mMapObject == null)
return;
if (mAlertDialog != null)
{
mAlertDialog.dismiss();
mAlertDialog.show();
mViewModel.isAlertDialogShowing = true;
return;
}
mViewModel.isAlertDialogShowing = true;
mAlertDialog = new MaterialAlertDialogBuilder(requireContext(), R.style.MwmTheme_AlertDialog)
.setTitle("Would you like to delete " + mMapObject.getTitle() + "?")
.setCancelable(true)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton("delete",
(dialog, which) -> {
BookmarkManager.INSTANCE.deleteTrack(((Track) mMapObject).getTrackId());
close();
})
.setOnDismissListener(dialog -> dismissAlertDialog())
.show();
}
void dismissAlertDialog()
{
if (mAlertDialog == null)
return;
mAlertDialog.dismiss();
mViewModel.isAlertDialogShowing = false;
}
private void onBackBtnClicked()
{
if (mMapObject == null)
@@ -577,8 +623,12 @@ public class PlacePageController
if (needToShowRoutingButtons && RoutingController.get().isStopPointAllowed())
buttons.add(PlacePageButtons.ButtonType.ROUTE_ADD);
else
{
buttons.add(mapObject.isBookmark() ? PlacePageButtons.ButtonType.BOOKMARK_DELETE
: PlacePageButtons.ButtonType.BOOKMARK_SAVE);
if (mapObject.isTrack())
buttons.add(PlacePageButtons.ButtonType.TRACK_DELETE);
}
if (needToShowRoutingButtons)
{
@@ -610,6 +660,8 @@ public class PlacePageController
// Place page will automatically open when the bottom sheet content is loaded so we can compute the peek height
createPlacePageFragments();
updateButtons(mapObject, showBackButton, !mMapObject.isMyPosition());
if (mViewModel.isAlertDialogShowing)
showTrackDeleteAlertDialog();
}
else
close();

View File

@@ -6,6 +6,7 @@ import static app.organicmaps.sdk.util.Utils.getLocalizedFeatureType;
import static app.organicmaps.sdk.util.Utils.getTagValueLocalized;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.net.Uri;
import android.os.Bundle;
@@ -16,25 +17,39 @@ import android.text.style.ForegroundColorSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import androidx.activity.result.ActivityResultLauncher;
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentFactory;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import app.organicmaps.MwmActivity;
import app.organicmaps.MwmApplication;
import app.organicmaps.R;
import app.organicmaps.bookmarks.BookmarksSharingHelper;
import app.organicmaps.bookmarks.ChooseBookmarkCategoryFragment;
import app.organicmaps.downloader.DownloaderStatusIcon;
import app.organicmaps.editor.OhState;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.bookmarks.data.Bookmark;
import app.organicmaps.sdk.bookmarks.data.BookmarkCategory;
import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
import app.organicmaps.sdk.bookmarks.data.BookmarkSharingResult;
import app.organicmaps.sdk.bookmarks.data.DistanceAndAzimut;
import app.organicmaps.sdk.bookmarks.data.Icon;
import app.organicmaps.sdk.bookmarks.data.KmlFileType;
import app.organicmaps.sdk.bookmarks.data.MapObject;
import app.organicmaps.sdk.bookmarks.data.Metadata;
import app.organicmaps.sdk.bookmarks.data.PredefinedColors;
import app.organicmaps.sdk.bookmarks.data.Track;
import app.organicmaps.sdk.downloader.CountryItem;
import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.editor.Editor;
@@ -49,13 +64,17 @@ import app.organicmaps.sdk.util.StringUtils;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.sdk.util.concurrency.UiThread;
import app.organicmaps.sdk.widget.placepage.CoordinatesFormat;
import app.organicmaps.util.Graphics;
import app.organicmaps.util.SharingUtils;
import app.organicmaps.util.Utils;
import app.organicmaps.util.bottomsheet.MenuBottomSheetFragment;
import app.organicmaps.util.bottomsheet.MenuBottomSheetItem;
import app.organicmaps.widget.ArrowView;
import app.organicmaps.widget.placepage.sections.PlacePageBookmarkFragment;
import app.organicmaps.widget.placepage.sections.PlacePageLinksFragment;
import app.organicmaps.widget.placepage.sections.PlacePageOpeningHoursFragment;
import app.organicmaps.widget.placepage.sections.PlacePagePhoneFragment;
import app.organicmaps.widget.placepage.sections.PlacePageTrackFragment;
import app.organicmaps.widget.placepage.sections.PlacePageWikipediaFragment;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.button.MaterialButton;
@@ -68,15 +87,19 @@ import java.util.Arrays;
import java.util.List;
public class PlacePageView extends Fragment
implements View.OnClickListener, View.OnLongClickListener, LocationListener, SensorListener, Observer<MapObject>
implements View.OnClickListener, View.OnLongClickListener, LocationListener, SensorListener, Observer<MapObject>,
ChooseBookmarkCategoryFragment.Listener, EditBookmarkFragment.EditBookmarkListener,
MenuBottomSheetFragment.MenuBottomSheetInterface, BookmarkManager.BookmarksSharingListener
{
private static final String PREF_COORDINATES_FORMAT = "coordinates_format";
private static final String BOOKMARK_FRAGMENT_TAG = "BOOKMARK_FRAGMENT_TAG";
private static final String TRACK_FRAGMENT_TAG = "TRACK_FRAGMENT_TAG";
private static final String WIKIPEDIA_FRAGMENT_TAG = "WIKIPEDIA_FRAGMENT_TAG";
private static final String PHONE_FRAGMENT_TAG = "PHONE_FRAGMENT_TAG";
private static final String OPENING_HOURS_FRAGMENT_TAG = "OPENING_HOURS_FRAGMENT_TAG";
private static final String LINKS_FRAGMENT_TAG = "LINKS_FRAGMENT_TAG";
private static final String TRACK_SHARE_MENU_ID = "TRACK_SHARE_MENU_ID";
private static final List<CoordinatesFormat> visibleCoordsFormat =
Arrays.asList(CoordinatesFormat.LatLonDMS, CoordinatesFormat.LatLonDecimal, CoordinatesFormat.OLCFull,
@@ -124,12 +147,16 @@ public class PlacePageView extends Fragment
private View mAddOrganisation;
private View mAddPlace;
private View mEditTopSpace;
private ImageView mColorIcon;
private TextView mTvCategory;
private ImageView mEditBookmark;
// Data
private CoordinatesFormat mCoordsFormat = CoordinatesFormat.LatLonDecimal;
// Downloader`s stuff
private DownloaderStatusIcon mDownloaderIcon;
private MaterialTextView mDownloaderInfo;
private ActivityResultLauncher<SharingUtils.SharingIntent> shareLauncher;
private int mStorageCallbackSlot;
@Nullable
private CountryItem mCurrentCountry;
@@ -185,6 +212,7 @@ public class PlacePageView extends Fragment
@Nullable Bundle savedInstanceState)
{
mViewModel = new ViewModelProvider(requireActivity()).get(PlacePageViewModel.class);
shareLauncher = SharingUtils.RegisterLauncher(this);
return inflater.inflate(R.layout.place_page, container, false);
}
@@ -232,8 +260,12 @@ public class PlacePageView extends Fragment
mTvAddress.setOnLongClickListener(this);
mTvAddress.setOnClickListener(this);
mColorIcon = mFrame.findViewById(R.id.item_icon);
mTvCategory = mFrame.findViewById(R.id.tv__category);
mEditBookmark = mFrame.findViewById(R.id.edit_Bookmark);
MaterialButton shareButton = mPreview.findViewById(R.id.share_button);
shareButton.setOnClickListener((v) -> SharingUtils.shareMapObject(requireContext(), mMapObject));
shareButton.setOnClickListener(this::shareClickListener);
final MaterialButton closeButton = mPreview.findViewById(R.id.close_button);
closeButton.setOnClickListener((v) -> mPlacePageViewListener.onPlacePageRequestClose());
@@ -301,6 +333,7 @@ public class PlacePageView extends Fragment
{
super.onStart();
mViewModel.getMapObject().observe(requireActivity(), this);
BookmarkManager.INSTANCE.addSharingListener(this);
MwmApplication.from(requireContext()).getLocationHelper().addListener(this);
MwmApplication.from(requireContext()).getSensorHelper().addListener(this);
}
@@ -310,6 +343,7 @@ public class PlacePageView extends Fragment
{
super.onStop();
mViewModel.getMapObject().removeObserver(this);
BookmarkManager.INSTANCE.removeSharingListener(this);
MwmApplication.from(requireContext()).getLocationHelper().removeListener(this);
MwmApplication.from(requireContext()).getSensorHelper().removeListener(this);
UiThread.cancelDelayedTasks(updateOpenState);
@@ -334,6 +368,10 @@ public class PlacePageView extends Fragment
refreshMyPosition(loc);
else
refreshDistanceToObject(loc);
UiUtils.hideIf(mMapObject.isTrack(), mFrame.findViewById(R.id.ll__place_latlon),
mFrame.findViewById(R.id.ll__place_open_in), mFrame.findViewById(R.id.ll__place_add), mEditTopSpace,
mTvAzimuth, mTvDistance, mAvDirection);
UiUtils.hideIf(MapObjectType.getMapObjectType(mMapObject) != MapObjectType.OTHER, mTvSubtitle);
}
private <T extends Fragment> void updateViewFragment(Class<T> controllerClass, String fragmentTag,
@@ -375,6 +413,12 @@ public class PlacePageView extends Fragment
mMapObject.isBookmark());
}
private void updateTrackView()
{
updateViewFragment(PlacePageTrackFragment.class, TRACK_FRAGMENT_TAG, R.id.place_page_track_fragment,
mMapObject.isTrack());
}
private boolean hasWikipediaEntry()
{
final String wikipediaLink = mMapObject.getMetadata(Metadata.MetadataType.FMD_WIKIPEDIA);
@@ -416,6 +460,180 @@ public class PlacePageView extends Fragment
mToolbar.setTitle(mMapObject.getTitle());
setTextAndColorizeSubtitle();
UiUtils.setTextAndHideIfEmpty(mTvAddress, mMapObject.getAddress());
refreshCategoryPreview();
}
void refreshCategoryPreview()
{
View categoryContainer = mFrame.findViewById(R.id.category_container);
switch (MapObjectType.getMapObjectType(mMapObject))
{
case TRACK ->
{
Track track = (Track) mMapObject;
Drawable circle =
Graphics.drawCircle(track.getColor(), R.dimen.place_page_icon_size, requireContext().getResources());
mColorIcon.setImageDrawable(circle);
mTvCategory.setText(BookmarkManager.INSTANCE.getCategoryById(track.getCategoryId()).getName());
UiUtils.show(mColorIcon, mTvCategory, categoryContainer);
}
case BOOKMARK ->
{
Bookmark bookmark = (Bookmark) mMapObject;
Icon icon = bookmark.getIcon();
if (icon != null)
{
Drawable circle = Graphics.drawCircleAndImage(icon.argb(), R.dimen.place_page_icon_size,
app.organicmaps.sdk.R.drawable.ic_bookmark_none,
R.dimen.place_page_icon_mark_size, requireContext());
mColorIcon.setImageDrawable(circle);
mTvCategory.setText(BookmarkManager.INSTANCE.getCategoryById(bookmark.getCategoryId()).getName());
UiUtils.show(mColorIcon, mTvCategory, categoryContainer);
}
}
case OTHER -> UiUtils.hide(mColorIcon, mTvCategory, categoryContainer);
}
mColorIcon.setOnClickListener(this::onClick);
mTvCategory.setOnClickListener(this::onClick);
mEditBookmark.setOnClickListener(this::onClick);
}
void showColorDialog()
{
final Bundle args = new Bundle();
final FragmentManager manager = getChildFragmentManager();
String className = BookmarkColorDialogFragment.class.getName();
final FragmentFactory factory = manager.getFragmentFactory();
final BookmarkColorDialogFragment dialogFragment =
(BookmarkColorDialogFragment) factory.instantiate(getContext().getClassLoader(), className);
dialogFragment.setArguments(args);
switch (MapObjectType.getMapObjectType(mMapObject))
{
case TRACK ->
{
final Track mTrack = (Track) mMapObject;
args.putInt(BookmarkColorDialogFragment.ICON_COLOR, PredefinedColors.getPredefinedColorIndex(mTrack.getColor()));
dialogFragment.setOnColorSetListener((colorPos) -> {
int from = mTrack.getColor();
int to = PredefinedColors.getColor(colorPos);
if (from == to)
return;
mViewModel.modifyMapObjectColorSilently(to);
Drawable circle = Graphics.drawCircle(to, R.dimen.place_page_icon_size, requireContext().getResources());
mColorIcon.setImageDrawable(circle);
});
dialogFragment.show(requireActivity().getSupportFragmentManager(), null);
}
case BOOKMARK ->
{
final Bookmark bookmark = (Bookmark) mMapObject;
args.putInt(BookmarkColorDialogFragment.ICON_COLOR, bookmark.getIcon().getColor());
args.putInt(BookmarkColorDialogFragment.ICON_RES, bookmark.getIcon().getResId());
dialogFragment.setOnColorSetListener((colorPos) -> {
int from = bookmark.getIcon().argb();
int to = PredefinedColors.getColor(colorPos);
if (from == to)
return;
mViewModel.modifyMapObjectColorSilently(to);
Drawable circle = Graphics.drawCircleAndImage(to, R.dimen.place_page_icon_size,
app.organicmaps.sdk.R.drawable.ic_bookmark_none,
R.dimen.place_page_icon_mark_size, requireContext());
mColorIcon.setImageDrawable(circle);
});
dialogFragment.show(requireActivity().getSupportFragmentManager(), null);
}
}
}
private void showCategoryList()
{
final Bundle args = new Bundle();
final List<BookmarkCategory> categories = BookmarkManager.INSTANCE.getCategories();
final FragmentManager manager = getChildFragmentManager();
String className = ChooseBookmarkCategoryFragment.class.getName();
final FragmentFactory factory = manager.getFragmentFactory();
final ChooseBookmarkCategoryFragment frag =
(ChooseBookmarkCategoryFragment) factory.instantiate(getContext().getClassLoader(), className);
switch (MapObjectType.getMapObjectType(mMapObject))
{
case TRACK ->
{
Track track = (Track) mMapObject;
BookmarkCategory currentCategory = BookmarkManager.INSTANCE.getCategoryById(track.getCategoryId());
final int index = categories.indexOf(currentCategory);
args.putInt(ChooseBookmarkCategoryFragment.CATEGORY_POSITION, index);
frag.setArguments(args);
frag.show(manager, null);
}
case BOOKMARK ->
{
Bookmark bookmark = (Bookmark) mMapObject;
BookmarkCategory currentCategory = BookmarkManager.INSTANCE.getCategoryById(bookmark.getCategoryId());
final int index = categories.indexOf(currentCategory);
args.putInt(ChooseBookmarkCategoryFragment.CATEGORY_POSITION, index);
frag.setArguments(args);
frag.show(manager, null);
}
}
}
@Override
public void onCategoryChanged(@NonNull BookmarkCategory newCategory)
{
switch (MapObjectType.getMapObjectType(mMapObject))
{
case TRACK ->
{
Track track = (Track) mMapObject;
BookmarkCategory previousCategory = BookmarkManager.INSTANCE.getCategoryById(track.getCategoryId());
if (previousCategory == newCategory)
return;
BookmarkManager.INSTANCE.notifyCategoryChanging(track, newCategory.getId());
mTvCategory.setText(newCategory.getName());
mViewModel.modifyMapObjectCategoryIdSilently(newCategory.getId());
}
case BOOKMARK ->
{
Bookmark bookmark = (Bookmark) mMapObject;
BookmarkCategory previousCategory = BookmarkManager.INSTANCE.getCategoryById(bookmark.getCategoryId());
if (previousCategory == newCategory)
return;
mTvCategory.setText(newCategory.getName());
mViewModel.modifyMapObjectCategoryIdSilently(newCategory.getId());
}
}
}
void showBookmarkEditFragment()
{
switch (MapObjectType.getMapObjectType(mMapObject))
{
case TRACK ->
{
Track track = (Track) mMapObject;
final FragmentActivity activity = requireActivity();
EditBookmarkFragment.editTrack(track.getCategoryId(), track.getTrackId(), activity, getChildFragmentManager(),
PlacePageView.this);
}
case BOOKMARK ->
{
Bookmark bookmark = (Bookmark) mMapObject;
final FragmentActivity activity = requireActivity();
EditBookmarkFragment.editBookmark(bookmark.getCategoryId(), bookmark.getBookmarkId(), activity,
getChildFragmentManager(), PlacePageView.this);
}
}
}
@Override
public void onBookmarkSaved(long bookmarkId, boolean movedFromCategory)
{
switch (MapObjectType.getMapObjectType(mMapObject))
{
case TRACK -> BookmarkManager.INSTANCE.updateTrackPlacePage(bookmarkId);
case BOOKMARK -> BookmarkManager.INSTANCE.updateBookmarkPlacePage(bookmarkId);
}
}
private void refreshDetails()
@@ -494,6 +712,7 @@ public class PlacePageView extends Fragment
updateWikipediaView();
updateBookmarkView();
updatePhoneView();
updateTrackView();
}
private void refreshWiFi()
@@ -532,6 +751,8 @@ public class PlacePageView extends Fragment
private void refreshDistanceToObject(Location l)
{
if (mMapObject.isTrack())
return;
UiUtils.showIf(l != null, mTvDistance);
if (l == null)
return;
@@ -660,6 +881,12 @@ public class PlacePageView extends Fragment
}
else if (id == R.id.direction_frame)
showBigDirection();
else if (id == R.id.item_icon)
showColorDialog();
else if (id == R.id.edit_Bookmark)
showBookmarkEditFragment();
else if (id == R.id.tv__category)
showCategoryList();
}
private void showBigDirection()
@@ -818,7 +1045,7 @@ public class PlacePageView extends Fragment
@Override
public void onCompassUpdated(double north)
{
if (mMapObject == null || mMapObject.isMyPosition())
if (mMapObject == null || mMapObject.isMyPosition() || mMapObject.isTrack())
return;
final Location location = MwmApplication.from(requireContext()).getLocationHelper().getSavedLocation();
@@ -840,6 +1067,50 @@ public class PlacePageView extends Fragment
}
}
void shareClickListener(View v)
{
if (mMapObject.isTrack())
{
MenuBottomSheetFragment.newInstance(TRACK_SHARE_MENU_ID, getString(R.string.PP_track_bottom_sheet_title))
.show(getChildFragmentManager(), TRACK_SHARE_MENU_ID);
}
else
SharingUtils.shareMapObject(requireContext(), mMapObject);
}
private void onShareTrackSelected(long trackId, KmlFileType kmlFileType)
{
BookmarksSharingHelper.INSTANCE.prepareTrackForSharing(requireActivity(), trackId, kmlFileType);
}
@Nullable
@Override
public ArrayList<MenuBottomSheetItem> getMenuBottomSheetItems(String id)
{
return switch (id)
{
case TRACK_SHARE_MENU_ID -> getTrackShareMenuItems();
default -> null;
};
}
public ArrayList<MenuBottomSheetItem> getTrackShareMenuItems()
{
Track track = (Track) mMapObject;
ArrayList<MenuBottomSheetItem> items = new ArrayList<>();
items.add(new MenuBottomSheetItem(R.string.export_file, R.drawable.ic_file_kmz,
() -> onShareTrackSelected(track.getTrackId(), KmlFileType.Text)));
items.add(new MenuBottomSheetItem(R.string.export_file_gpx, R.drawable.ic_file_gpx,
() -> onShareTrackSelected(track.getTrackId(), KmlFileType.Gpx)));
return items;
}
@Override
public void onPreparedFileForSharing(@NonNull BookmarkSharingResult result)
{
BookmarksSharingHelper.INSTANCE.onPreparedFileForSharing(requireActivity(), shareLauncher, result);
}
public interface PlacePageViewListener
{
// Called when the content has actually changed and we are ready to compute the peek height
@@ -848,4 +1119,21 @@ public class PlacePageView extends Fragment
void onPlacePageRequestToggleState();
void onPlacePageRequestClose();
}
public enum MapObjectType
{
TRACK,
BOOKMARK,
OTHER;
public static MapObjectType getMapObjectType(MapObject mapObject)
{
if (mapObject.isTrack())
return TRACK;
else if (mapObject.isBookmark())
return BOOKMARK;
else
return OTHER;
}
}
}

View File

@@ -3,7 +3,10 @@ package app.organicmaps.widget.placepage;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import app.organicmaps.sdk.bookmarks.data.Bookmark;
import app.organicmaps.sdk.bookmarks.data.ElevationInfo;
import app.organicmaps.sdk.bookmarks.data.MapObject;
import app.organicmaps.sdk.bookmarks.data.Track;
import java.util.List;
public class PlacePageViewModel extends ViewModel
@@ -12,6 +15,7 @@ public class PlacePageViewModel extends ViewModel
private final MutableLiveData<MapObject> mMapObject = new MutableLiveData<>();
private final MutableLiveData<Integer> mPlacePageWidth = new MutableLiveData<>();
private final MutableLiveData<Integer> mPlacePageDistanceToTop = new MutableLiveData<>();
public boolean isAlertDialogShowing = false;
public LiveData<List<PlacePageButtons.ButtonType>> getCurrentButtons()
{
@@ -33,6 +37,38 @@ public class PlacePageViewModel extends ViewModel
mMapObject.setValue(mapObject);
}
// These silent method are used to update data of map object silently without triggering
// the observer which refreshes everything and puts extra load on device in calculation
// which is not required
public void modifyMapObjectPointSilently(ElevationInfo.Point point)
{
if (mMapObject.getValue() == null)
return;
mMapObject.getValue().setLat(point.getLatitude());
mMapObject.getValue().setLon(point.getLongitude());
}
public void modifyMapObjectCategoryIdSilently(long categoryId)
{
if (mMapObject.getValue() == null)
return;
switch (PlacePageView.MapObjectType.getMapObjectType(mMapObject.getValue()))
{
case TRACK -> ((Track) mMapObject.getValue()).setCategoryId(categoryId);
case BOOKMARK -> ((Bookmark) mMapObject.getValue()).setCategoryId(categoryId);
}
}
public void modifyMapObjectColorSilently(int color)
{
if (mMapObject.getValue() == null)
return;
switch (PlacePageView.MapObjectType.getMapObjectType(mMapObject.getValue()))
{
case TRACK -> ((Track) mMapObject.getValue()).setColor(color);
case BOOKMARK -> ((Bookmark) mMapObject.getValue()).setIconColor(color);
}
}
public MutableLiveData<Integer> getPlacePageWidth()
{
return mPlacePageWidth;

View File

@@ -16,23 +16,18 @@ import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import app.organicmaps.R;
import app.organicmaps.sdk.bookmarks.data.Bookmark;
import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
import app.organicmaps.sdk.bookmarks.data.MapObject;
import app.organicmaps.sdk.util.StringUtils;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.util.Utils;
import app.organicmaps.widget.placepage.EditBookmarkFragment;
import app.organicmaps.widget.placepage.PlacePageViewModel;
import com.google.android.material.textview.MaterialTextView;
public class PlacePageBookmarkFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener,
Observer<MapObject>,
EditBookmarkFragment.EditBookmarkListener
public class PlacePageBookmarkFragment extends Fragment implements View.OnLongClickListener, Observer<MapObject>
{
private View mFrame;
private MaterialTextView mTvBookmarkNote;
@@ -60,8 +55,6 @@ public class PlacePageBookmarkFragment extends Fragment implements View.OnClickL
mFrame = view;
mTvBookmarkNote = mFrame.findViewById(R.id.tv__bookmark_notes);
mTvBookmarkNote.setOnLongClickListener(this);
final View editBookmarkBtn = mFrame.findViewById(R.id.tv__bookmark_edit);
editBookmarkBtn.setOnClickListener(this);
}
private void initWebView()
@@ -119,14 +112,6 @@ public class PlacePageBookmarkFragment extends Fragment implements View.OnClickL
}
}
@Override
public void onClick(View v)
{
final FragmentActivity activity = requireActivity();
EditBookmarkFragment.editBookmark(currentBookmark.getCategoryId(), currentBookmark.getBookmarkId(), activity,
getChildFragmentManager(), PlacePageBookmarkFragment.this);
}
@Override
public boolean onLongClick(View v)
{
@@ -156,13 +141,4 @@ public class PlacePageBookmarkFragment extends Fragment implements View.OnClickL
updateBookmarkDetails();
}
}
@Override
public void onBookmarkSaved(long bookmarkId, boolean movedFromCategory)
{
Bookmark updatedBookmark = BookmarkManager.INSTANCE.updateBookmarkPlacePage(bookmarkId);
if (updatedBookmark == null)
return;
mViewModel.setMapObject(updatedBookmark);
}
}

View File

@@ -0,0 +1,115 @@
package app.organicmaps.widget.placepage.sections;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import app.organicmaps.R;
import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
import app.organicmaps.sdk.bookmarks.data.ElevationInfo;
import app.organicmaps.sdk.bookmarks.data.MapObject;
import app.organicmaps.sdk.bookmarks.data.Track;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.widget.placepage.ElevationProfileViewRenderer;
import app.organicmaps.widget.placepage.PlacePageStateListener;
import app.organicmaps.widget.placepage.PlacePageViewModel;
public class PlacePageTrackFragment extends Fragment
implements PlacePageStateListener, Observer<MapObject>, BookmarkManager.OnElevationActivePointChangedListener,
BookmarkManager.OnElevationCurrentPositionChangedListener
{
private PlacePageViewModel mViewModel;
@Nullable
private Track mTrack;
private ElevationProfileViewRenderer mElevationProfileViewRenderer;
private View mFrame;
private View mElevationProfileView;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState)
{
mViewModel = new ViewModelProvider(requireActivity()).get(PlacePageViewModel.class);
return inflater.inflate(R.layout.placepage_track_fragment, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
mElevationProfileViewRenderer = new ElevationProfileViewRenderer();
mFrame = view;
mElevationProfileView = mFrame.findViewById(R.id.elevation_profile);
mElevationProfileViewRenderer.initialize(mElevationProfileView);
}
@Override
public void onStart()
{
super.onStart();
BookmarkManager.INSTANCE.setElevationActivePointChangedListener(this);
BookmarkManager.INSTANCE.setElevationCurrentPositionChangedListener(this);
mViewModel.getMapObject().observe(requireActivity(), this);
}
@Override
public void onStop()
{
super.onStop();
mViewModel.getMapObject().removeObserver(this);
}
@Override
public void onDestroy()
{
BookmarkManager.INSTANCE.setElevationActivePointChangedListener(null);
BookmarkManager.INSTANCE.setElevationCurrentPositionChangedListener(null);
super.onDestroy();
}
@Override
public void onChanged(@Nullable MapObject mapObject)
{
// MapObject could be something else than a Track if the user already has the place page
// opened and clicks on a non-Track POI.
// This callback would be called before the fragment had time to be destroyed
if (mapObject != null && mapObject.isTrack())
{
Track track = (Track) mapObject;
if (track.isElevationInfoHasValue())
{
if (mTrack == null || mTrack.getTrackId() != track.getTrackId())
{
mElevationProfileViewRenderer.render(track);
UiUtils.show(mElevationProfileView);
}
}
else
UiUtils.hide(mElevationProfileView);
mTrack = track;
}
}
@Override
public void onElevationActivePointChanged()
{
if (mTrack == null)
return;
mElevationProfileViewRenderer.onChartElevationActivePointChanged();
ElevationInfo.Point point = BookmarkManager.INSTANCE.getElevationActivePointCoordinates(mTrack.getTrackId());
mViewModel.modifyMapObjectPointSilently(point);
}
@Override
public void onCurrentPositionChanged()
{
mElevationProfileViewRenderer.onChartCurrentPositionChanged();
}
}

View File

@@ -0,0 +1,10 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:viewportHeight="590.91"
android:viewportWidth="590.91"
android:width="24dp">
<path
android:fillColor="#000000"
android:pathData="M541.67,295.45l-86.21,-86.21l0,71.21l-320,0l0,-71.21l-86.21,86.21l86.21,86.21l0,-71.21l320,0l0,71.21z" />
</vector>

View File

@@ -3,7 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/elevation_profile"
android:layout_width="@dimen/place_page_width"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/margin_base"
android:paddingBottom="@dimen/margin_base"

View File

@@ -8,7 +8,9 @@
<app.organicmaps.widget.placepage.ElevationProfileChart
android:id="@+id/elevation_profile_chart"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true" />
<app.organicmaps.widget.placepage.FloatingMarkerView
android:id="@+id/floating_marker"
android:visibility="gone"

View File

@@ -1,37 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/elevation_profile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/margin_half_plus"
android:paddingBottom="@dimen/margin_base"
android:background="?cardBackground"
android:clickable="true"
android:focusable="true"
android:fillViewport="true"
android:focusable="true"
app:behavior_peekHeight="@dimen/elevation_profile_peek_height"
app:layout_behavior="@string/placepage_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/pull_icon_container"
android:layout_width="wrap_content"
android:layout_height="@dimen/margin_half"
android:layout_gravity="center_horizontal"
android:layout_marginStart="@dimen/margin_base"
android:layout_marginEnd="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_eighth"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/pull_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<include layout="@layout/elevation_profile_internal" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>

View File

@@ -4,22 +4,188 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="@layout/elevation_profile_bottom_sheet">
<LinearLayout
android:id="@+id/title_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/margin_half"
android:layout_marginStart="@dimen/margin_base"
android:layout_marginEnd="@dimen/margin_base"
android:paddingTop="@dimen/margin_half"
android:paddingBottom="@dimen/margin_base"
android:textAppearance="?fontHeadline6"
tools:text="Xindian Shitoushan Trail" />
<include
layout="@layout/list_divider"
android:layout_width="match_parent"
android:layout_height="@dimen/divider_height"
android:layout_marginStart="@dimen/margin_base"
android:layout_marginEnd="@dimen/margin_base"
layout="@layout/list_divider" />
android:layout_marginEnd="@dimen/margin_base" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_half"
android:layout_marginTop="@dimen/margin_quarter"
android:layout_marginEnd="@dimen/margin_half"
android:layout_marginBottom="@dimen/margin_half_plus_eight"
android:baselineAligned="false"
android:orientation="horizontal">
<!--card one-->
<RelativeLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/margin_half"
android:layout_weight="1"
android:gravity="center">
<LinearLayout
android:id="@+id/ascent_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="@dimen/margin_base_plus_quarter"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/margin_quarter"
app:srcCompat="@drawable/ic_ascent"
app:tint="?elevationProfilePropIconTint" />
<TextView
android:id="@+id/ascent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@string/robotoMedium"
android:textAppearance="@style/MwmTextAppearance.Body3"
tools:text="10000 m" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/ascent_container"
android:layout_alignStart="@+id/ascent_container"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/elevation_profile_ascent"
android:textAppearance="@style/MwmTextAppearance.Body5" />
</RelativeLayout>
<!--card two-->
<RelativeLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/margin_half"
android:layout_weight="1"
android:gravity="center">
<LinearLayout
android:id="@+id/descent_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="@dimen/margin_base_plus_quarter"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/margin_quarter"
app:srcCompat="@drawable/ic_descent"
app:tint="?elevationProfilePropIconTint" />
<TextView
android:id="@+id/descent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@string/robotoMedium"
android:textAppearance="@style/MwmTextAppearance.Body3"
tools:text="10000 m" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/descent_container"
android:layout_alignStart="@+id/descent_container"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/elevation_profile_descent"
android:textAppearance="@style/MwmTextAppearance.Body5" />
</RelativeLayout>
<!--card three-->
<RelativeLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/margin_half"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:id="@+id/max_height_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/margin_quarter"
app:srcCompat="@drawable/ic_maxalt"
app:tint="?elevationProfilePropIconTint" />
<TextView
android:id="@+id/max_altitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@string/robotoMedium"
android:textAppearance="@style/MwmTextAppearance.Body3"
tools:text="10000 m" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/max_height_container"
android:layout_alignStart="@+id/max_height_container"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/elevation_profile_max_elevation"
android:textAppearance="@style/MwmTextAppearance.Body5" />
</RelativeLayout>
<!--card four-->
<RelativeLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/margin_half"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:id="@+id/min_elevation_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/margin_half"
app:srcCompat="@drawable/ic_minalt"
app:tint="?elevationProfilePropIconTint" />
<TextView
android:id="@+id/min_altitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@string/robotoMedium"
android:textAppearance="@style/MwmTextAppearance.Body3"
tools:text="10000 m" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/min_elevation_container"
android:layout_alignStart="@+id/min_elevation_container"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/elevation_profile_min_elevation"
android:textAppearance="@style/MwmTextAppearance.Body5" />
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/chart_container"
android:layout_width="match_parent"
@@ -27,142 +193,13 @@
android:gravity="center"
android:minHeight="@dimen/elevation_profile_chart_min_height"
android:orientation="vertical">
<include layout="@layout/elevation_profile"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_base"
android:layout_marginStart="@dimen/margin_base"
android:layout_marginEnd="@dimen/margin_base"
android:minHeight="@dimen/elevation_profile_chart_info_min_height"
android:orientation="horizontal"
android:baselineAligned="false">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginEnd="@dimen/margin_quarter"
android:layout_weight="1"
android:background="?elevationProfilePropertyBg"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="@dimen/margin_quarter_plus">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_ascent"
app:tint="?elevationProfilePropIconTint" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_eighth"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/elevation_profile_ascent"
android:textAppearance="@style/MwmTextAppearance.Body5" />
<TextView
android:id="@+id/ascent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:textAppearance"
android:fontFamily="@string/robotoMedium"
tools:text="10000 m" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginEnd="@dimen/margin_quarter"
android:layout_weight="1"
android:background="?elevationProfilePropertyBg"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="@dimen/margin_quarter_plus">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_descent"
app:tint="?elevationProfilePropIconTint" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_eighth"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/elevation_profile_descent"
android:textAppearance="@style/MwmTextAppearance.Body5" />
<TextView
android:id="@+id/descent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:textAppearance"
android:fontFamily="@string/robotoMedium"
tools:text="10000 m" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginEnd="@dimen/margin_quarter"
android:layout_weight="1"
android:background="?elevationProfilePropertyBg"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="@dimen/margin_quarter_plus">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_maxalt"
app:tint="?elevationProfilePropIconTint" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_eighth"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/elevation_profile_max_elevation"
android:textAppearance="@style/MwmTextAppearance.Body5" />
<TextView
android:id="@+id/max_altitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:textAppearance"
android:fontFamily="@string/robotoMedium"
tools:text="10000 m" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="?elevationProfilePropertyBg"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="@dimen/margin_quarter_plus">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_minalt"
app:tint="?elevationProfilePropIconTint" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_eighth"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/elevation_profile_min_elevation"
android:textAppearance="@style/MwmTextAppearance.Body5" />
<TextView
android:id="@+id/min_altitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:textAppearance"
android:fontFamily="@string/robotoMedium"
tools:text="10000 m" />
</LinearLayout>
<include layout="@layout/elevation_profile" />
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_base"
android:layout_marginStart="@dimen/margin_base"
android:layout_marginTop="@dimen/margin_quarter_plus"
android:layout_marginEnd="@dimen/margin_base"
android:orientation="horizontal">
<LinearLayout
@@ -174,21 +211,21 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:textAppearance"
android:text="@string/elevation_profile_difficulty"/>
android:text="@string/elevation_profile_difficulty"
android:textAppearance="?android:textAppearance" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="@dimen/elevation_profile_dot_levels_margin"
android:layout_gravity="bottom"
android:layout_marginStart="@dimen/margin_half_plus_eight">
android:layout_marginStart="@dimen/margin_half_plus_eight"
android:layout_marginBottom="@dimen/elevation_profile_dot_levels_margin"
android:orientation="horizontal">
<TextView
android:id="@+id/difficulty_level_1"
android:layout_width="@dimen/elevation_profile_difficulty_dot_size"
android:layout_height="@dimen/elevation_profile_difficulty_dot_size"
android:background="@drawable/dot_elevation_difficulty"
android:enabled="false"/>
android:enabled="false" />
<TextView
android:id="@+id/difficulty_level_2"
android:layout_width="@dimen/elevation_profile_difficulty_dot_size"
@@ -196,37 +233,37 @@
android:layout_marginStart="@dimen/margin_quarter"
android:layout_marginEnd="@dimen/margin_quarter"
android:background="@drawable/dot_elevation_difficulty"
android:enabled="false"/>
android:enabled="false" />
<TextView
android:id="@+id/difficulty_level_3"
android:layout_width="@dimen/elevation_profile_difficulty_dot_size"
android:layout_height="@dimen/elevation_profile_difficulty_dot_size"
android:background="@drawable/dot_elevation_difficulty"
android:enabled="false"/>
android:enabled="false" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_toEndOf="@id/difficulty_container"
android:layout_alignParentEnd="true"
android:id="@+id/time_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_toEndOf="@id/difficulty_container"
android:gravity="end"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:textAppearance"
android:text="@string/elevation_profile_time" />
android:text="@string/elevation_profile_time"
android:textAppearance="?android:textAppearance" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_half"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:textAppearanceMedium"
android:textStyle="bold"
android:singleLine="true"
android:ellipsize="end"
tools:text="3 h. 25 min." />
</LinearLayout>
</RelativeLayout>

View File

@@ -9,8 +9,8 @@
tools:ignore="Overdraw">
<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="@dimen/elevation_profile_marker_width"
android:layout_height="@dimen/elevation_profile_marker_width"
android:layout_centerVertical="true"
app:srcCompat="@drawable/ic_graph_point" />
<RelativeLayout
@@ -43,39 +43,41 @@
android:maxWidth="@dimen/dialog_min_height"
android:padding="@dimen/margin_quarter_plus"
tools:ignore="UnusedAttribute">
<TextView
android:id="@+id/distance_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxWidth="@dimen/dialog_min_height"
android:singleLine="true"
android:textSize="@dimen/margin_half_plus_eight" />
<ImageView
android:id="@+id/distance_icon"
android:layout_width="@dimen/margin_half_plus"
android:layout_height="@dimen/margin_half_plus"
app:srcCompat="@drawable/ic_distance_travelled"
app:tint="?ppFloatingMarkerIconColor" />
<TextView
android:id="@+id/distance_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/distance_text"
android:layout_marginStart="@dimen/margin_quarter"
android:layout_toEndOf="@+id/distance_icon"
android:ellipsize="end"
android:maxWidth="@dimen/dialog_min_height"
android:singleLine="true"
android:textSize="@dimen/margin_half_plus_eight" />
android:textSize="@dimen/margin_half_plus_eight"
tools:text="10 km" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="@+id/distance_icon"
android:layout_below="@id/distance_value"
android:layout_alignParentBottom="true"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/triangle"
android:layout_width="@dimen/margin_half_plus"
android:layout_height="@dimen/margin_half_plus"
android:layout_width="@dimen/margin_half_plus_eight"
android:layout_height="@dimen/margin_half_plus_eight"
app:srcCompat="?elevationProfileSelectedPointTriangle" />
<TextView
android:id="@+id/altitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="900 m"
android:layout_marginStart="@dimen/margin_quarter"
android:ellipsize="end"
android:singleLine="true"

View File

@@ -18,16 +18,6 @@
android:textAppearance="?android:attr/textAppearance"
tools:text="Long, long text Long, long text Long, long text Long, long text Long, long text Long, long text "/>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tv__bookmark_edit"
style="@style/PlacePageMetadataText.Button"
android:gravity="center"
android:layout_height="@dimen/height_block_base"
android:background="?clickableBackground"
android:paddingEnd="@dimen/margin_base"
android:paddingStart="@dimen/margin_base"
android:text="@string/placepage_edit_bookmark_button"/>
<include
layout="@layout/divider_horizontal"/>
</LinearLayout>

View File

@@ -21,7 +21,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:layout="@layout/place_page_bookmark_fragment" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/place_page_wikipedia_fragment"
android:layout_width="match_parent"

View File

@@ -5,8 +5,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="@dimen/margin_quarter">
android:orientation="vertical">
<include
android:id="@+id/pull_icon_container"
layout="@layout/bottom_sheet_handle" />
@@ -180,4 +179,62 @@
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/category_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_half"
android:orientation="vertical">
<include layout="@layout/place_page_shadow_gap" />
<RelativeLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?ppBackground">
<ImageView
android:id="@+id/item_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:background="?clickableBackground"
android:layout_centerVertical="true"
android:clickable="true"
android:focusable="true"
android:paddingHorizontal="8dp"
android:paddingVertical="5dp" />
<TextView
android:id="@+id/tv__category"
style="@style/PlacePageMetadataText.Button"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_centerVertical="true"
android:layout_toStartOf="@id/edit_Bookmark"
android:layout_toEndOf="@id/item_icon"
android:background="?clickableBackground"
android:paddingStart="@dimen/margin_quarter"
android:paddingEnd="@dimen/margin_quarter"
android:textAllCaps="false"
tools:text="@string/categories" />
<ImageView
android:id="@+id/edit_Bookmark"
style="@style/MwmWidget.Editor.MetadataIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_centerVertical="true"
android:background="?clickableBackground"
android:clickable="true"
android:focusable="true"
android:src="@drawable/ic_edit" />
</RelativeLayout>
</LinearLayout>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/place_page_track_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:layout="@layout/placepage_track_fragment" />
</LinearLayout>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:background="@color/black_8"
android:layout_width="match_parent"
android:layout_height="@dimen/margin_half" />

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/place_page_track_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/place_page_shadow_gap" />
<include
android:id="@+id/elevation_profile"
layout="@layout/elevation_profile_bottom_sheet" />
</LinearLayout>

View File

@@ -46,6 +46,8 @@
<dimen name="place_page_width">320dp</dimen>
<dimen name="place_page_buttons_height">56dp</dimen>
<dimen name="place_page_top_button">40dp</dimen>
<dimen name="place_page_icon_size">32dp</dimen>
<dimen name="place_page_icon_mark_size">20dp</dimen>
<dimen name="downloader_status_size">40dp</dimen>
<dimen name="search_progress_size">32dp</dimen>
@@ -75,12 +77,13 @@
<dimen name="viewport_min_width">300dp</dimen>
<dimen name="elevation_profile_peek_height">260dp</dimen>
<dimen name="elevation_profile_chart_min_height">144dp</dimen>
<dimen name="elevation_profile_chart_info_min_height">68dp</dimen>
<dimen name="elevation_profile_chart_info_min_height">54dp</dimen>
<dimen name="elevation_profile_difficulty_dot_size">10dp</dimen>
<dimen name="elevation_profile_content_height">144dp</dimen>
<dimen name="elevation_profile_height">108dp</dimen>
<dimen name="elevation_profile_half_height">54dp</dimen>
<dimen name="elevation_profile_height">80dp</dimen>
<dimen name="elevation_profile_half_height">40dp</dimen>
<dimen name="elevation_profile_dot_levels_margin">3dp</dimen>
<dimen name="elevation_profile_marker_width">25dp</dimen>
<dimen name="map_button_size">48dp</dimen>
<dimen name="map_button_icon_size">28dp</dimen>
<dimen name="map_button_arrow_icon_size">34dp</dimen>

View File

@@ -16,6 +16,7 @@
<dimen name="text_size_body_3">14sp</dimen>
<dimen name="text_size_body_4">12sp</dimen>
<dimen name="text_size_body_5">10sp</dimen>
<dimen name="text_size_body_6">8sp</dimen>
<dimen name="text_size_caption">14sp</dimen>
<dimen name="text_size_icon_title">10sp</dimen>
<dimen name="text_size_button">16sp</dimen>

View File

@@ -971,4 +971,5 @@
<string name="closed_now">Closed now</string>
<!-- Used in place page preview for next open/close time. eg. "closing in 30 min • at 19:30" -->
<string name="at">at %s</string>
<string name="PP_track_bottom_sheet_title">Save Track As</string>
</resources>

View File

@@ -93,6 +93,11 @@
<item name="android:textColor">?android:textColorSecondary</item>
</style>
<style name="MwmTextAppearance.Body6">
<item name="android:textSize">@dimen/text_size_body_6</item>
<item name="android:textColor">?android:textColorSecondary</item>
</style>
<style name="MwmTextAppearance.Button">
<item name="android:textSize">@dimen/text_size_button</item>
<item name="android:textColor">?colorSecondary</item>

View File

@@ -17,6 +17,7 @@
<attr name="iconTintLight" format="color" />
<attr name="ppBackground" format="color" />
<attr name="ppButtonsBackground" format="color" />
<attr name="ppFloatingMarkerIconColor" format="color" />
<attr name="navNextTurnFrame" format="reference" />
<attr name="navNextNextTurnFrame" format="reference" />
<attr name="navLanesBackgroundColor" format="reference" />

View File

@@ -921,17 +921,7 @@ JNIEXPORT void JNICALL Java_app_organicmaps_sdk_Framework_nativePlacePageActivat
JNIEnv * env = jni::GetEnv();
auto const & info = frm()->GetCurrentPlacePageInfo();
jni::TScopedLocalRef placePageDataRef(env, nullptr);
if (info.IsTrack())
{
// todo: (KK) implement elevation info handling for the proper track selection
auto const & track = frm()->GetBookmarkManager().GetTrack(info.GetTrackId());
auto const & elevationInfo = track->GetElevationInfo();
if (elevationInfo.has_value())
placePageDataRef.reset(usermark_helper::CreateElevationInfo(env, elevationInfo.value()));
}
if (!placePageDataRef)
placePageDataRef.reset(usermark_helper::CreateMapObject(env, info));
env->CallVoidMethod(g_placePageActivationListener, activatedId, placePageDataRef.get());
};
auto const closePlacePage = [deactivateId]()

View File

@@ -88,6 +88,47 @@ jobject CreateMapObject(JNIEnv * env, place_page::Info const & info, int mapObje
return mapObject;
}
jobject CreateTrack(JNIEnv * env, place_page::Info const & info, jni::TScopedLocalObjectArrayRef const & jrawTypes,
jni::TScopedLocalRef const & routingPointInfo, jobject const & popularity)
{
static jmethodID const ctorId =
jni::GetConstructorID(env, g_trackClazz,
"(Lapp/organicmaps/sdk/bookmarks/data/FeatureId;JJLjava/lang/String;"
"Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;"
"Lapp/organicmaps/sdk/routing/RoutePointInfo;"
"ILapp/organicmaps/sdk/search/Popularity;Ljava/lang/String;"
"[Ljava/lang/String;ILapp/organicmaps/sdk/util/Distance;DD)V");
static jmethodID const featureCtorId = jni::GetConstructorID(env, g_featureIdClazz, "(Ljava/lang/String;JI)V");
auto const trackId = info.GetTrackId();
auto const track = frm()->GetBookmarkManager().GetTrack(trackId);
dp::Color nColor = track->GetColor(0);
jint androidColor =
shift(nColor.GetAlpha(), 24) + shift(nColor.GetRed(), 16) + shift(nColor.GetGreen(), 8) + nColor.GetBlue();
auto const categoryId = track->GetGroupId();
ms::LatLon const ll = info.GetLatLon();
jni::TScopedLocalRef jMwmName(env, jni::ToJavaString(env, info.GetID().GetMwmName()));
jni::TScopedLocalRef jFeatureId(env, env->NewObject(g_featureIdClazz, featureCtorId, jMwmName.get(),
(jlong)info.GetID().GetMwmVersion(), (jint)info.GetID().m_index));
jni::TScopedLocalRef jTitle(env, jni::ToJavaString(env, info.GetTitle()));
jni::TScopedLocalRef jSecondaryTitle(env, jni::ToJavaString(env, info.GetSecondaryTitle()));
jni::TScopedLocalRef jSubtitle(env, jni::ToJavaString(env, info.GetSubtitle()));
jni::TScopedLocalRef jAddress(env, jni::ToJavaString(env, info.GetSecondarySubtitle()));
jni::TScopedLocalRef jWikiDescription(env, jni::ToJavaString(env, info.GetWikiDescription()));
jobject mapObject =
env->NewObject(g_trackClazz, ctorId, jFeatureId.get(), static_cast<jlong>(categoryId),
static_cast<jlong>(trackId), jTitle.get(), jSecondaryTitle.get(), jSubtitle.get(), jAddress.get(),
routingPointInfo.get(), info.GetOpeningMode(), popularity, jWikiDescription.get(), jrawTypes.get(),
androidColor, ToJavaDistance(env, platform::Distance::CreateFormatted(track->GetLengthMeters())),
static_cast<jdouble>(ll.m_lat), static_cast<jdouble>(ll.m_lon));
if (info.HasMetadata())
InjectMetadata(env, g_mapObjectClazz, mapObject, info);
return mapObject;
}
jobject CreateBookmark(JNIEnv * env, place_page::Info const & info, jni::TScopedLocalObjectArrayRef const & jrawTypes,
jni::TScopedLocalRef const & routingPointInfo, jobject const & popularity)
{
@@ -129,10 +170,11 @@ jobject CreateElevationPoint(JNIEnv * env, ElevationInfo::Point const & point)
{
static jclass const pointClass =
jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/ElevationInfo$Point");
// public Point(double distance, int altitude)
static jmethodID const pointCtorId = jni::GetConstructorID(env, pointClass, "(DI)V");
return env->NewObject(pointClass, pointCtorId, static_cast<jdouble>(point.m_distance),
static_cast<jint>(point.m_point.GetAltitude()));
// public Point(double distance, int altitude, double latitude, double longitude)
static jmethodID const pointCtorId = jni::GetConstructorID(env, pointClass, "(DIDD)V");
return env->NewObject(
pointClass, pointCtorId, static_cast<jdouble>(point.m_distance), static_cast<jint>(point.m_point.GetAltitude()),
static_cast<jdouble>(point.m_point.GetPoint().x), static_cast<jdouble>(point.m_point.GetPoint().y));
}
jobjectArray ToElevationPointArray(JNIEnv * env, ElevationInfo::Points const & points)
@@ -146,22 +188,12 @@ jobjectArray ToElevationPointArray(JNIEnv * env, ElevationInfo::Points const & p
jobject CreateElevationInfo(JNIEnv * env, ElevationInfo const & info)
{
// public ElevationInfo(long trackId, @NonNull String name, @NonNull Point[] points,
// int ascent, int descent, int minAltitude, int maxAltitude, int difficulty,
// long m_duration)
static jmethodID const ctorId = jni::GetConstructorID(env, g_elevationInfoClazz,
"(JLjava/lang/String;Ljava/lang/String;"
"[Lapp/organicmaps/sdk/bookmarks/data/ElevationInfo$Point;"
"IIIIIJ)V");
// public ElevationInfo(@NonNull Point[] points, int difficulty);
static jmethodID const ctorId =
jni::GetConstructorID(env, g_elevationInfoClazz, "([Lapp/organicmaps/sdk/bookmarks/data/ElevationInfo$Point;I)V");
jni::TScopedLocalObjectArrayRef jPoints(env, ToElevationPointArray(env, info.GetPoints()));
// TODO (KK): elevation info should have only the elevation data - see the
// https://github.com/organicmaps/organicmaps/pull/10063
return env->NewObject(g_elevationInfoClazz, ctorId, jPoints.get(),
// static_cast<jint>(info.GetAscent()),
// static_cast<jint>(info.GetDescent()),
// static_cast<jint>(info.GetMinAltitude()),
// static_cast<jint>(info.GetMaxAltitude()),
static_cast<jint>(info.GetDifficulty()));
return env->NewObject(g_elevationInfoClazz, ctorId, jPoints.get(), static_cast<jint>(info.GetDifficulty()));
}
jobject CreateMapObject(JNIEnv * env, place_page::Info const & info)
@@ -193,6 +225,9 @@ jobject CreateMapObject(JNIEnv * env, place_page::Info const & info)
routingPointInfo.get(), popularity, jrawTypes.get());
}
if (info.IsTrack())
return CreateTrack(env, info, jrawTypes, routingPointInfo, popularity);
return CreateMapObject(env, info, kPoi, ll.m_lat, ll.m_lon, true /* parseMeta */, false /* parseApi */,
routingPointInfo.get(), popularity, jrawTypes.get());
}

View File

@@ -26,6 +26,7 @@ static constexpr int kApiPoint = 1;
static constexpr int kBookmark = 2;
static constexpr int kMyPosition = 3;
static constexpr int kSearch = 4;
static constexpr int kTrack = 5;
static constexpr int kPriceRateUndefined = -1;
@@ -34,6 +35,9 @@ void InjectMetadata(JNIEnv * env, jclass clazz, jobject const mapObject, feature
jobject CreateMapObject(JNIEnv * env, place_page::Info const & info);
jobject CreateTrack(JNIEnv * env, place_page::Info const & info, jni::TScopedLocalObjectArrayRef const & jrawTypes,
jni::TScopedLocalRef const & routingPointInfo, jobject const & popularity);
jobject CreateElevationInfo(JNIEnv * env, ElevationInfo const & info);
jobjectArray ToRatingArray(JNIEnv * env, std::vector<std::string> const & ratingCategories);

View File

@@ -447,6 +447,16 @@ JNIEXPORT jobject JNICALL Java_app_organicmaps_sdk_bookmarks_data_BookmarkManage
return usermark_helper::CreateMapObject(env, g_framework->GetPlacePageInfo());
}
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeUpdateTrackPlacePage(JNIEnv * env,
jobject,
jlong trackId)
{
if (!frm()->HasPlacePageInfo())
return;
frm()->UpdatePlacePageInfoForCurrentSelection();
}
JNIEXPORT jobject JNICALL Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetBookmarkInfo(JNIEnv * env,
jobject,
jlong bmkId)
@@ -824,13 +834,11 @@ Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeRemoveElevationCur
}
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeSetElevationActivePoint(
JNIEnv *, jclass, jlong trackId, jdouble distanceInMeters)
JNIEnv *, jclass, jlong trackId, jdouble distanceInMeters, jdouble latitude, jdouble longitude)
{
auto & bm = frm()->GetBookmarkManager();
bm.SetElevationActivePoint(
static_cast<kml::TrackId>(trackId),
{0,
0}, // todo(KK): replace with coordinates from the elevation profile point to show selection mark on the track
bm.SetElevationActivePoint(static_cast<kml::TrackId>(trackId),
m2::PointD(static_cast<double>(latitude), static_cast<double>(longitude)),
static_cast<double>(distanceInMeters));
}
@@ -858,4 +866,41 @@ Java_app_organicmaps_sdk_widget_placepage_PlacePageButtonFactory_nativeHasRecent
{
return frm()->GetBookmarkManager().HasRecentlyDeletedBookmark();
}
JNIEXPORT jobject JNICALL Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetTrackElevationInfo(
JNIEnv * env, jclass clazz, jlong track_id)
{
auto const & track = frm()->GetBookmarkManager().GetTrack(track_id);
auto const & elevationInfo = track->GetElevationInfo();
return usermark_helper::CreateElevationInfo(env, elevationInfo.value());
}
JNIEXPORT jboolean JNICALL Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeIsElevationInfoHasValue(
JNIEnv * env, jclass clazz, jlong track_id)
{
return static_cast<jboolean>(frm()->GetBookmarkManager().GetTrack(track_id)->GetElevationInfo().has_value());
}
JNIEXPORT jobject JNICALL Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetTrackStatistics(
JNIEnv * env, jclass clazz, jlong track_id)
{
static jmethodID const cId = jni::GetConstructorID(env, g_trackStatisticsClazz, "(DDDDII)V");
auto const trackStats = frm()->GetBookmarkManager().GetTrack(track_id)->GetStatistics();
return env->NewObject(g_trackStatisticsClazz, cId, static_cast<jdouble>(trackStats.m_length),
static_cast<jdouble>(trackStats.m_duration), static_cast<jdouble>(trackStats.m_ascent),
static_cast<jdouble>(trackStats.m_descent), static_cast<jint>(trackStats.m_minElevation),
static_cast<jint>(trackStats.m_maxElevation));
}
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetElevationActivePointCoordinates(JNIEnv * env,
jclass clazz,
jlong track_id)
{
static jclass const pointClass =
jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/ElevationInfo$Point");
static jmethodID const pointCtorId = jni::GetConstructorID(env, pointClass, "(DIDD)V");
auto const & trackInfo = frm()->GetBookmarkManager().GetTrackSelectionInfo(track_id);
auto const latlon = mercator::ToLatLon(trackInfo.m_trackPoint);
return env->NewObject(pointClass, pointCtorId, 0.0, 0, static_cast<jdouble>(latlon.m_lat),
static_cast<jdouble>(latlon.m_lon));
}
} // extern "C"

View File

@@ -21,6 +21,8 @@ extern JavaVM * GetJVM()
jclass g_mapObjectClazz;
jclass g_featureIdClazz;
jclass g_bookmarkClazz;
jclass g_trackClazz;
jclass g_trackStatisticsClazz;
jclass g_httpClientClazz;
jclass g_httpParamsClazz;
jclass g_platformSocketClazz;
@@ -57,6 +59,8 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM * jvm, void *)
JNIEnv * env = jni::GetEnv();
g_mapObjectClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/MapObject");
g_featureIdClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/FeatureId");
g_trackClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/Track");
g_trackStatisticsClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/TrackStatistics");
g_bookmarkClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/Bookmark");
g_httpClientClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/util/HttpClient");
g_httpParamsClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/util/HttpClient$Params");
@@ -85,6 +89,8 @@ JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *, void *)
env->DeleteGlobalRef(g_mapObjectClazz);
env->DeleteGlobalRef(g_featureIdClazz);
env->DeleteGlobalRef(g_bookmarkClazz);
env->DeleteGlobalRef(g_trackClazz);
env->DeleteGlobalRef(g_trackStatisticsClazz);
env->DeleteGlobalRef(g_httpClientClazz);
env->DeleteGlobalRef(g_httpParamsClazz);
env->DeleteGlobalRef(g_platformSocketClazz);

View File

@@ -18,6 +18,8 @@
extern jclass g_mapObjectClazz;
extern jclass g_featureIdClazz;
extern jclass g_bookmarkClazz;
extern jclass g_trackClazz;
extern jclass g_trackStatisticsClazz;
extern jclass g_httpClientClazz;
extern jclass g_httpParamsClazz;
extern jclass g_platformSocketClazz;

View File

@@ -866,7 +866,7 @@ void BookmarkManager::SetElevationActivePoint(kml::TrackId const & trackId, m2::
auto const track = GetTrack(trackId);
CHECK(track != nullptr, ());
SetTrackSelectionInfo({trackId, pt, targetDistance}, false /* notifyListeners */);
SetTrackSelectionInfo({trackId, pt, targetDistance}, true /* notifyListeners */);
m_drapeEngine.SafeCall(&df::DrapeEngine::SelectObject, df::SelectionShape::ESelectedObject::OBJECT_TRACK, pt,
FeatureID(), false /* isAnim */, false /* isGeometrySelectionAllowed */,

View File

@@ -2173,16 +2173,8 @@ place_page::Info Framework::BuildPlacePageInfo(place_page::BuildInfo const & bui
FeatureID selectedFeature = buildInfo.m_featureId;
auto const isFeatureMatchingEnabled = buildInfo.IsFeatureMatchingEnabled();
// @TODO: (KK) Enable track selection.
// The isTrackSelectionEnabled should be removed to enable the track selection when the UI will be implemented.
#if defined(TARGET_OS_IPHONE)
bool constexpr isTrackSelectionEnabled = true;
#else
bool constexpr isTrackSelectionEnabled = false;
#endif
// Using VisualParams inside FindTrackInTapPosition/GetDefaultTapRect requires drapeEngine.
if (isTrackSelectionEnabled && m_drapeEngine != nullptr && buildInfo.IsTrackMatchingEnabled() &&
if (m_drapeEngine != nullptr && buildInfo.IsTrackMatchingEnabled() &&
!(isFeatureMatchingEnabled && selectedFeature.IsValid()))
{
Track::TrackSelectionInfo trackSelectionInfo;