Merge pull request #10815 from osmandapp/fix_gpx_context_menu_overview_actions_p4

Fix changing track info with using "Join segments" option
This commit is contained in:
Vitaliy 2021-02-10 14:10:25 +02:00 committed by GitHub
commit 7a4ecab2b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 143 additions and 99 deletions

View file

@ -36,6 +36,7 @@ import net.osmand.data.LatLon;
import net.osmand.data.QuadRect; import net.osmand.data.QuadRect;
import net.osmand.data.RotatedTileBox; import net.osmand.data.RotatedTileBox;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem; import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.UiUtilities; import net.osmand.plus.UiUtilities;
@ -66,6 +67,8 @@ public class TrackDetailsMenu {
@Nullable @Nullable
private GpxDisplayItem gpxItem; private GpxDisplayItem gpxItem;
@Nullable @Nullable
private SelectedGpxFile selectedGpxFile;
@Nullable
private TrackDetailsBarController toolbarController; private TrackDetailsBarController toolbarController;
@Nullable @Nullable
private TrkSegment segment; private TrkSegment segment;
@ -101,6 +104,15 @@ public class TrackDetailsMenu {
this.gpxItem = gpxItem; this.gpxItem = gpxItem;
} }
@Nullable
public SelectedGpxFile getSelectedGpxFile() {
return selectedGpxFile;
}
public void setSelectedGpxFile(@NonNull SelectedGpxFile selectedGpxFile) {
this.selectedGpxFile = selectedGpxFile;
}
public boolean isVisible() { public boolean isVisible() {
return visible; return visible;
} }
@ -707,18 +719,19 @@ public class TrackDetailsMenu {
if (gpxItem.chartTypes != null && gpxItem.chartTypes.length > 0) { if (gpxItem.chartTypes != null && gpxItem.chartTypes.length > 0) {
for (int i = 0; i < gpxItem.chartTypes.length; i++) { for (int i = 0; i < gpxItem.chartTypes.length; i++) {
OrderedLineDataSet dataSet = null; OrderedLineDataSet dataSet = null;
boolean withoutGaps = selectedGpxFile != null && (!selectedGpxFile.isJoinSegments() && gpxItem.isGeneralTrack());
switch (gpxItem.chartTypes[i]) { switch (gpxItem.chartTypes[i]) {
case ALTITUDE: case ALTITUDE:
dataSet = GpxUiHelper.createGPXElevationDataSet(app, chart, analysis, dataSet = GpxUiHelper.createGPXElevationDataSet(app, chart, analysis,
gpxItem.chartAxisType, false, true, false); gpxItem.chartAxisType, false, true, withoutGaps);
break; break;
case SPEED: case SPEED:
dataSet = GpxUiHelper.createGPXSpeedDataSet(app, chart, analysis, dataSet = GpxUiHelper.createGPXSpeedDataSet(app, chart, analysis,
gpxItem.chartAxisType, gpxItem.chartTypes.length > 1, true, false); gpxItem.chartAxisType, gpxItem.chartTypes.length > 1, true, withoutGaps);
break; break;
case SLOPE: case SLOPE:
dataSet = GpxUiHelper.createGPXSlopeDataSet(app, chart, analysis, dataSet = GpxUiHelper.createGPXSlopeDataSet(app, chart, analysis,
gpxItem.chartAxisType, null, gpxItem.chartTypes.length > 1, true, false); gpxItem.chartAxisType, null, gpxItem.chartTypes.length > 1, true, withoutGaps);
break; break;
} }
if (dataSet != null) { if (dataSet != null) {

View file

@ -1,10 +1,10 @@
package net.osmand.plus.track; package net.osmand.plus.track;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Handler;
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.TextView; import android.widget.TextView;
import androidx.annotation.ColorInt; import androidx.annotation.ColorInt;
@ -12,21 +12,19 @@ import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes; import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatImageView; import androidx.appcompat.widget.AppCompatImageView;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import net.osmand.AndroidUtils; import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.GPXTrackAnalysis; import net.osmand.GPXUtilities.GPXTrackAnalysis;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayGroup;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem; import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItemType;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile; import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetType; import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetType;
import net.osmand.plus.myplaces.SegmentActionsListener; import net.osmand.plus.myplaces.SegmentActionsListener;
import net.osmand.plus.widgets.TextViewEx; import net.osmand.plus.widgets.TextViewEx;
@ -40,101 +38,134 @@ public class GpxBlockStatisticsBuilder {
private final OsmandApplication app; private final OsmandApplication app;
private RecyclerView blocksView; private RecyclerView blocksView;
private final SelectedGpxFile selectedGpxFile; private final SelectedGpxFile selectedGpxFile;
private final TrackDisplayHelper displayHelper;
private final GpxDisplayItemType[] filterTypes = {GpxDisplayItemType.TRACK_SEGMENT};
public GpxBlockStatisticsBuilder(OsmandApplication app, SelectedGpxFile selectedGpxFile, TrackDisplayHelper displayHelper) { private BlockStatisticsAdapter adapter;
private final List<StatBlock> items = new ArrayList<>();
private final Handler handler = new Handler();
private Runnable updatingItems;
private boolean updateRunning = false;
public GpxBlockStatisticsBuilder(OsmandApplication app, SelectedGpxFile selectedGpxFile) {
this.app = app; this.app = app;
this.selectedGpxFile = selectedGpxFile; this.selectedGpxFile = selectedGpxFile;
this.displayHelper = displayHelper;
} }
public void setBlocksView(RecyclerView blocksView) { public void setBlocksView(RecyclerView blocksView) {
this.blocksView = blocksView; this.blocksView = blocksView;
} }
private GPXTrackAnalysis getAnalysis() { private GpxDisplayItem getDisplayItem(GPXFile gpxFile) {
return selectedGpxFile.getTrackAnalysis(app); return GpxUiHelper.makeGpxDisplayItem(app, gpxFile);
}
private GPXFile getGPXFile() {
return selectedGpxFile.getGpxFile();
} }
public void initStatBlocks(SegmentActionsListener actionsListener, @ColorInt int activeColor, boolean nightMode) { public void initStatBlocks(SegmentActionsListener actionsListener, @ColorInt int activeColor, boolean nightMode) {
GPXTrackAnalysis analysis = getAnalysis(); initItems();
float totalDistance = analysis.totalDistance; boolean isNotEmpty = !Algorithms.isEmpty(items);
float timeSpan = analysis.timeSpan; AndroidUiHelper.updateVisibility(blocksView, isNotEmpty);
if (isNotEmpty) {
adapter = new BlockStatisticsAdapter(getDisplayItem(getGPXFile()), actionsListener, activeColor, nightMode);
adapter.setItems(items);
blocksView.setLayoutManager(new LinearLayoutManager(app, LinearLayoutManager.HORIZONTAL, false));
blocksView.setAdapter(adapter);
}
}
public void stopUpdatingStatBlocks() {
handler.removeCallbacks(updatingItems);
updateRunning = false;
}
public void runUpdatingStatBlocks() {
updatingItems = new Runnable() {
@Override
public void run() {
if (adapter != null) {
initItems();
adapter.setItems(items);
AndroidUiHelper.updateVisibility(blocksView, !Algorithms.isEmpty(items));
}
int interval = app.getSettings().SAVE_GLOBAL_TRACK_INTERVAL.get();
handler.postDelayed(this, Math.max(1000, interval));
}
};
updateRunning = handler.post(updatingItems);
}
public void initItems() {
GPXFile gpxFile = getGPXFile();
GpxDisplayItem gpxDisplayItem = null;
GPXTrackAnalysis analysis = null;
boolean withoutGaps = true;
if (gpxFile.tracks.size() > 0) {
gpxDisplayItem = getDisplayItem(gpxFile);
}
if (gpxDisplayItem != null) {
analysis = gpxDisplayItem.analysis;
withoutGaps = !selectedGpxFile.isJoinSegments() && gpxDisplayItem.isGeneralTrack();
}
if (analysis != null) {
float totalDistance = withoutGaps ? analysis.totalDistanceWithoutGaps : analysis.totalDistance;
float timeSpan = withoutGaps ? analysis.timeSpanWithoutGaps : analysis.timeSpan;
String asc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationUp, app); String asc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationUp, app);
String desc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationDown, app); String desc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationDown, app);
String avg = OsmAndFormatter.getFormattedSpeed(analysis.avgSpeed, app); String avg = OsmAndFormatter.getFormattedSpeed(analysis.avgSpeed, app);
String max = OsmAndFormatter.getFormattedSpeed(analysis.maxSpeed, app); String max = OsmAndFormatter.getFormattedSpeed(analysis.maxSpeed, app);
List<StatBlock> items = new ArrayList<>();
prepareData(analysis, items, app.getString(R.string.distance), OsmAndFormatter.getFormattedDistance(totalDistance, app), items.clear();
prepareData(analysis, app.getString(R.string.distance), OsmAndFormatter.getFormattedDistance(totalDistance, app),
R.drawable.ic_action_track_16, R.color.icon_color_default_light, GPXDataSetType.ALTITUDE, GPXDataSetType.SPEED, ItemType.ITEM_DISTANCE); R.drawable.ic_action_track_16, R.color.icon_color_default_light, GPXDataSetType.ALTITUDE, GPXDataSetType.SPEED, ItemType.ITEM_DISTANCE);
prepareData(analysis, items, app.getString(R.string.altitude_ascent), asc, prepareData(analysis, app.getString(R.string.altitude_ascent), asc,
R.drawable.ic_action_arrow_up_16, R.color.gpx_chart_red, GPXDataSetType.SLOPE, null, ItemType.ITEM_ALTITUDE); R.drawable.ic_action_arrow_up_16, R.color.gpx_chart_red, GPXDataSetType.SLOPE, null, ItemType.ITEM_ALTITUDE);
prepareData(analysis, items, app.getString(R.string.altitude_descent), desc, prepareData(analysis, app.getString(R.string.altitude_descent), desc,
R.drawable.ic_action_arrow_down_16, R.color.gpx_pale_green, GPXDataSetType.ALTITUDE, GPXDataSetType.SLOPE, ItemType.ITEM_ALTITUDE); R.drawable.ic_action_arrow_down_16, R.color.gpx_pale_green, GPXDataSetType.ALTITUDE, GPXDataSetType.SLOPE, ItemType.ITEM_ALTITUDE);
prepareData(analysis, items, app.getString(R.string.average_speed), avg, prepareData(analysis, app.getString(R.string.average_speed), avg,
R.drawable.ic_action_speed_16, R.color.icon_color_default_light, GPXDataSetType.SPEED, null, ItemType.ITEM_SPEED); R.drawable.ic_action_speed_16, R.color.icon_color_default_light, GPXDataSetType.SPEED, null, ItemType.ITEM_SPEED);
prepareData(analysis, items, app.getString(R.string.max_speed), max, prepareData(analysis, app.getString(R.string.max_speed), max,
R.drawable.ic_action_max_speed_16, R.color.icon_color_default_light, GPXDataSetType.SPEED, null, ItemType.ITEM_SPEED); R.drawable.ic_action_max_speed_16, R.color.icon_color_default_light, GPXDataSetType.SPEED, null, ItemType.ITEM_SPEED);
prepareData(analysis, items, app.getString(R.string.shared_string_time_span), prepareData(analysis, app.getString(R.string.shared_string_time_span),
Algorithms.formatDuration((int) (timeSpan / 1000), app.accessibilityEnabled()), Algorithms.formatDuration((int) (timeSpan / 1000), app.accessibilityEnabled()),
R.drawable.ic_action_time_span_16, R.color.icon_color_default_light, GPXDataSetType.SPEED, null, ItemType.ITEM_TIME); R.drawable.ic_action_time_span_16, R.color.icon_color_default_light, GPXDataSetType.SPEED, null, ItemType.ITEM_TIME);
if (Algorithms.isEmpty(items)) {
AndroidUiHelper.updateVisibility(blocksView, false);
} else {
final BlockStatisticsAdapter sbAdapter = new BlockStatisticsAdapter(items, actionsListener, activeColor, nightMode);
blocksView.setLayoutManager(new LinearLayoutManager(app, LinearLayoutManager.HORIZONTAL, false));
blocksView.setAdapter(sbAdapter);
} }
} }
public void prepareData(GPXTrackAnalysis analysis, List<StatBlock> listItems, String title, public void prepareData(GPXTrackAnalysis analysis, String title, String value,
String value, @DrawableRes int imageResId, @ColorRes int imageColorId, @DrawableRes int imageResId, @ColorRes int imageColorId,
GPXDataSetType firstType, GPXDataSetType secondType, ItemType itemType) { GPXDataSetType firstType, GPXDataSetType secondType, ItemType itemType) {
StatBlock statBlock = new StatBlock(title, value, imageResId, imageColorId, firstType, secondType, itemType); StatBlock statBlock = new StatBlock(title, value, imageResId, imageColorId, firstType, secondType, itemType);
switch (statBlock.itemType) { switch (statBlock.itemType) {
case ITEM_DISTANCE: { case ITEM_DISTANCE: {
if (analysis.totalDistance != 0f) { if (analysis.totalDistance != 0f) {
listItems.add(statBlock); items.add(statBlock);
} }
break; break;
} }
case ITEM_ALTITUDE: { case ITEM_ALTITUDE: {
if (analysis.hasElevationData) { if (analysis.hasElevationData) {
listItems.add(statBlock); items.add(statBlock);
} }
break; break;
} }
case ITEM_SPEED: { case ITEM_SPEED: {
if (analysis.isSpeedSpecified()) { if (analysis.isSpeedSpecified()) {
listItems.add(statBlock); items.add(statBlock);
} }
break; break;
} }
case ITEM_TIME: { case ITEM_TIME: {
if (analysis.hasSpeedData) { if (analysis.hasSpeedData) {
listItems.add(statBlock); items.add(statBlock);
} }
break; break;
} }
} }
} }
private void setImageDrawable(ImageView iv, @DrawableRes Integer resId, @ColorRes int color) {
Drawable icon = resId != null ? app.getUIUtilities().getIcon(resId, color)
: UiUtilities.tintDrawable(iv.getDrawable(), getResolvedColor(color));
iv.setImageDrawable(icon);
}
@ColorInt
protected int getResolvedColor(@ColorRes int colorId) {
return ContextCompat.getColor(app, colorId);
}
public class StatBlock { public class StatBlock {
private final String title; private final String title;
private final String value; private final String value;
private final int imageResId; private final int imageResId;
@ -164,14 +195,16 @@ public class GpxBlockStatisticsBuilder {
private class BlockStatisticsAdapter extends RecyclerView.Adapter<BlockStatisticsViewHolder> { private class BlockStatisticsAdapter extends RecyclerView.Adapter<BlockStatisticsViewHolder> {
private final List<StatBlock> items = new ArrayList<>();
private final GpxDisplayItem displayItem;
private final SegmentActionsListener actionsListener;
@ColorInt @ColorInt
private final int activeColor; private final int activeColor;
private final List<StatBlock> statBlocks;
private final boolean nightMode; private final boolean nightMode;
private final SegmentActionsListener actionsListener;
public BlockStatisticsAdapter(List<StatBlock> statBlocks, SegmentActionsListener actionsListener, @ColorInt int activeColor, boolean nightMode) { public BlockStatisticsAdapter(GpxDisplayItem displayItem, SegmentActionsListener actionsListener,
this.statBlocks = statBlocks; @ColorInt int activeColor, boolean nightMode) {
this.displayItem = displayItem;
this.actionsListener = actionsListener; this.actionsListener = actionsListener;
this.activeColor = activeColor; this.activeColor = activeColor;
this.nightMode = nightMode; this.nightMode = nightMode;
@ -179,7 +212,7 @@ public class GpxBlockStatisticsBuilder {
@Override @Override
public int getItemCount() { public int getItemCount() {
return statBlocks.size(); return items.size();
} }
@NonNull @NonNull
@ -192,29 +225,21 @@ public class GpxBlockStatisticsBuilder {
@Override @Override
public void onBindViewHolder(BlockStatisticsViewHolder holder, int position) { public void onBindViewHolder(BlockStatisticsViewHolder holder, int position) {
final StatBlock item = statBlocks.get(position); final StatBlock item = items.get(position);
holder.valueText.setText(item.value); holder.valueText.setText(item.value);
holder.titleText.setText(item.title); holder.titleText.setText(item.title);
if (updateRunning) {
holder.titleText.setWidth(app.getResources().getDimensionPixelSize(R.dimen.map_route_buttons_width));
}
holder.valueText.setTextColor(activeColor); holder.valueText.setTextColor(activeColor);
holder.titleText.setTextColor(app.getResources().getColor(R.color.text_color_secondary_light)); holder.titleText.setTextColor(app.getResources().getColor(R.color.text_color_secondary_light));
holder.itemView.setOnClickListener(new View.OnClickListener() { holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
List<GpxDisplayGroup> groups = displayHelper.getDisplayGroups(filterTypes); GPXTrackAnalysis analysis = displayItem != null ? displayItem.analysis : null;
GpxDisplayGroup group = null; if (analysis != null) {
for (GpxDisplayGroup g : groups) {
if (g.isGeneralTrack()) {
group = g;
}
}
if (group == null && !groups.isEmpty()) {
group = groups.get(0);
}
if (group != null) {
GpxDisplayItem displayItem = group.getModifiableList().get(0);
if (displayItem != null && displayItem.analysis != null) {
ArrayList<GPXDataSetType> list = new ArrayList<>(); ArrayList<GPXDataSetType> list = new ArrayList<>();
if (displayItem.analysis.hasElevationData || displayItem.analysis.isSpeedSpecified() || displayItem.analysis.hasSpeedData) { if (analysis.hasElevationData || analysis.isSpeedSpecified() || analysis.hasSpeedData) {
if (item.firstType != null) { if (item.firstType != null) {
list.add(item.firstType); list.add(item.firstType);
} }
@ -227,11 +252,17 @@ public class GpxBlockStatisticsBuilder {
actionsListener.openAnalyzeOnMap(displayItem); actionsListener.openAnalyzeOnMap(displayItem);
} }
} }
}
}); });
setImageDrawable(holder.imageView, item.imageResId, item.imageColorId); Drawable icon = app.getUIUtilities().getIcon(item.imageResId, item.imageColorId);
holder.imageView.setImageDrawable(icon);
AndroidUtils.setBackgroundColor(app, holder.divider, nightMode, R.color.divider_color_light, R.color.divider_color_dark); AndroidUtils.setBackgroundColor(app, holder.divider, nightMode, R.color.divider_color_light, R.color.divider_color_dark);
AndroidUiHelper.updateVisibility(holder.divider, position != statBlocks.size() - 1); AndroidUiHelper.updateVisibility(holder.divider, position != items.size() - 1);
}
public void setItems(List<StatBlock> items) {
this.items.clear();
this.items.addAll(items);
notifyDataSetChanged();
} }
} }

View file

@ -43,12 +43,11 @@ public class OverviewCard extends BaseCard {
private final SelectedGpxFile selectedGpxFile; private final SelectedGpxFile selectedGpxFile;
private final GpxBlockStatisticsBuilder blockStatisticsBuilder; private final GpxBlockStatisticsBuilder blockStatisticsBuilder;
public OverviewCard(@NonNull MapActivity mapActivity, @NonNull TrackDisplayHelper displayHelper, public OverviewCard(@NonNull MapActivity mapActivity, @NonNull SegmentActionsListener actionsListener, SelectedGpxFile selectedGpxFile) {
@NonNull SegmentActionsListener actionsListener, SelectedGpxFile selectedGpxFile) {
super(mapActivity); super(mapActivity);
this.actionsListener = actionsListener; this.actionsListener = actionsListener;
this.selectedGpxFile = selectedGpxFile; this.selectedGpxFile = selectedGpxFile;
blockStatisticsBuilder = new GpxBlockStatisticsBuilder(app, selectedGpxFile, displayHelper); blockStatisticsBuilder = new GpxBlockStatisticsBuilder(app, selectedGpxFile);
} }
@Override @Override

View file

@ -326,7 +326,7 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
} }
headerContainer.addView(overviewCard.getView()); headerContainer.addView(overviewCard.getView());
} else { } else {
overviewCard = new OverviewCard(getMapActivity(), displayHelper, this, selectedGpxFile); overviewCard = new OverviewCard(getMapActivity(), this, selectedGpxFile);
overviewCard.setListener(this); overviewCard.setListener(this);
headerContainer.addView(overviewCard.build(getMapActivity())); headerContainer.addView(overviewCard.build(getMapActivity()));
} }
@ -1013,6 +1013,7 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
public void openAnalyzeOnMap(GpxDisplayItem gpxItem) { public void openAnalyzeOnMap(GpxDisplayItem gpxItem) {
TrackDetailsMenu trackDetailsMenu = getMapActivity().getTrackDetailsMenu(); TrackDetailsMenu trackDetailsMenu = getMapActivity().getTrackDetailsMenu();
trackDetailsMenu.setGpxItem(gpxItem); trackDetailsMenu.setGpxItem(gpxItem);
trackDetailsMenu.setSelectedGpxFile(selectedGpxFile);
trackDetailsMenu.show(); trackDetailsMenu.show();
hide(); hide();
} }