Add split interval card and bottom sheet

This commit is contained in:
Vitaliy 2020-07-14 20:59:08 +03:00
parent e5c61ddc8b
commit 1eb20f7dfa
9 changed files with 745 additions and 76 deletions

View file

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include
android:id="@+id/header_view"
layout="@layout/bottom_sheet_item_with_right_descr" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="@dimen/context_menu_padding_margin_tiny"
android:paddingBottom="@dimen/content_padding">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:orientation="horizontal"
android:paddingStart="@dimen/content_padding_half"
android:paddingLeft="@dimen/content_padding_half"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
tools:itemCount="3"
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/point_editor_group_select_item"
tools:orientation="horizontal" />
</LinearLayout>
<net.osmand.plus.widgets.FlowLayout
android:id="@+id/select_color"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding_small"
android:layout_marginLeft="@dimen/content_padding_small"
android:layout_marginTop="@dimen/context_menu_padding_margin_tiny"
android:layout_marginBottom="@dimen/content_padding_half" />
</LinearLayout>

View file

@ -0,0 +1,169 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/bottom_btns"
android:layout_width="match_parent"
android:layout_height="@dimen/dialog_button_height"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginTop="@dimen/text_margin_small"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginBottom="@dimen/content_padding_small"
android:background="?attr/btn_bg_border_inactive"
android:baselineAligned="false"
android:orientation="horizontal">
<FrameLayout
android:id="@+id/left_btn_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/left_btn"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:gravity="center"
android:text="@string/shared_string_none"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium" />
</FrameLayout>
<FrameLayout
android:id="@+id/center_btn_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/center_btn"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:gravity="center"
android:text="@string/shared_string_time"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium" />
</FrameLayout>
<FrameLayout
android:id="@+id/right_btn_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/right_btn"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:gravity="center"
android:text="@string/distance"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium" />
</FrameLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/slider_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="@dimen/content_padding"
android:paddingTop="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding">
<net.osmand.plus.widgets.TextViewEx
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:lineSpacingExtra="@dimen/line_spacing_extra_description"
android:text="@string/gpx_split_interval"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/split_value_tv"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end"
android:lineSpacingExtra="@dimen/line_spacing_extra_description"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
tools:text="@string/shared_string_max" />
</LinearLayout>
<com.google.android.material.slider.Slider
android:id="@+id/split_slider"
style="@style/Widget.Styled.Slider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:stepSize="1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/split_value_min"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:lineSpacingExtra="@dimen/line_spacing_extra_description"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_list_text_size"
tools:text="3" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/split_value_max"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end"
android:lineSpacingExtra="@dimen/line_spacing_extra_description"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_list_text_size"
tools:text="19" />
</LinearLayout>
</LinearLayout>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/split_interval_none_descr"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginBottom="@dimen/content_padding"
android:lineSpacingExtra="@dimen/line_spacing_extra_description"
android:text="@string/gpx_split_interval_none_descr"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size" />
</LinearLayout>

View file

