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

View File

@@ -2,6 +2,7 @@ package app.organicmaps.sdk.bookmarks.data;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.os.Parcel; import android.os.Parcel;
import androidx.annotation.ColorInt;
import androidx.annotation.IntRange; import androidx.annotation.IntRange;
import androidx.annotation.Keep; import androidx.annotation.Keep;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@@ -110,6 +111,14 @@ public class Bookmark extends MapObject
mCategoryId = catId; 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) public void setParams(@NonNull String title, @Nullable Icon icon, @NonNull String description)
{ {
BookmarkManager.INSTANCE.notifyParametersUpdating(this, title, icon, description); BookmarkManager.INSTANCE.notifyParametersUpdating(this, title, icon, description);

View File

@@ -263,6 +263,12 @@ public enum BookmarkManager {
return nativeUpdateBookmarkPlacePage(bmkId); return nativeUpdateBookmarkPlacePage(bmkId);
} }
@Nullable
public void updateTrackPlacePage(long trackId)
{
nativeUpdateTrackPlacePage(trackId);
}
@Nullable @Nullable
public BookmarkInfo getBookmarkInfo(long bmkId) public BookmarkInfo getBookmarkInfo(long bmkId)
{ {
@@ -729,9 +735,9 @@ public enum BookmarkManager {
return nativeGetElevationCurPositionDistance(trackId); 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) public double getElevationActivePointDistance(long trackId)
@@ -739,9 +745,14 @@ public enum BookmarkManager {
return nativeGetElevationActivePointDistance(trackId); return nativeGetElevationActivePointDistance(trackId);
} }
private static native ElevationInfo.Point nativeGetElevationActivePointCoordinates(long trackId);
@Nullable @Nullable
private native Bookmark nativeUpdateBookmarkPlacePage(long bmkId); private native Bookmark nativeUpdateBookmarkPlacePage(long bmkId);
@Nullable
private native void nativeUpdateTrackPlacePage(long trackId);
@Nullable @Nullable
private native BookmarkInfo nativeGetBookmarkInfo(long bmkId); private native BookmarkInfo nativeGetBookmarkInfo(long bmkId);
@@ -892,14 +903,25 @@ public enum BookmarkManager {
public static native void nativeRemoveElevationCurrentPositionChangedListener(); 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); private static native double nativeGetElevationActivePointDistance(long trackId);
public ElevationInfo.Point getElevationActivePointCoordinates(long trackId)
{
return nativeGetElevationActivePointCoordinates(trackId);
}
private static native void nativeSetElevationActiveChangedListener(); private static native void nativeSetElevationActiveChangedListener();
public static native void nativeRemoveElevationActiveChangedListener(); 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 public interface BookmarksLoadingListener
{ {
default void onBookmarksLoadingStarted() {} default void onBookmarksLoadingStarted() {}

View File

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

View File

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

View File

@@ -1,21 +1,32 @@
package app.organicmaps.sdk.bookmarks.data; package app.organicmaps.sdk.bookmarks.data;
import androidx.annotation.IntRange;
import androidx.annotation.Keep; 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; import app.organicmaps.sdk.util.Distance;
// Called from JNI. // Called from JNI.
@Keep @Keep
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class Track public class Track extends MapObject
{ {
private final long mTrackId; private final long mTrackId;
private final long mCategoryId; private long mCategoryId;
private final String mName; private final String mName;
private final Distance mLength; 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) 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; mTrackId = trackId;
mCategoryId = categoryId; mCategoryId = categoryId;
mName = name; mName = name;
@@ -23,6 +34,34 @@ public class Track
mColor = color; 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() public String getName()
{ {
return mName; return mName;
@@ -52,4 +91,25 @@ public class Track
{ {
return BookmarkManager.INSTANCE.getTrackDescription(mTrackId); 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; package app.organicmaps.widget.placepage;
import androidx.annotation.NonNull; 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.charts.BarLineChartBase;
import com.github.mikephil.charting.formatter.DefaultValueFormatter; import com.github.mikephil.charting.formatter.DefaultValueFormatter;
@@ -20,6 +20,6 @@ public class AxisValueFormatter extends DefaultValueFormatter
@Override @Override
public String getFormattedValue(float value) 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; package app.organicmaps.widget.placepage;
import android.content.Context; import android.content.Context;
import android.os.Bundle;
import android.view.View; import android.view.View;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
@@ -12,18 +11,19 @@ import app.organicmaps.ChartController;
import app.organicmaps.R; import app.organicmaps.R;
import app.organicmaps.sdk.Framework; import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.bookmarks.data.ElevationInfo; 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.util.UiUtils;
import app.organicmaps.sdk.widget.placepage.PlacePageData;
import app.organicmaps.util.Utils; import app.organicmaps.util.Utils;
import java.util.Objects; import java.util.Objects;
@SuppressWarnings("unused") // https://github.com/organicmaps/organicmaps/issues/2829
public class ElevationProfileViewRenderer implements PlacePageStateListener public class ElevationProfileViewRenderer implements PlacePageStateListener
{ {
// Must be correspond to map/elevation_info.hpp constants. // Must be correspond to map/elevation_info.hpp constants.
private static final int MAX_DIFFICULTY_LEVEL = 3; private static final int MAX_DIFFICULTY_LEVEL = 3;
private static final int UNKNOWN_DIFFICULTY = 0; private static final int UNKNOWN_DIFFICULTY = 0;
@NonNull
private final View[] mDifficultyLevels = new View[MAX_DIFFICULTY_LEVEL];
@SuppressWarnings("NullableProblems") @SuppressWarnings("NullableProblems")
@NonNull @NonNull
private NestedScrollView mScrollView; private NestedScrollView mScrollView;
@@ -45,8 +45,6 @@ public class ElevationProfileViewRenderer implements PlacePageStateListener
@SuppressWarnings("NullableProblems") @SuppressWarnings("NullableProblems")
@NonNull @NonNull
private TextView mTime; private TextView mTime;
@NonNull
private final View[] mDifficultyLevels = new View[MAX_DIFFICULTY_LEVEL];
@SuppressWarnings("NullableProblems") @SuppressWarnings("NullableProblems")
@NonNull @NonNull
private ChartController mChartController; private ChartController mChartController;
@@ -58,23 +56,7 @@ public class ElevationProfileViewRenderer implements PlacePageStateListener
@SuppressWarnings("NullableProblems") @SuppressWarnings("NullableProblems")
@NonNull @NonNull
private View mTimeContainer; private View mTimeContainer;
private View mTitleContainer;
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));
}
@NonNull @NonNull
private static String formatDistance(final Context context, int distance) private static String formatDistance(final Context context, int distance)
@@ -82,6 +64,24 @@ public class ElevationProfileViewRenderer implements PlacePageStateListener
return Framework.nativeFormatAltitude(distance); 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) public void initialize(@Nullable View view)
{ {
Objects.requireNonNull(view); Objects.requireNonNull(view);
@@ -89,6 +89,7 @@ public class ElevationProfileViewRenderer implements PlacePageStateListener
mChartController.initialize(view); mChartController.initialize(view);
mScrollView = (NestedScrollView) view; mScrollView = (NestedScrollView) view;
mTitle = view.findViewById(R.id.title); mTitle = view.findViewById(R.id.title);
mTitleContainer = view.findViewById(R.id.title_container);
mAscent = view.findViewById(R.id.ascent); mAscent = view.findViewById(R.id.ascent);
mDescent = view.findViewById(R.id.descent); mDescent = view.findViewById(R.id.descent);
mMaxAltitude = view.findViewById(R.id.max_altitude); mMaxAltitude = view.findViewById(R.id.max_altitude);
@@ -123,21 +124,13 @@ public class ElevationProfileViewRenderer implements PlacePageStateListener
mDifficultyLevels[i].setEnabled(true); 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, mChartController.onCurrentPositionChanged();
// ElevationInfo.class); if (mElevationInfo != null)
// render(mElevationInfo);
}
public void onHide()
{
mScrollView.scrollTo(0, 0);
mChartController.onHide();
} }
} }

View File

@@ -37,9 +37,6 @@ public class FloatingMarkerView extends RelativeLayout implements IMarker
private TextView mAltitudeView; private TextView mAltitudeView;
@SuppressWarnings("NullableProblems") @SuppressWarnings("NullableProblems")
@NonNull @NonNull
private TextView mDistanceTextView;
@SuppressWarnings("NullableProblems")
@NonNull
private TextView mDistanceValueView; private TextView mDistanceValueView;
@SuppressWarnings("NullableProblems") @SuppressWarnings("NullableProblems")
@NonNull @NonNull
@@ -93,7 +90,6 @@ public class FloatingMarkerView extends RelativeLayout implements IMarker
mTextContentContainer = findViewById(R.id.floating_text_container); mTextContentContainer = findViewById(R.id.floating_text_container);
mFloatingTriangle = findViewById(R.id.floating_triangle); mFloatingTriangle = findViewById(R.id.floating_triangle);
mImage = findViewById(R.id.image); mImage = findViewById(R.id.image);
mDistanceTextView = findViewById(R.id.distance_text);
mAltitudeView = findViewById(R.id.altitude); mAltitudeView = findViewById(R.id.altitude);
mDistanceValueView = findViewById(R.id.distance_value); 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) public void updateOffsets(@NonNull Entry entry, @NonNull Highlight highlight)
{ {
updateVertical(entry); 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); boolean isLeftToRightDirection = isInvertedOrder(highlight);
mOffset = isLeftToRightDirection ? -getWidth() + halfImg : -halfImg; mOffset = isLeftToRightDirection ? -getWidth() + halfImg : -halfImg;
updateHorizontal(highlight); updateHorizontal(highlight);
@@ -184,7 +180,6 @@ public class FloatingMarkerView extends RelativeLayout implements IMarker
private void updatePointValues(@NonNull Entry entry) private void updatePointValues(@NonNull Entry entry)
{ {
mDistanceTextView.setText(R.string.elevation_profile_distance);
mDistanceValueView.setText( mDistanceValueView.setText(
StringUtils.nativeFormatDistance(entry.getX()).toString(mDistanceValueView.getContext())); StringUtils.nativeFormatDistance(entry.getX()).toString(mDistanceValueView.getContext()));
mAltitudeView.setText(Framework.nativeFormatAltitude(entry.getY())); mAltitudeView.setText(Framework.nativeFormatAltitude(entry.getY()));

View File

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

View File

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

View File

@@ -2,6 +2,7 @@ package app.organicmaps.widget.placepage;
import android.animation.ValueAnimator; import android.animation.ValueAnimator;
import android.app.Activity; import android.app.Activity;
import android.app.Dialog;
import android.content.Intent; import android.content.Intent;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Bundle; 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.BookmarkManager;
import app.organicmaps.sdk.bookmarks.data.MapObject; import app.organicmaps.sdk.bookmarks.data.MapObject;
import app.organicmaps.sdk.bookmarks.data.RoadWarningMarkType; import app.organicmaps.sdk.bookmarks.data.RoadWarningMarkType;
import app.organicmaps.sdk.bookmarks.data.Track;
import app.organicmaps.sdk.routing.RoutingController; import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.settings.RoadType; import app.organicmaps.sdk.settings.RoadType;
import app.organicmaps.sdk.util.UiUtils; 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.MenuBottomSheetFragment;
import app.organicmaps.util.bottomsheet.MenuBottomSheetItem; import app.organicmaps.util.bottomsheet.MenuBottomSheetItem;
import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.shape.MaterialShapeDrawable; import com.google.android.material.shape.MaterialShapeDrawable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -74,6 +77,7 @@ public class PlacePageController
private ValueAnimator mCustomPeekHeightAnimator; private ValueAnimator mCustomPeekHeightAnimator;
private PlacePageRouteSettingsListener mPlacePageRouteSettingsListener; private PlacePageRouteSettingsListener mPlacePageRouteSettingsListener;
private Dialog mAlertDialog;
private final Observer<Integer> mPlacePageDistanceToTopObserver = new Observer<>() { private final Observer<Integer> mPlacePageDistanceToTopObserver = new Observer<>() {
private float mPlacePageCornerRadius; private float mPlacePageCornerRadius;
@@ -120,7 +124,6 @@ public class PlacePageController
bg.setCornerSize(mPlacePageCornerRadius); bg.setCornerSize(mPlacePageCornerRadius);
} }
}; };
private final BottomSheetBehavior.BottomSheetCallback mDefaultBottomSheetCallback = private final BottomSheetBehavior.BottomSheetCallback mDefaultBottomSheetCallback =
new BottomSheetBehavior.BottomSheetCallback() { new BottomSheetBehavior.BottomSheetCallback() {
@Override @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 @Nullable
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@@ -202,18 +217,6 @@ public class PlacePageController
ViewCompat.requestApplyInsets(mPlacePage); 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() private void stopCustomPeekHeightAnimation()
{ {
if (mCustomPeekHeightAnimator != null && mCustomPeekHeightAnimator.isStarted()) if (mCustomPeekHeightAnimator != null && mCustomPeekHeightAnimator.isStarted())
@@ -415,6 +418,7 @@ public class PlacePageController
switch (item) switch (item)
{ {
case BOOKMARK_SAVE, BOOKMARK_DELETE -> onBookmarkBtnClicked(); case BOOKMARK_SAVE, BOOKMARK_DELETE -> onBookmarkBtnClicked();
case TRACK_DELETE -> onTrackRemoveClicked();
case BACK -> onBackBtnClicked(); case BACK -> onBackBtnClicked();
case ROUTE_FROM -> onRouteFromBtnClicked(); case ROUTE_FROM -> onRouteFromBtnClicked();
case ROUTE_TO -> onRouteToBtnClicked(); case ROUTE_TO -> onRouteToBtnClicked();
@@ -439,6 +443,48 @@ public class PlacePageController
BookmarkManager.INSTANCE.addNewBookmark(mMapObject.getLat(), mMapObject.getLon()); 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() private void onBackBtnClicked()
{ {
if (mMapObject == null) if (mMapObject == null)
@@ -577,8 +623,12 @@ public class PlacePageController
if (needToShowRoutingButtons && RoutingController.get().isStopPointAllowed()) if (needToShowRoutingButtons && RoutingController.get().isStopPointAllowed())
buttons.add(PlacePageButtons.ButtonType.ROUTE_ADD); buttons.add(PlacePageButtons.ButtonType.ROUTE_ADD);
else else
{
buttons.add(mapObject.isBookmark() ? PlacePageButtons.ButtonType.BOOKMARK_DELETE buttons.add(mapObject.isBookmark() ? PlacePageButtons.ButtonType.BOOKMARK_DELETE
: PlacePageButtons.ButtonType.BOOKMARK_SAVE); : PlacePageButtons.ButtonType.BOOKMARK_SAVE);
if (mapObject.isTrack())
buttons.add(PlacePageButtons.ButtonType.TRACK_DELETE);
}
if (needToShowRoutingButtons) 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 // Place page will automatically open when the bottom sheet content is loaded so we can compute the peek height
createPlacePageFragments(); createPlacePageFragments();
updateButtons(mapObject, showBackButton, !mMapObject.isMyPosition()); updateButtons(mapObject, showBackButton, !mMapObject.isMyPosition());
if (mViewModel.isAlertDialogShowing)
showTrackDeleteAlertDialog();
} }
else else
close(); close();

View File

@@ -6,6 +6,7 @@ import static app.organicmaps.sdk.util.Utils.getLocalizedFeatureType;
import static app.organicmaps.sdk.util.Utils.getTagValueLocalized; import static app.organicmaps.sdk.util.Utils.getTagValueLocalized;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Drawable;
import android.location.Location; import android.location.Location;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
@@ -16,25 +17,39 @@ import android.text.style.ForegroundColorSpan;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import androidx.activity.result.ActivityResultLauncher;
import androidx.annotation.IdRes; import androidx.annotation.IdRes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentFactory;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Observer; import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import app.organicmaps.MwmActivity; import app.organicmaps.MwmActivity;
import app.organicmaps.MwmApplication; import app.organicmaps.MwmApplication;
import app.organicmaps.R; import app.organicmaps.R;
import app.organicmaps.bookmarks.BookmarksSharingHelper;
import app.organicmaps.bookmarks.ChooseBookmarkCategoryFragment;
import app.organicmaps.downloader.DownloaderStatusIcon; import app.organicmaps.downloader.DownloaderStatusIcon;
import app.organicmaps.editor.OhState; import app.organicmaps.editor.OhState;
import app.organicmaps.sdk.Framework; 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.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.MapObject;
import app.organicmaps.sdk.bookmarks.data.Metadata; 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.CountryItem;
import app.organicmaps.sdk.downloader.MapManager; import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.editor.Editor; 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.UiUtils;
import app.organicmaps.sdk.util.concurrency.UiThread; import app.organicmaps.sdk.util.concurrency.UiThread;
import app.organicmaps.sdk.widget.placepage.CoordinatesFormat; import app.organicmaps.sdk.widget.placepage.CoordinatesFormat;
import app.organicmaps.util.Graphics;
import app.organicmaps.util.SharingUtils; import app.organicmaps.util.SharingUtils;
import app.organicmaps.util.Utils; 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.ArrowView;
import app.organicmaps.widget.placepage.sections.PlacePageBookmarkFragment; import app.organicmaps.widget.placepage.sections.PlacePageBookmarkFragment;
import app.organicmaps.widget.placepage.sections.PlacePageLinksFragment; import app.organicmaps.widget.placepage.sections.PlacePageLinksFragment;
import app.organicmaps.widget.placepage.sections.PlacePageOpeningHoursFragment; import app.organicmaps.widget.placepage.sections.PlacePageOpeningHoursFragment;
import app.organicmaps.widget.placepage.sections.PlacePagePhoneFragment; import app.organicmaps.widget.placepage.sections.PlacePagePhoneFragment;
import app.organicmaps.widget.placepage.sections.PlacePageTrackFragment;
import app.organicmaps.widget.placepage.sections.PlacePageWikipediaFragment; import app.organicmaps.widget.placepage.sections.PlacePageWikipediaFragment;
import com.google.android.material.appbar.MaterialToolbar; import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.button.MaterialButton; import com.google.android.material.button.MaterialButton;
@@ -68,15 +87,19 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
public class PlacePageView extends Fragment 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 PREF_COORDINATES_FORMAT = "coordinates_format";
private static final String BOOKMARK_FRAGMENT_TAG = "BOOKMARK_FRAGMENT_TAG"; 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 WIKIPEDIA_FRAGMENT_TAG = "WIKIPEDIA_FRAGMENT_TAG";
private static final String PHONE_FRAGMENT_TAG = "PHONE_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 OPENING_HOURS_FRAGMENT_TAG = "OPENING_HOURS_FRAGMENT_TAG";
private static final String LINKS_FRAGMENT_TAG = "LINKS_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 = private static final List<CoordinatesFormat> visibleCoordsFormat =
Arrays.asList(CoordinatesFormat.LatLonDMS, CoordinatesFormat.LatLonDecimal, CoordinatesFormat.OLCFull, Arrays.asList(CoordinatesFormat.LatLonDMS, CoordinatesFormat.LatLonDecimal, CoordinatesFormat.OLCFull,
@@ -124,12 +147,16 @@ public class PlacePageView extends Fragment
private View mAddOrganisation; private View mAddOrganisation;
private View mAddPlace; private View mAddPlace;
private View mEditTopSpace; private View mEditTopSpace;
private ImageView mColorIcon;
private TextView mTvCategory;
private ImageView mEditBookmark;
// Data // Data
private CoordinatesFormat mCoordsFormat = CoordinatesFormat.LatLonDecimal; private CoordinatesFormat mCoordsFormat = CoordinatesFormat.LatLonDecimal;
// Downloader`s stuff // Downloader`s stuff
private DownloaderStatusIcon mDownloaderIcon; private DownloaderStatusIcon mDownloaderIcon;
private MaterialTextView mDownloaderInfo; private MaterialTextView mDownloaderInfo;
private ActivityResultLauncher<SharingUtils.SharingIntent> shareLauncher;
private int mStorageCallbackSlot; private int mStorageCallbackSlot;
@Nullable @Nullable
private CountryItem mCurrentCountry; private CountryItem mCurrentCountry;
@@ -185,6 +212,7 @@ public class PlacePageView extends Fragment
@Nullable Bundle savedInstanceState) @Nullable Bundle savedInstanceState)
{ {
mViewModel = new ViewModelProvider(requireActivity()).get(PlacePageViewModel.class); mViewModel = new ViewModelProvider(requireActivity()).get(PlacePageViewModel.class);
shareLauncher = SharingUtils.RegisterLauncher(this);
return inflater.inflate(R.layout.place_page, container, false); return inflater.inflate(R.layout.place_page, container, false);
} }
@@ -232,8 +260,12 @@ public class PlacePageView extends Fragment
mTvAddress.setOnLongClickListener(this); mTvAddress.setOnLongClickListener(this);
mTvAddress.setOnClickListener(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); 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); final MaterialButton closeButton = mPreview.findViewById(R.id.close_button);
closeButton.setOnClickListener((v) -> mPlacePageViewListener.onPlacePageRequestClose()); closeButton.setOnClickListener((v) -> mPlacePageViewListener.onPlacePageRequestClose());
@@ -301,6 +333,7 @@ public class PlacePageView extends Fragment
{ {
super.onStart(); super.onStart();
mViewModel.getMapObject().observe(requireActivity(), this); mViewModel.getMapObject().observe(requireActivity(), this);
BookmarkManager.INSTANCE.addSharingListener(this);
MwmApplication.from(requireContext()).getLocationHelper().addListener(this); MwmApplication.from(requireContext()).getLocationHelper().addListener(this);
MwmApplication.from(requireContext()).getSensorHelper().addListener(this); MwmApplication.from(requireContext()).getSensorHelper().addListener(this);
} }
@@ -310,6 +343,7 @@ public class PlacePageView extends Fragment
{ {
super.onStop(); super.onStop();
mViewModel.getMapObject().removeObserver(this); mViewModel.getMapObject().removeObserver(this);
BookmarkManager.INSTANCE.removeSharingListener(this);
MwmApplication.from(requireContext()).getLocationHelper().removeListener(this); MwmApplication.from(requireContext()).getLocationHelper().removeListener(this);
MwmApplication.from(requireContext()).getSensorHelper().removeListener(this); MwmApplication.from(requireContext()).getSensorHelper().removeListener(this);
UiThread.cancelDelayedTasks(updateOpenState); UiThread.cancelDelayedTasks(updateOpenState);
@@ -334,6 +368,10 @@ public class PlacePageView extends Fragment
refreshMyPosition(loc); refreshMyPosition(loc);
else else
refreshDistanceToObject(loc); 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, private <T extends Fragment> void updateViewFragment(Class<T> controllerClass, String fragmentTag,
@@ -375,6 +413,12 @@ public class PlacePageView extends Fragment
mMapObject.isBookmark()); mMapObject.isBookmark());
} }
private void updateTrackView()
{
updateViewFragment(PlacePageTrackFragment.class, TRACK_FRAGMENT_TAG, R.id.place_page_track_fragment,
mMapObject.isTrack());
}
private boolean hasWikipediaEntry() private boolean hasWikipediaEntry()
{ {
final String wikipediaLink = mMapObject.getMetadata(Metadata.MetadataType.FMD_WIKIPEDIA); final String wikipediaLink = mMapObject.getMetadata(Metadata.MetadataType.FMD_WIKIPEDIA);
@@ -416,6 +460,180 @@ public class PlacePageView extends Fragment
mToolbar.setTitle(mMapObject.getTitle()); mToolbar.setTitle(mMapObject.getTitle());
setTextAndColorizeSubtitle(); setTextAndColorizeSubtitle();
UiUtils.setTextAndHideIfEmpty(mTvAddress, mMapObject.getAddress()); 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() private void refreshDetails()
@@ -494,6 +712,7 @@ public class PlacePageView extends Fragment
updateWikipediaView(); updateWikipediaView();
updateBookmarkView(); updateBookmarkView();
updatePhoneView(); updatePhoneView();
updateTrackView();
} }
private void refreshWiFi() private void refreshWiFi()
@@ -532,6 +751,8 @@ public class PlacePageView extends Fragment
private void refreshDistanceToObject(Location l) private void refreshDistanceToObject(Location l)
{ {
if (mMapObject.isTrack())
return;
UiUtils.showIf(l != null, mTvDistance); UiUtils.showIf(l != null, mTvDistance);
if (l == null) if (l == null)
return; return;
@@ -660,6 +881,12 @@ public class PlacePageView extends Fragment
} }
else if (id == R.id.direction_frame) else if (id == R.id.direction_frame)
showBigDirection(); 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() private void showBigDirection()
@@ -818,7 +1045,7 @@ public class PlacePageView extends Fragment
@Override @Override
public void onCompassUpdated(double north) public void onCompassUpdated(double north)
{ {
if (mMapObject == null || mMapObject.isMyPosition()) if (mMapObject == null || mMapObject.isMyPosition() || mMapObject.isTrack())
return; return;
final Location location = MwmApplication.from(requireContext()).getLocationHelper().getSavedLocation(); 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 public interface PlacePageViewListener
{ {
// Called when the content has actually changed and we are ready to compute the peek height // 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 onPlacePageRequestToggleState();
void onPlacePageRequestClose(); 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.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel; 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.MapObject;
import app.organicmaps.sdk.bookmarks.data.Track;
import java.util.List; import java.util.List;
public class PlacePageViewModel extends ViewModel public class PlacePageViewModel extends ViewModel
@@ -12,6 +15,7 @@ public class PlacePageViewModel extends ViewModel
private final MutableLiveData<MapObject> mMapObject = new MutableLiveData<>(); private final MutableLiveData<MapObject> mMapObject = new MutableLiveData<>();
private final MutableLiveData<Integer> mPlacePageWidth = new MutableLiveData<>(); private final MutableLiveData<Integer> mPlacePageWidth = new MutableLiveData<>();
private final MutableLiveData<Integer> mPlacePageDistanceToTop = new MutableLiveData<>(); private final MutableLiveData<Integer> mPlacePageDistanceToTop = new MutableLiveData<>();
public boolean isAlertDialogShowing = false;
public LiveData<List<PlacePageButtons.ButtonType>> getCurrentButtons() public LiveData<List<PlacePageButtons.ButtonType>> getCurrentButtons()
{ {
@@ -33,6 +37,38 @@ public class PlacePageViewModel extends ViewModel
mMapObject.setValue(mapObject); 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() public MutableLiveData<Integer> getPlacePageWidth()
{ {
return mPlacePageWidth; return mPlacePageWidth;

View File

@@ -16,23 +16,18 @@ import android.widget.LinearLayout;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.Observer; import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import app.organicmaps.R; import app.organicmaps.R;
import app.organicmaps.sdk.bookmarks.data.Bookmark; 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.bookmarks.data.MapObject;
import app.organicmaps.sdk.util.StringUtils; import app.organicmaps.sdk.util.StringUtils;
import app.organicmaps.sdk.util.UiUtils; import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.util.Utils; import app.organicmaps.util.Utils;
import app.organicmaps.widget.placepage.EditBookmarkFragment;
import app.organicmaps.widget.placepage.PlacePageViewModel; import app.organicmaps.widget.placepage.PlacePageViewModel;
import com.google.android.material.textview.MaterialTextView; import com.google.android.material.textview.MaterialTextView;
public class PlacePageBookmarkFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener, public class PlacePageBookmarkFragment extends Fragment implements View.OnLongClickListener, Observer<MapObject>
Observer<MapObject>,
EditBookmarkFragment.EditBookmarkListener
{ {
private View mFrame; private View mFrame;
private MaterialTextView mTvBookmarkNote; private MaterialTextView mTvBookmarkNote;
@@ -60,8 +55,6 @@ public class PlacePageBookmarkFragment extends Fragment implements View.OnClickL
mFrame = view; mFrame = view;
mTvBookmarkNote = mFrame.findViewById(R.id.tv__bookmark_notes); mTvBookmarkNote = mFrame.findViewById(R.id.tv__bookmark_notes);
mTvBookmarkNote.setOnLongClickListener(this); mTvBookmarkNote.setOnLongClickListener(this);
final View editBookmarkBtn = mFrame.findViewById(R.id.tv__bookmark_edit);
editBookmarkBtn.setOnClickListener(this);
} }
private void initWebView() 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 @Override
public boolean onLongClick(View v) public boolean onLongClick(View v)
{ {
@@ -156,13 +141,4 @@ public class PlacePageBookmarkFragment extends Fragment implements View.OnClickL
updateBookmarkDetails(); 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:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/elevation_profile" android:id="@+id/elevation_profile"
android:layout_width="@dimen/place_page_width" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="@dimen/margin_base" android:paddingTop="@dimen/margin_base"
android:paddingBottom="@dimen/margin_base" android:paddingBottom="@dimen/margin_base"

View File

@@ -8,7 +8,9 @@
<app.organicmaps.widget.placepage.ElevationProfileChart <app.organicmaps.widget.placepage.ElevationProfileChart
android:id="@+id/elevation_profile_chart" android:id="@+id/elevation_profile_chart"
android:layout_width="match_parent" 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 <app.organicmaps.widget.placepage.FloatingMarkerView
android:id="@+id/floating_marker" android:id="@+id/floating_marker"
android:visibility="gone" android:visibility="gone"

View File

@@ -1,37 +1,20 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/elevation_profile" android:id="@+id/elevation_profile"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="@dimen/margin_half_plus"
android:paddingBottom="@dimen/margin_base"
android:background="?cardBackground" android:background="?cardBackground"
android:clickable="true" android:clickable="true"
android:focusable="true"
android:fillViewport="true" android:fillViewport="true"
android:focusable="true"
app:behavior_peekHeight="@dimen/elevation_profile_peek_height" app:behavior_peekHeight="@dimen/elevation_profile_peek_height"
app:layout_behavior="@string/placepage_behavior"> app:layout_behavior="@string/placepage_behavior">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> 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" /> <include layout="@layout/elevation_profile_internal" />
</LinearLayout> </LinearLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>

View File

@@ -4,22 +4,188 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:showIn="@layout/elevation_profile_bottom_sheet"> 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 <TextView
android:id="@+id/title" android:id="@+id/title"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="@dimen/margin_half"
android:layout_marginStart="@dimen/margin_base" android:layout_marginStart="@dimen/margin_base"
android:layout_marginEnd="@dimen/margin_base" android:layout_marginEnd="@dimen/margin_base"
android:paddingTop="@dimen/margin_half"
android:paddingBottom="@dimen/margin_base" android:paddingBottom="@dimen/margin_base"
android:textAppearance="?fontHeadline6" android:textAppearance="?fontHeadline6"
tools:text="Xindian Shitoushan Trail" /> tools:text="Xindian Shitoushan Trail" />
<include <include
layout="@layout/list_divider"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/divider_height" android:layout_height="@dimen/divider_height"
android:layout_marginStart="@dimen/margin_base" android:layout_marginStart="@dimen/margin_base"
android:layout_marginEnd="@dimen/margin_base" android:layout_marginEnd="@dimen/margin_base" />
layout="@layout/list_divider" /> </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 <LinearLayout
android:id="@+id/chart_container" android:id="@+id/chart_container"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -29,140 +195,11 @@
android:orientation="vertical"> android:orientation="vertical">
<include layout="@layout/elevation_profile" /> <include layout="@layout/elevation_profile" />
</LinearLayout> </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>
</LinearLayout>
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_base"
android:layout_marginStart="@dimen/margin_base" android:layout_marginStart="@dimen/margin_base"
android:layout_marginTop="@dimen/margin_quarter_plus"
android:layout_marginEnd="@dimen/margin_base" android:layout_marginEnd="@dimen/margin_base"
android:orientation="horizontal"> android:orientation="horizontal">
<LinearLayout <LinearLayout
@@ -174,15 +211,15 @@
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="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 <LinearLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="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_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 <TextView
android:id="@+id/difficulty_level_1" android:id="@+id/difficulty_level_1"
android:layout_width="@dimen/elevation_profile_difficulty_dot_size" android:layout_width="@dimen/elevation_profile_difficulty_dot_size"
@@ -206,27 +243,27 @@
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:layout_toEndOf="@id/difficulty_container"
android:layout_alignParentEnd="true"
android:id="@+id/time_container" android:id="@+id/time_container"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_toEndOf="@id/difficulty_container"
android:gravity="end" android:gravity="end"
android:orientation="horizontal"> android:orientation="horizontal">
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="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 <com.google.android.material.textview.MaterialTextView
android:id="@+id/time" android:id="@+id/time"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_half" android:layout_marginStart="@dimen/margin_half"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:textAppearanceMedium" android:textAppearance="?android:textAppearanceMedium"
android:textStyle="bold" android:textStyle="bold"
android:singleLine="true"
android:ellipsize="end"
tools:text="3 h. 25 min." /> tools:text="3 h. 25 min." />
</LinearLayout> </LinearLayout>
</RelativeLayout> </RelativeLayout>

View File

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

View File

@@ -18,16 +18,6 @@
android:textAppearance="?android:attr/textAppearance" 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 "/> 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 <include
layout="@layout/divider_horizontal"/> layout="@layout/divider_horizontal"/>
</LinearLayout> </LinearLayout>

View File

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

View File

@@ -5,8 +5,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical">
android:paddingBottom="@dimen/margin_quarter">
<include <include
android:id="@+id/pull_icon_container" android:id="@+id/pull_icon_container"
layout="@layout/bottom_sheet_handle" /> layout="@layout/bottom_sheet_handle" />
@@ -180,4 +179,62 @@
</LinearLayout> </LinearLayout>
</LinearLayout> </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> </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_width">320dp</dimen>
<dimen name="place_page_buttons_height">56dp</dimen> <dimen name="place_page_buttons_height">56dp</dimen>
<dimen name="place_page_top_button">40dp</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="downloader_status_size">40dp</dimen>
<dimen name="search_progress_size">32dp</dimen> <dimen name="search_progress_size">32dp</dimen>
@@ -75,12 +77,13 @@
<dimen name="viewport_min_width">300dp</dimen> <dimen name="viewport_min_width">300dp</dimen>
<dimen name="elevation_profile_peek_height">260dp</dimen> <dimen name="elevation_profile_peek_height">260dp</dimen>
<dimen name="elevation_profile_chart_min_height">144dp</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_difficulty_dot_size">10dp</dimen>
<dimen name="elevation_profile_content_height">144dp</dimen> <dimen name="elevation_profile_content_height">144dp</dimen>
<dimen name="elevation_profile_height">108dp</dimen> <dimen name="elevation_profile_height">80dp</dimen>
<dimen name="elevation_profile_half_height">54dp</dimen> <dimen name="elevation_profile_half_height">40dp</dimen>
<dimen name="elevation_profile_dot_levels_margin">3dp</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_size">48dp</dimen>
<dimen name="map_button_icon_size">28dp</dimen> <dimen name="map_button_icon_size">28dp</dimen>
<dimen name="map_button_arrow_icon_size">34dp</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_3">14sp</dimen>
<dimen name="text_size_body_4">12sp</dimen> <dimen name="text_size_body_4">12sp</dimen>
<dimen name="text_size_body_5">10sp</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_caption">14sp</dimen>
<dimen name="text_size_icon_title">10sp</dimen> <dimen name="text_size_icon_title">10sp</dimen>
<dimen name="text_size_button">16sp</dimen> <dimen name="text_size_button">16sp</dimen>

View File

@@ -971,4 +971,5 @@
<string name="closed_now">Closed now</string> <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" --> <!-- 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="at">at %s</string>
<string name="PP_track_bottom_sheet_title">Save Track As</string>
</resources> </resources>

View File

@@ -93,6 +93,11 @@
<item name="android:textColor">?android:textColorSecondary</item> <item name="android:textColor">?android:textColorSecondary</item>
</style> </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"> <style name="MwmTextAppearance.Button">
<item name="android:textSize">@dimen/text_size_button</item> <item name="android:textSize">@dimen/text_size_button</item>
<item name="android:textColor">?colorSecondary</item> <item name="android:textColor">?colorSecondary</item>

View File

@@ -17,6 +17,7 @@
<attr name="iconTintLight" format="color" /> <attr name="iconTintLight" format="color" />
<attr name="ppBackground" format="color" /> <attr name="ppBackground" format="color" />
<attr name="ppButtonsBackground" format="color" /> <attr name="ppButtonsBackground" format="color" />
<attr name="ppFloatingMarkerIconColor" format="color" />
<attr name="navNextTurnFrame" format="reference" /> <attr name="navNextTurnFrame" format="reference" />
<attr name="navNextNextTurnFrame" format="reference" /> <attr name="navNextNextTurnFrame" format="reference" />
<attr name="navLanesBackgroundColor" 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(); JNIEnv * env = jni::GetEnv();
auto const & info = frm()->GetCurrentPlacePageInfo(); auto const & info = frm()->GetCurrentPlacePageInfo();
jni::TScopedLocalRef placePageDataRef(env, nullptr); 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)); placePageDataRef.reset(usermark_helper::CreateMapObject(env, info));
env->CallVoidMethod(g_placePageActivationListener, activatedId, placePageDataRef.get()); env->CallVoidMethod(g_placePageActivationListener, activatedId, placePageDataRef.get());
}; };
auto const closePlacePage = [deactivateId]() auto const closePlacePage = [deactivateId]()

View File

@@ -88,6 +88,47 @@ jobject CreateMapObject(JNIEnv * env, place_page::Info const & info, int mapObje
return mapObject; 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, jobject CreateBookmark(JNIEnv * env, place_page::Info const & info, jni::TScopedLocalObjectArrayRef const & jrawTypes,
jni::TScopedLocalRef const & routingPointInfo, jobject const & popularity) jni::TScopedLocalRef const & routingPointInfo, jobject const & popularity)
{ {
@@ -129,10 +170,11 @@ jobject CreateElevationPoint(JNIEnv * env, ElevationInfo::Point const & point)
{ {
static jclass const pointClass = static jclass const pointClass =
jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/ElevationInfo$Point"); jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/ElevationInfo$Point");
// public Point(double distance, int altitude) // public Point(double distance, int altitude, double latitude, double longitude)
static jmethodID const pointCtorId = jni::GetConstructorID(env, pointClass, "(DI)V"); static jmethodID const pointCtorId = jni::GetConstructorID(env, pointClass, "(DIDD)V");
return env->NewObject(pointClass, pointCtorId, static_cast<jdouble>(point.m_distance), return env->NewObject(
static_cast<jint>(point.m_point.GetAltitude())); 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) 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) jobject CreateElevationInfo(JNIEnv * env, ElevationInfo const & info)
{ {
// public ElevationInfo(long trackId, @NonNull String name, @NonNull Point[] points, // public ElevationInfo(@NonNull Point[] points, int difficulty);
// int ascent, int descent, int minAltitude, int maxAltitude, int difficulty, static jmethodID const ctorId =
// long m_duration) jni::GetConstructorID(env, g_elevationInfoClazz, "([Lapp/organicmaps/sdk/bookmarks/data/ElevationInfo$Point;I)V");
static jmethodID const ctorId = jni::GetConstructorID(env, g_elevationInfoClazz,
"(JLjava/lang/String;Ljava/lang/String;"
"[Lapp/organicmaps/sdk/bookmarks/data/ElevationInfo$Point;"
"IIIIIJ)V");
jni::TScopedLocalObjectArrayRef jPoints(env, ToElevationPointArray(env, info.GetPoints())); jni::TScopedLocalObjectArrayRef jPoints(env, ToElevationPointArray(env, info.GetPoints()));
// TODO (KK): elevation info should have only the elevation data - see the return env->NewObject(g_elevationInfoClazz, ctorId, jPoints.get(), static_cast<jint>(info.GetDifficulty()));
// 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()));
} }
jobject CreateMapObject(JNIEnv * env, place_page::Info const & info) 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()); 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 */, return CreateMapObject(env, info, kPoi, ll.m_lat, ll.m_lon, true /* parseMeta */, false /* parseApi */,
routingPointInfo.get(), popularity, jrawTypes.get()); routingPointInfo.get(), popularity, jrawTypes.get());
} }

View File

@@ -26,6 +26,7 @@ static constexpr int kApiPoint = 1;
static constexpr int kBookmark = 2; static constexpr int kBookmark = 2;
static constexpr int kMyPosition = 3; static constexpr int kMyPosition = 3;
static constexpr int kSearch = 4; static constexpr int kSearch = 4;
static constexpr int kTrack = 5;
static constexpr int kPriceRateUndefined = -1; 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 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); jobject CreateElevationInfo(JNIEnv * env, ElevationInfo const & info);
jobjectArray ToRatingArray(JNIEnv * env, std::vector<std::string> const & ratingCategories); 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()); 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, JNIEXPORT jobject JNICALL Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetBookmarkInfo(JNIEnv * env,
jobject, jobject,
jlong bmkId) 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( 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(); auto & bm = frm()->GetBookmarkManager();
bm.SetElevationActivePoint( bm.SetElevationActivePoint(static_cast<kml::TrackId>(trackId),
static_cast<kml::TrackId>(trackId), m2::PointD(static_cast<double>(latitude), static_cast<double>(longitude)),
{0,
0}, // todo(KK): replace with coordinates from the elevation profile point to show selection mark on the track
static_cast<double>(distanceInMeters)); static_cast<double>(distanceInMeters));
} }
@@ -858,4 +866,41 @@ Java_app_organicmaps_sdk_widget_placepage_PlacePageButtonFactory_nativeHasRecent
{ {
return frm()->GetBookmarkManager().HasRecentlyDeletedBookmark(); 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" } // extern "C"

View File

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

View File

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

View File

@@ -866,7 +866,7 @@ void BookmarkManager::SetElevationActivePoint(kml::TrackId const & trackId, m2::
auto const track = GetTrack(trackId); auto const track = GetTrack(trackId);
CHECK(track != nullptr, ()); 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, m_drapeEngine.SafeCall(&df::DrapeEngine::SelectObject, df::SelectionShape::ESelectedObject::OBJECT_TRACK, pt,
FeatureID(), false /* isAnim */, false /* isGeometrySelectionAllowed */, 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; FeatureID selectedFeature = buildInfo.m_featureId;
auto const isFeatureMatchingEnabled = buildInfo.IsFeatureMatchingEnabled(); 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. // Using VisualParams inside FindTrackInTapPosition/GetDefaultTapRect requires drapeEngine.
if (isTrackSelectionEnabled && m_drapeEngine != nullptr && buildInfo.IsTrackMatchingEnabled() && if (m_drapeEngine != nullptr && buildInfo.IsTrackMatchingEnabled() &&
!(isFeatureMatchingEnabled && selectedFeature.IsValid())) !(isFeatureMatchingEnabled && selectedFeature.IsValid()))
{ {
Track::TrackSelectionInfo trackSelectionInfo; Track::TrackSelectionInfo trackSelectionInfo;