@ -178,7 +178,7 @@ public class TrackActivity extends TabActivity {
}
}
public List<GpxDisplayGroup> getGpxFile(boolean useDisplayGroups) {
public List<GpxDisplayGroup> getGpxDisplayGroups(boolean useDisplayGroups) {
if (gpxFile == null) {
return new ArrayList<>();
}

View file

@ -380,7 +380,7 @@ public class SplitSegmentDialogFragment extends DialogFragment {
private List<GpxDisplayGroup> filterGroups(boolean useDisplayGroups) {
List<GpxDisplayGroup> groups = new ArrayList<>();
if (getTrackActivity() != null) {
List<GpxDisplayGroup> result = getTrackActivity().getGpxFile(useDisplayGroups);
List<GpxDisplayGroup> result = getTrackActivity().getGpxDisplayGroups(useDisplayGroups);
for (GpxDisplayGroup group : result) {
boolean add = hasFilterType(group.getType());
if (add) {
@ -397,7 +397,7 @@ public class SplitSegmentDialogFragment extends DialogFragment {
TrackActivity trackActivity = getTrackActivity();
List<GpxDisplayItem> splitSegments = new ArrayList<>();
if (trackActivity != null) {
List<GpxDisplayGroup> result = trackActivity.getGpxFile(true);
List<GpxDisplayGroup> result = trackActivity.getGpxDisplayGroups(true);
if (result != null && result.size() > 0 && trkSegment.points.size() > 0) {
for (GpxDisplayGroup group : result) {
splitSegments.addAll(collectDisplayItemsFromGroup(group));

View file

@ -0,0 +1,76 @@
package net.osmand.plus.myplaces;
import android.os.AsyncTask;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.osmand.plus.GpxSelectionHelper;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayGroup;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.track.GpxSplitType;
import java.util.List;
public class SplitTrackAsyncTask extends AsyncTask<Void, Void, Void> {
private OsmandApplication app;
private GpxSplitType gpxSplitType;
private List<GpxDisplayGroup> groups;
private SplitTrackListener splitTrackListener;
private boolean joinSegments;
private int timeSplitInterval;
private double distanceSplitInterval;
public SplitTrackAsyncTask(@NonNull OsmandApplication app,
@NonNull GpxSplitType gpxSplitType,
@NonNull List<GpxDisplayGroup> groups,
@Nullable SplitTrackListener splitTrackListener,
boolean joinSegments,
int timeSplitInterval,
double distanceSplitInterval) {
this.app = app;
this.groups = groups;
this.gpxSplitType = gpxSplitType;
this.splitTrackListener = splitTrackListener;
this.joinSegments = joinSegments;
this.timeSplitInterval = timeSplitInterval;
this.distanceSplitInterval = distanceSplitInterval;
}
@Override
protected void onPreExecute() {
if (splitTrackListener != null) {
splitTrackListener.trackSplittingStarted();
}
}
@Override
protected Void doInBackground(Void... params) {
for (GpxSelectionHelper.GpxDisplayGroup model : groups) {
if (gpxSplitType == GpxSplitType.NO_SPLIT) {
model.noSplit(app);
} else if (gpxSplitType == GpxSplitType.DISTANCE && distanceSplitInterval > 0) {
model.splitByDistance(app, distanceSplitInterval, joinSegments);
} else if (gpxSplitType == GpxSplitType.TIME && timeSplitInterval > 0) {
model.splitByTime(app, timeSplitInterval, joinSegments);
}
}
return null;
}
@Override
protected void onPostExecute(Void result) {
if (splitTrackListener != null) {
splitTrackListener.trackSplittingFinished();
}
}
public interface SplitTrackListener {
void trackSplittingStarted();
void trackSplittingFinished();
}
}

View file

@ -55,6 +55,7 @@ import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.TrackActivity;
import net.osmand.plus.measurementtool.NewGpxData;
import net.osmand.plus.myplaces.SplitTrackAsyncTask.SplitTrackListener;
import net.osmand.plus.myplaces.TrackBitmapDrawer.TrackBitmapDrawerListener;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.track.GpxSplitType;
@ -64,7 +65,6 @@ import net.osmand.plus.wikivoyage.WikivoyageUtils;
import net.osmand.plus.wikivoyage.article.WikivoyageArticleDialogFragment;
import net.osmand.plus.wikivoyage.data.TravelArticle;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -639,7 +639,7 @@ public class TrackActivityFragmentAdapter implements TrackBitmapDrawerListener {
List<GpxDisplayGroup> groups = new ArrayList<>();
TrackActivity activity = getTrackActivity();
if (activity != null) {
List<GpxDisplayGroup> result = activity.getGpxFile(useDisplayGroups);
List<GpxDisplayGroup> result = activity.getGpxDisplayGroups(useDisplayGroups);
for (GpxDisplayGroup group : result) {
boolean add = hasFilterType(group.getType());
if (add) {
@ -738,14 +738,55 @@ public class TrackActivityFragmentAdapter implements TrackBitmapDrawerListener {
addOptionSplit(3600, false, groups);
}
private void updateSplit(@NonNull List<GpxDisplayGroup> groups, @Nullable SelectedGpxFile sf) {
private void updateSplit(@NonNull List<GpxDisplayGroup> groups, @Nullable final SelectedGpxFile selectedGpx) {
TrackActivity activity = getTrackActivity();
if (activity != null) {
new SplitTrackAsyncTask(activity, this, sf, groups)
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
GpxSplitType gpxSplitType = getGpxSplitType();
if (gpxSplitType != null) {
int timeSplit = this.timeSplit.get(selectedSplitInterval);
double distanceSplit = this.distanceSplit.get(selectedSplitInterval);
SplitTrackListener splitTrackListener = new SplitTrackListener() {
@Override
public void trackSplittingStarted() {
TrackActivity activity = getTrackActivity();
if (activity != null) {
activity.setSupportProgressBarIndeterminateVisibility(true);
}
}
@Override
public void trackSplittingFinished() {
TrackActivity activity = getTrackActivity();
if (activity != null) {
if (AndroidUtils.isActivityNotDestroyed(activity)) {
activity.setSupportProgressBarIndeterminateVisibility(false);
}
if (selectedGpx != null) {
List<GpxDisplayGroup> groups = getDisplayGroups();
selectedGpx.setDisplayGroups(groups, app);
}
}
}
};
new SplitTrackAsyncTask(app, gpxSplitType, groups, splitTrackListener, activity.isJoinSegments(),
timeSplit, distanceSplit).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
}
private GpxSplitType getGpxSplitType() {
if (selectedSplitInterval == 0) {
return GpxSplitType.NO_SPLIT;
} else if (distanceSplit.get(selectedSplitInterval) > 0) {
return GpxSplitType.DISTANCE;
} else if (timeSplit.get(selectedSplitInterval) > 0) {
return GpxSplitType.TIME;
}
return null;
}
private void addOptionSplit(int value, boolean distance, @NonNull List<GpxDisplayGroup> model) {
if (model.size() > 0) {
if (distance) {
@ -905,70 +946,4 @@ public class TrackActivityFragmentAdapter implements TrackBitmapDrawerListener {
public void drawTrackBitmap(Bitmap bitmap) {
imageView.setImageDrawable(new BitmapDrawable(app.getResources(), bitmap));
}
private static class SplitTrackAsyncTask extends AsyncTask<Void, Void, Void> {
private final SelectedGpxFile selectedGpx;
private OsmandApplication app;
private final WeakReference<TrackActivity> activityRef;
private final WeakReference<TrackActivityFragmentAdapter> fragmentAdapterRef;
private final List<GpxDisplayGroup> groups;
private List<Double> distanceSplit;
private TIntArrayList timeSplit;
private int selectedSplitInterval;
private boolean joinSegments;
SplitTrackAsyncTask(@NonNull TrackActivity activity,
@NonNull TrackActivityFragmentAdapter fragmentAdapter,
@Nullable SelectedGpxFile selectedGpx,
@NonNull List<GpxDisplayGroup> groups) {
activityRef = new WeakReference<>(activity);
fragmentAdapterRef = new WeakReference<>(fragmentAdapter);
app = activity.getMyApplication();
this.selectedGpx = selectedGpx;
this.groups = groups;
selectedSplitInterval = fragmentAdapter.selectedSplitInterval;
distanceSplit = fragmentAdapter.distanceSplit;
timeSplit = fragmentAdapter.timeSplit;
joinSegments = activity.isJoinSegments();
}
@Override
protected void onPreExecute() {
TrackActivity activity = activityRef.get();
if (activity != null) {
activity.setSupportProgressBarIndeterminateVisibility(true);
}
}
@Override
protected void onPostExecute(Void result) {
TrackActivity activity = activityRef.get();
TrackActivityFragmentAdapter fragment = fragmentAdapterRef.get();
if (activity != null && fragment != null) {
if (!activity.isFinishing()) {
activity.setSupportProgressBarIndeterminateVisibility(false);
}
if (selectedGpx != null) {
List<GpxDisplayGroup> groups = fragment.getDisplayGroups();
selectedGpx.setDisplayGroups(groups, app);
}
}
}
@Override
protected Void doInBackground(Void... params) {
for (GpxDisplayGroup model : groups) {
if (selectedSplitInterval == 0) {
model.noSplit(app);
} else if (distanceSplit.get(selectedSplitInterval) > 0) {
model.splitByDistance(app, distanceSplit.get(selectedSplitInterval), joinSegments);
} else if (timeSplit.get(selectedSplitInterval) > 0) {
model.splitByTime(app, timeSplit.get(selectedSplitInterval), joinSegments);
}
}
return null;
}
}
}

View file

@ -0,0 +1,358 @@
package net.osmand.plus.track;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentManager;
import com.google.android.material.slider.Slider;
import net.osmand.PlatformUtil;
import net.osmand.plus.GPXDatabase.GpxDataItem;
import net.osmand.plus.GpxSelectionHelper;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayGroup;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.LongDescriptionItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.myplaces.SplitTrackAsyncTask;
import net.osmand.plus.myplaces.SplitTrackAsyncTask.SplitTrackListener;
import org.apache.commons.logging.Log;
import java.io.File;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static net.osmand.plus.track.TrackAppearanceFragment.SELECTED_TRACK_FILE_PATH;
public class SplitIntervalBottomSheet extends MenuBottomSheetDialogFragment {
public static final String TAG = SplitIntervalBottomSheet.class.getSimpleName();
private static final Log log = PlatformUtil.getLog(SplitIntervalBottomSheet.class);
public static final String SELECTED_TRACK_SPLIT_TYPE = "selected_track_split_type";
public static final String SELECTED_TIME_SPLIT_INTERVAL = "selected_time_split_interval";
public static final String SELECTED_DISTANCE_SPLIT_INTERVAL = "selected_distance_split_interval";
private OsmandApplication app;
private SelectedGpxFile selectedGpxFile;
private Map<String, Integer> timeSplitOptions = new LinkedHashMap<>();
private Map<String, Double> distanceSplitOptions = new LinkedHashMap<>();
private int selectedTimeSplitInterval;
private int selectedDistanceSplitInterval;
private GpxSplitType selectedSplitType = GpxSplitType.NO_SPLIT;
private Slider slider;
private View sliderContainer;
private TextView splitValueMin;
private TextView splitValueMax;
private TextView selectedSplitValue;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = requiredMyApplication();
Bundle arguments = getArguments();
if (savedInstanceState != null) {
String gpxFilePath = savedInstanceState.getString(SELECTED_TRACK_FILE_PATH);
selectedGpxFile = app.getSelectedGpxHelper().getSelectedFileByPath(gpxFilePath);
prepareSplitIntervalOptions();
selectedTimeSplitInterval = savedInstanceState.getInt(SELECTED_TIME_SPLIT_INTERVAL);
selectedDistanceSplitInterval = savedInstanceState.getInt(SELECTED_DISTANCE_SPLIT_INTERVAL);
selectedSplitType = GpxSplitType.valueOf(savedInstanceState.getString(SELECTED_TRACK_SPLIT_TYPE));
} else if (arguments != null) {
String gpxFilePath = arguments.getString(SELECTED_TRACK_FILE_PATH);
selectedGpxFile = app.getSelectedGpxHelper().getSelectedFileByPath(gpxFilePath);
prepareSplitIntervalOptions();
updateSelectedSplitParams();
}
}
@Override
public void createMenuItems(Bundle savedInstanceState) {
items.add(new TitleItem(getString(R.string.gpx_split_interval)));
items.add(new LongDescriptionItem(getString(R.string.gpx_split_interval_descr)));
LayoutInflater themedInflater = UiUtilities.getInflater(requireContext(), nightMode);
View view = themedInflater.inflate(R.layout.track_split_interval, null);
sliderContainer = view.findViewById(R.id.slider_container);
slider = sliderContainer.findViewById(R.id.split_slider);
splitValueMin = (TextView) view.findViewById(R.id.split_value_min);
splitValueMax = (TextView) view.findViewById(R.id.split_value_max);
selectedSplitValue = (TextView) view.findViewById(R.id.split_value_tv);
UiUtilities.setupSlider(slider, nightMode, null);
view.findViewById(R.id.left_btn_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
selectedSplitType = GpxSplitType.NO_SPLIT;
updateSlider();
}
});
view.findViewById(R.id.center_btn_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
selectedSplitType = GpxSplitType.TIME;
updateSlider();
}
});
view.findViewById(R.id.right_btn_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
selectedSplitType = GpxSplitType.DISTANCE;
updateSlider();
}
});
SimpleBottomSheetItem titleItem = (SimpleBottomSheetItem) new SimpleBottomSheetItem.Builder()
.setCustomView(view)
.create();
items.add(titleItem);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(SELECTED_TIME_SPLIT_INTERVAL, selectedTimeSplitInterval);
outState.putInt(SELECTED_DISTANCE_SPLIT_INTERVAL, selectedDistanceSplitInterval);
outState.putString(SELECTED_TRACK_SPLIT_TYPE, selectedSplitType.name());
outState.putString(SELECTED_TRACK_FILE_PATH, selectedGpxFile.getGpxFile().path);
}
private void updateSelectedSplitParams() {
GpxDataItem gpxDataItem = app.getGpxDbHelper().getItem(new File(selectedGpxFile.getGpxFile().path));
if (gpxDataItem != null) {
if (gpxDataItem.getSplitType() == GpxSplitType.DISTANCE.getType()) {
selectedSplitType = GpxSplitType.DISTANCE;
List<Double> splitOptions = new ArrayList<>(distanceSplitOptions.values());
int index = splitOptions.indexOf(gpxDataItem.getSplitInterval());
selectedDistanceSplitInterval = Math.max(index, 0);
} else if (gpxDataItem.getSplitType() == GpxSplitType.TIME.getType()) {
selectedSplitType = GpxSplitType.TIME;
List<Integer> splitOptions = new ArrayList<>(timeSplitOptions.values());
int index = splitOptions.indexOf((int) gpxDataItem.getSplitInterval());
selectedTimeSplitInterval = Math.max(index, 0);
}
}
}
private void prepareSplitIntervalOptions() {
List<GpxDisplayGroup> groups = getDisplayGroups();
addDistanceOptionSplit(30, groups); // 50 feet, 20 yards, 20 m
addDistanceOptionSplit(60, groups); // 100 feet, 50 yards, 50 m
addDistanceOptionSplit(150, groups); // 200 feet, 100 yards, 100 m
addDistanceOptionSplit(300, groups); // 500 feet, 200 yards, 200 m
addDistanceOptionSplit(600, groups); // 1000 feet, 500 yards, 500 m
addDistanceOptionSplit(1500, groups); // 2000 feet, 1000 yards, 1 km
addDistanceOptionSplit(3000, groups); // 1 mi, 2 km
addDistanceOptionSplit(6000, groups); // 2 mi, 5 km
addDistanceOptionSplit(15000, groups); // 5 mi, 10 km
addTimeOptionSplit(15, groups);
addTimeOptionSplit(30, groups);
addTimeOptionSplit(60, groups);
addTimeOptionSplit(120, groups);
addTimeOptionSplit(150, groups);
addTimeOptionSplit(300, groups);
addTimeOptionSplit(600, groups);
addTimeOptionSplit(900, groups);
addTimeOptionSplit(1800, groups);
addTimeOptionSplit(3600, groups);
}
private void addDistanceOptionSplit(int value, @NonNull List<GpxDisplayGroup> displayGroups) {
if (displayGroups.size() > 0) {
double dvalue = OsmAndFormatter.calculateRoundedDist(value, app);
String formattedDist = OsmAndFormatter.getFormattedDistance((float) dvalue, app);
distanceSplitOptions.put(formattedDist, dvalue);
if (Math.abs(displayGroups.get(0).getSplitDistance() - dvalue) < 1) {
selectedDistanceSplitInterval = distanceSplitOptions.size() - 1;
}
}
}
private void addTimeOptionSplit(int value, @NonNull List<GpxDisplayGroup> model) {
if (model.size() > 0) {
String time;
if (value < 60) {
time = value + " " + getString(R.string.int_seconds);
} else if (value % 60 == 0) {
time = (value / 60) + " " + getString(R.string.int_min);
} else {
time = (value / 60f) + " " + getString(R.string.int_min);
}
timeSplitOptions.put(time, value);
if (model.get(0).getSplitTime() == value) {
selectedTimeSplitInterval = timeSplitOptions.size() - 1;
}
}
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
updateSlider();
}
private void updateSlider() {
if (selectedSplitType != GpxSplitType.NO_SPLIT) {
slider.clearOnChangeListeners();
if (selectedSplitType == GpxSplitType.TIME) {
updateSliderTimeInterval();
} else {
updateSliderDistanceInterval();
}
AndroidUiHelper.updateVisibility(sliderContainer, true);
} else {
AndroidUiHelper.updateVisibility(sliderContainer, false);
}
setupHeightAndBackground(getView());
}
private void updateSliderTimeInterval() {
final List<String> splitOptions = new ArrayList<>(timeSplitOptions.keySet());
updateSliderMinMaxValues(splitOptions);
slider.setValue(selectedTimeSplitInterval);
slider.addOnChangeListener(new Slider.OnChangeListener() {
@Override
public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) {
if (fromUser) {
selectedTimeSplitInterval = (int) value;
selectedSplitValue.setText(splitOptions.get(selectedTimeSplitInterval));
}
}
});
selectedSplitValue.setText(splitOptions.get(selectedTimeSplitInterval));
}
private void updateSliderDistanceInterval() {
final List<String> splitOptions = new ArrayList<>(distanceSplitOptions.keySet());
updateSliderMinMaxValues(splitOptions);
slider.setValue(selectedDistanceSplitInterval);
slider.addOnChangeListener(new Slider.OnChangeListener() {
@Override
public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) {
if (fromUser) {
selectedDistanceSplitInterval = (int) value;
selectedSplitValue.setText(splitOptions.get(selectedDistanceSplitInterval));
}
}
});
selectedSplitValue.setText(splitOptions.get(selectedDistanceSplitInterval));
}
private void updateSliderMinMaxValues(List<String> splitOptions) {
int valueFrom = 0;
int valueTo = splitOptions.size() - 1;
slider.setValueTo(valueTo);
slider.setValueFrom(valueFrom);
splitValueMin.setText(splitOptions.get(valueFrom));
splitValueMax.setText(splitOptions.get(valueTo));
}
@Override
protected int getRightBottomButtonTextId() {
return R.string.shared_string_apply;
}
@Override
protected void onRightBottomButtonClick() {
applySelectedSplit();
updateSplitInDatabase();
dismiss();
}
private void updateSplitInDatabase() {
double splitInterval = 0;
if (selectedSplitType == GpxSplitType.NO_SPLIT) {
splitInterval = 0;
} else if (selectedSplitType == GpxSplitType.DISTANCE) {
splitInterval = new ArrayList<>(distanceSplitOptions.values()).get(selectedDistanceSplitInterval);
} else if (selectedSplitType == GpxSplitType.TIME) {
splitInterval = new ArrayList<>(timeSplitOptions.values()).get(selectedTimeSplitInterval);
}
GpxDataItem gpxDataItem = app.getGpxDbHelper().getItem(new File(selectedGpxFile.getGpxFile().path));
if (gpxDataItem != null) {
app.getGpxDbHelper().updateSplit(gpxDataItem, selectedSplitType, splitInterval);
}
}
private void applySelectedSplit() {
int timeSplit = new ArrayList<>(timeSplitOptions.values()).get(selectedTimeSplitInterval);
double distanceSplit = new ArrayList<>(distanceSplitOptions.values()).get(selectedDistanceSplitInterval);
SplitTrackListener splitTrackListener = new SplitTrackListener() {
@Override
public void trackSplittingStarted() {
}
@Override
public void trackSplittingFinished() {
if (selectedGpxFile != null) {
List<GpxDisplayGroup> groups = getDisplayGroups();
selectedGpxFile.setDisplayGroups(groups, app);
}
}
};
List<GpxDisplayGroup> groups = selectedGpxFile.getDisplayGroups(app);
GpxDataItem gpxDataItem = app.getGpxDbHelper().getItem(new File(selectedGpxFile.getGpxFile().path));
boolean isJoinSegments = gpxDataItem != null && gpxDataItem.isJoinSegments();
new SplitTrackAsyncTask(app, selectedSplitType, groups, splitTrackListener, isJoinSegments,
timeSplit, distanceSplit).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
@NonNull
private List<GpxDisplayGroup> getDisplayGroups() {
List<GpxDisplayGroup> groups = new ArrayList<>();
for (GpxDisplayGroup group : selectedGpxFile.getDisplayGroups(app)) {
if (GpxSelectionHelper.GpxDisplayItemType.TRACK_SEGMENT == group.getType()) {
groups.add(group);
}
}
return groups;
}
public static void showInstance(@NonNull FragmentManager fragmentManager, SelectedGpxFile selectedGpxFile) {
try {
if (fragmentManager.findFragmentByTag(SplitIntervalBottomSheet.TAG) == null) {
Bundle args = new Bundle();
args.putString(SELECTED_TRACK_FILE_PATH, selectedGpxFile.getGpxFile().path);
SplitIntervalBottomSheet splitIntervalBottomSheet = new SplitIntervalBottomSheet();
splitIntervalBottomSheet.setArguments(args);
splitIntervalBottomSheet.show(fragmentManager, SplitIntervalBottomSheet.TAG);
}
} catch (RuntimeException e) {
log.error("showInstance", e);
}
}
}

View file

@ -0,0 +1,44 @@
package net.osmand.plus.track;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
public class SplitIntervalCard extends BaseCard {
private SelectedGpxFile selectedGpxFile;
public SplitIntervalCard(@NonNull MapActivity mapActivity, SelectedGpxFile selectedGpxFile) {
super(mapActivity);
this.selectedGpxFile = selectedGpxFile;
}
@Override
public int getCardLayoutId() {
return R.layout.bottom_sheet_item_with_right_descr;
}
@Override
protected void updateContent() {
AndroidUiHelper.updateVisibility(view.findViewById(R.id.icon), false);
TextView titleView = view.findViewById(R.id.title);
titleView.setText(R.string.gpx_split_interval);
TextView descriptionView = view.findViewById(R.id.description);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SplitIntervalBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), selectedGpxFile);
}
});
}
}

View file

@ -27,13 +27,12 @@ public class TrackAppearanceFragment extends ContextMenuFragment {
public static final String SELECTED_TRACK_FILE_PATH = "selected_track_file_path";
private OsmandApplication app;
private SelectedGpxFile selectedGpxFile;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = requireMyApplication();
OsmandApplication app = requireMyApplication();
String gpxFilePath = null;
Bundle arguments = getArguments();
@ -122,6 +121,9 @@ public class TrackAppearanceFragment extends ContextMenuFragment {
ViewGroup cardsContainer = getCardsContainer();
cardsContainer.removeAllViews();
BaseCard splitIntervalCard = new SplitIntervalCard(mapActivity, selectedGpxFile);
cardsContainer.addView(splitIntervalCard.build(mapActivity));
BaseCard arrowsCard = new DirectionArrowsCard(mapActivity, selectedGpxFile);
cardsContainer.addView(arrowsCard.build(mapActivity));