Merge pull request #9514 from osmandapp/plan_route_start

Plan route start
This commit is contained in:
max-klaus 2020-07-26 13:49:37 +03:00 committed by GitHub
commit d72d210b3b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 773 additions and 94 deletions

View file

@ -0,0 +1,35 @@
<?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:background="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="@dimen/bottom_sheet_list_item_height"
android:paddingBottom="@dimen/content_padding_half"
android:paddingTop="@dimen/content_padding_half"
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingStart="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin_large"
android:layout_marginRight="@dimen/bottom_sheet_icon_margin_large"
tools:src="@drawable/ic_action_info_dark" />
<TextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:ellipsize="end"
android:textAppearance="@style/TextAppearance.ListItemTitle"
tools:text="Title" />
</LinearLayout>

View file

@ -0,0 +1,60 @@
<?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="match_parent"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingTop="@dimen/bottom_sheet_title_padding_top"
android:paddingBottom="@dimen/bottom_sheet_title_padding_bottom"
android:text="@string/plan_route_open_existing_track"
android:textAppearance="@style/TextAppearance.ListItemCategoryTitle" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingTop="@dimen/bottom_sheet_title_padding_top"
android:paddingBottom="@dimen/bottom_sheet_title_padding_bottom"
android:text="@string/plan_route_select_track_file_for_open"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_regular" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/folder_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingStart="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding"
android:clipToPadding="false"
android:orientation="horizontal"
tools:itemCount="3"
tools:orientation="horizontal"
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/point_editor_icon_category_item" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/gpx_track_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:itemCount="1"
tools:listitem="@layout/gpx_track_select_item">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>

View file

@ -0,0 +1,40 @@
<?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="match_parent"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingTop="@dimen/bottom_sheet_title_padding_top"
android:paddingBottom="@dimen/bottom_sheet_title_padding_bottom">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/last_edited"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/plan_route_last_edited"
android:textColor="?attr/active_color_basic"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_regular" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/gpx_track_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
tools:itemCount="1"
tools:listitem="@layout/gpx_track_select_item">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>

View file

@ -71,7 +71,7 @@
android:layout_marginStart="@dimen/measurement_tool_text_button_padding" android:layout_marginStart="@dimen/measurement_tool_text_button_padding"
android:layout_toEndOf="@id/main_icon" android:layout_toEndOf="@id/main_icon"
android:layout_toRightOf="@id/main_icon" android:layout_toRightOf="@id/main_icon"
android:textAppearance="@style/TextAppearance.ListItemTitle" android:textAppearance="@style/TextAppearance.ListItemCategoryTitle"
tools:text="724 m,"/> tools:text="724 m,"/>
<TextView <TextView
@ -81,8 +81,7 @@
android:layout_marginTop="@dimen/measurement_tool_button_padding" android:layout_marginTop="@dimen/measurement_tool_button_padding"
android:layout_toEndOf="@id/measurement_distance_text_view" android:layout_toEndOf="@id/measurement_distance_text_view"
android:layout_toRightOf="@id/measurement_distance_text_view" android:layout_toRightOf="@id/measurement_distance_text_view"
android:textColor="?android:textColorSecondary" android:textAppearance="@style/TextAppearance.ListItemCategoryTitle"
android:textSize="@dimen/default_list_text_size"
tools:text="points: 3"/> tools:text="points: 3"/>
<TextView <TextView
@ -93,7 +92,7 @@
android:layout_alignStart="@+id/measurement_distance_text_view" android:layout_alignStart="@+id/measurement_distance_text_view"
android:layout_alignLeft="@+id/measurement_distance_text_view" android:layout_alignLeft="@+id/measurement_distance_text_view"
android:maxLines="1" android:maxLines="1"
android:textColor="@color/color_distance" android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size" android:textSize="@dimen/default_desc_text_size"
tools:text=" 700 m" /> tools:text=" 700 m" />

View file

@ -4,7 +4,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:minHeight="@dimen/settings_divider_margin_start" android:minHeight="@dimen/favorites_list_item_height"
android:background="?attr/selectableItemBackground" android:background="?attr/selectableItemBackground"
android:orientation="horizontal"> android:orientation="horizontal">
@ -29,9 +29,8 @@
android:layout_marginEnd="@dimen/list_content_padding" android:layout_marginEnd="@dimen/list_content_padding"
android:layout_marginRight="@dimen/list_content_padding" android:layout_marginRight="@dimen/list_content_padding"
android:layout_weight="1" android:layout_weight="1"
android:orientation="vertical" android:layout_gravity="center_vertical"
android:paddingTop="@dimen/content_padding_small" android:orientation="vertical">
android:paddingBottom="@dimen/content_padding_small">
<TextView <TextView
android:id="@+id/name" android:id="@+id/name"

View file

@ -268,6 +268,9 @@
<dimen name="bottom_sheet_list_item_height">48dp</dimen> <dimen name="bottom_sheet_list_item_height">48dp</dimen>
<dimen name="bottom_sheet_large_list_item_height">64dp</dimen> <dimen name="bottom_sheet_large_list_item_height">64dp</dimen>
<dimen name="bottom_sheet_icon_margin">24dp</dimen> <dimen name="bottom_sheet_icon_margin">24dp</dimen>
<dimen name="bottom_sheet_title_padding_top">10dp</dimen>
<dimen name="bottom_sheet_title_padding_bottom">6dp</dimen>
<dimen name="bottom_sheet_icon_margin_large">32dp</dimen>
<dimen name="bottom_sheet_divider_margin_top">7dp</dimen> <dimen name="bottom_sheet_divider_margin_top">7dp</dimen>
<dimen name="bottom_sheet_divider_margin_bottom">8dp</dimen> <dimen name="bottom_sheet_divider_margin_bottom">8dp</dimen>
<dimen name="bottom_sheet_divider_margin_start">64dp</dimen> <dimen name="bottom_sheet_divider_margin_start">64dp</dimen>

View file

@ -11,6 +11,12 @@
Thx - Hardy Thx - Hardy
--> -->
<string name="shared_string_done">Done</string>
<string name="plan_route_select_track_file_for_open">Select a track file for open.</string>
<string name="plan_route_create_new_route">Create new route</string>
<string name="plan_route_open_existing_track">Open existing track</string>
<string name="plan_route_import_track">Import track</string>
<string name="plan_route_last_edited">Last edited</string>
<string name="track_coloring_solid">Solid</string> <string name="track_coloring_solid">Solid</string>
<string name="gpx_direction_arrows">Direction arrows</string> <string name="gpx_direction_arrows">Direction arrows</string>
<string name="shared_string_custom">Custom</string> <string name="shared_string_custom">Custom</string>

View file

@ -41,8 +41,8 @@ import androidx.core.view.ViewCompat;
import androidx.core.widget.TintableCompoundButton; import androidx.core.widget.TintableCompoundButton;
import com.google.android.material.slider.RangeSlider; import com.google.android.material.slider.RangeSlider;
import com.google.android.material.snackbar.BaseTransientBottomBar;
import com.google.android.material.slider.Slider; import com.google.android.material.slider.Slider;
import com.google.android.material.snackbar.BaseTransientBottomBar;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.snackbar.SnackbarContentLayout; import com.google.android.material.snackbar.SnackbarContentLayout;
@ -60,7 +60,6 @@ import org.apache.commons.logging.Log;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import gnu.trove.map.hash.TLongObjectHashMap; import gnu.trove.map.hash.TLongObjectHashMap;
import static net.osmand.plus.SimplePopUpMenuItemAdapter.SimplePopUpMenuItem; import static net.osmand.plus.SimplePopUpMenuItemAdapter.SimplePopUpMenuItem;
@ -184,7 +183,7 @@ public class UiUtilities {
return tintDrawable(AppCompatResources.getDrawable(context, resId), color); return tintDrawable(AppCompatResources.getDrawable(context, resId), color);
} }
public static Drawable tintDrawable(Drawable drawable, int color) { public static Drawable tintDrawable(Drawable drawable, @ColorInt int color) {
Drawable coloredDrawable = null; Drawable coloredDrawable = null;
if (drawable != null) { if (drawable != null) {
coloredDrawable = DrawableCompat.wrap(drawable); coloredDrawable = DrawableCompat.wrap(drawable);

View file

@ -15,11 +15,13 @@ import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities; import net.osmand.GPXUtilities;
import net.osmand.IndexConstants; import net.osmand.IndexConstants;
import net.osmand.plus.GPXDatabase; import net.osmand.plus.GPXDatabase;
import net.osmand.plus.GPXDatabase.GpxDataItem;
import net.osmand.plus.GpxDbHelper; import net.osmand.plus.GpxDbHelper;
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.UiUtilities;
import net.osmand.plus.helpers.GpxUiHelper.GPXInfo;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import java.io.File; import java.io.File;
@ -29,20 +31,27 @@ import java.util.List;
public class GpxTrackAdapter extends RecyclerView.Adapter<GpxTrackAdapter.TrackViewHolder> { public class GpxTrackAdapter extends RecyclerView.Adapter<GpxTrackAdapter.TrackViewHolder> {
private LayoutInflater themedInflater;
private List<GpxUiHelper.GPXInfo> gpxInfoList;
private OsmandApplication app; private OsmandApplication app;
private LayoutInflater themedInflater;
private UiUtilities iconsCache;
private List<GPXInfo> gpxInfoList;
private boolean showCurrentGpx; private boolean showCurrentGpx;
private OnItemClickListener onItemClickListener; private OnItemClickListener onItemClickListener;
private UiUtilities iconsCache;
GpxTrackAdapter(Context ctx, List<GpxUiHelper.GPXInfo> gpxInfoList, boolean showCurrentGpx) { public GpxTrackAdapter(Context ctx, List<GPXInfo> gpxInfoList, boolean showCurrentGpx) {
this.showCurrentGpx = showCurrentGpx;
app = (OsmandApplication) ctx.getApplicationContext(); app = (OsmandApplication) ctx.getApplicationContext();
boolean nightMode = app.getDaynightHelper().isNightModeForMapControls(); themedInflater = UiUtilities.getInflater(ctx, app.getDaynightHelper().isNightModeForMapControls());
themedInflater = UiUtilities.getInflater(ctx, nightMode);
this.gpxInfoList = gpxInfoList;
iconsCache = app.getUIUtilities(); iconsCache = app.getUIUtilities();
this.gpxInfoList = gpxInfoList;
this.showCurrentGpx = showCurrentGpx;
}
public void setGpxInfoList(List<GPXInfo> gpxInfoList) {
this.gpxInfoList = gpxInfoList;
}
public void setShowCurrentGpx(boolean showCurrentGpx) {
this.showCurrentGpx = showCurrentGpx;
} }
@NonNull @NonNull
@ -67,15 +76,17 @@ public class GpxTrackAdapter extends RecyclerView.Adapter<GpxTrackAdapter.TrackV
holder.icon.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_polygom_dark)); holder.icon.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_polygom_dark));
} }
final int adapterPosition = holder.getAdapterPosition(); final int adapterPosition = holder.getAdapterPosition();
GpxUiHelper.GPXInfo info = gpxInfoList.get(adapterPosition); GPXInfo info = gpxInfoList.get(adapterPosition);
GPXDatabase.GpxDataItem dataItem = getDataItem(info); GpxDataItem dataItem = getDataItem(info);
String itemTitle = GpxUiHelper.getGpxTitle(info.getFileName()); String itemTitle = GpxUiHelper.getGpxTitle(info.getFileName());
updateGpxInfoView(holder, itemTitle, info, dataItem, currentlyRecordingTrack, app); updateGpxInfoView(holder, itemTitle, info, dataItem, currentlyRecordingTrack, app);
holder.itemView.setOnClickListener(new View.OnClickListener() { holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(adapterPosition); onItemClickListener.onItemClick(adapterPosition);
} }
}
}); });
} }
@ -84,8 +95,8 @@ public class GpxTrackAdapter extends RecyclerView.Adapter<GpxTrackAdapter.TrackV
return gpxInfoList.size(); return gpxInfoList.size();
} }
private void updateGpxInfoView(TrackViewHolder holder, String itemTitle, GpxUiHelper.GPXInfo info, private void updateGpxInfoView(TrackViewHolder holder, String itemTitle, GPXInfo info,
GPXDatabase.GpxDataItem dataItem, boolean currentlyRecordingTrack, GpxDataItem dataItem, boolean currentlyRecordingTrack,
OsmandApplication app) { OsmandApplication app) {
holder.name.setText(itemTitle.replace("/", "").trim()); holder.name.setText(itemTitle.replace("/", "").trim());
GPXUtilities.GPXTrackAnalysis analysis = null; GPXUtilities.GPXTrackAnalysis analysis = null;
@ -121,7 +132,7 @@ public class GpxTrackAdapter extends RecyclerView.Adapter<GpxTrackAdapter.TrackV
} }
} }
private GPXDatabase.GpxDataItem getDataItem(final GpxUiHelper.GPXInfo info) { private GpxDataItem getDataItem(final GPXInfo info) {
GpxDbHelper.GpxDataItemCallback gpxDataItemCallback = new GpxDbHelper.GpxDataItemCallback() { GpxDbHelper.GpxDataItemCallback gpxDataItemCallback = new GpxDbHelper.GpxDataItemCallback() {
@Override @Override
public boolean isCancelled() { public boolean isCancelled() {
@ -129,7 +140,7 @@ public class GpxTrackAdapter extends RecyclerView.Adapter<GpxTrackAdapter.TrackV
} }
@Override @Override
public void onGpxDataItemReady(GPXDatabase.GpxDataItem item) { public void onGpxDataItemReady(GpxDataItem item) {
if (item != null && gpxInfoList != null && info != null) { if (item != null && gpxInfoList != null && info != null) {
notifyItemChanged(gpxInfoList.indexOf(info)); notifyItemChanged(gpxInfoList.indexOf(info));
} }
@ -139,7 +150,7 @@ public class GpxTrackAdapter extends RecyclerView.Adapter<GpxTrackAdapter.TrackV
, gpxDataItemCallback); , gpxDataItemCallback);
} }
void setAdapterListener(OnItemClickListener onItemClickListener) { public void setAdapterListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener; this.onItemClickListener = onItemClickListener;
} }

View file

@ -40,6 +40,7 @@ import net.osmand.plus.activities.ActivityResultListener;
import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.TrackActivity; import net.osmand.plus.activities.TrackActivity;
import net.osmand.plus.dialogs.ImportGpxBottomSheetDialogFragment; import net.osmand.plus.dialogs.ImportGpxBottomSheetDialogFragment;
import net.osmand.plus.measurementtool.MeasurementToolFragment;
import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin; import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin;
import net.osmand.plus.settings.backend.SettingsHelper; import net.osmand.plus.settings.backend.SettingsHelper;
import net.osmand.plus.settings.backend.SettingsHelper.CheckDuplicatesListener; import net.osmand.plus.settings.backend.SettingsHelper.CheckDuplicatesListener;
@ -142,13 +143,17 @@ public class ImportHelper {
} }
public boolean handleGpxImport(final Uri contentUri, final boolean useImportDir) { public boolean handleGpxImport(final Uri contentUri, final boolean useImportDir) {
return handleGpxImport(contentUri, useImportDir, true);
}
public boolean handleGpxImport(final Uri contentUri, final boolean useImportDir, boolean showInDetailsActivity) {
String name = getNameFromContentUri(app, contentUri); String name = getNameFromContentUri(app, contentUri);
boolean isOsmandSubdir = Algorithms.isSubDirectory(app.getAppPath(IndexConstants.GPX_INDEX_DIR), new File(contentUri.getPath())); boolean isOsmandSubdir = Algorithms.isSubDirectory(app.getAppPath(IndexConstants.GPX_INDEX_DIR), new File(contentUri.getPath()));
if (!isOsmandSubdir && name != null) { if (!isOsmandSubdir && name != null) {
String nameLC = name.toLowerCase(); String nameLC = name.toLowerCase();
if (nameLC.endsWith(GPX_FILE_EXT)) { if (nameLC.endsWith(GPX_FILE_EXT)) {
name = name.substring(0, name.length() - GPX_FILE_EXT.length()) + GPX_FILE_EXT; name = name.substring(0, name.length() - GPX_FILE_EXT.length()) + GPX_FILE_EXT;
handleGpxImport(contentUri, name, true, useImportDir); handleGpxImport(contentUri, name, true, useImportDir, showInDetailsActivity);
return true; return true;
} else if (nameLC.endsWith(KML_SUFFIX)) { } else if (nameLC.endsWith(KML_SUFFIX)) {
name = name.substring(0, name.length() - KML_SUFFIX.length()) + KML_SUFFIX; name = name.substring(0, name.length() - KML_SUFFIX.length()) + KML_SUFFIX;
@ -229,7 +234,8 @@ public class ImportHelper {
} }
@SuppressLint("StaticFieldLeak") @SuppressLint("StaticFieldLeak")
private void handleGpxImport(final Uri gpxFile, final String fileName, final boolean save, final boolean useImportDir) { private void handleGpxImport(final Uri gpxFile, final String fileName, final boolean save, final boolean useImportDir,
final boolean showInDetailsActivity) {
new AsyncTask<Void, Void, GPXFile>() { new AsyncTask<Void, Void, GPXFile>() {
ProgressDialog progress = null; ProgressDialog progress = null;
@ -264,7 +270,7 @@ public class ImportHelper {
if (AndroidUtils.isActivityNotDestroyed(activity)) { if (AndroidUtils.isActivityNotDestroyed(activity)) {
progress.dismiss(); progress.dismiss();
} }
handleResult(result, fileName, save, useImportDir, false); handleResult(result, fileName, save, useImportDir, false, showInDetailsActivity);
} }
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
@ -941,8 +947,13 @@ public class ImportHelper {
executeImportTask(renderingImportTask); executeImportTask(renderingImportTask);
} }
private void handleResult(GPXFile result, String name, boolean save,
boolean useImportDir, boolean forceImportFavourites) {
handleResult(result, name, save, useImportDir, forceImportFavourites, true);
}
private void handleResult(final GPXFile result, final String name, final boolean save, private void handleResult(final GPXFile result, final String name, final boolean save,
final boolean useImportDir, boolean forceImportFavourites) { final boolean useImportDir, boolean forceImportFavourites, boolean showInDetailsActivity) {
if (result != null) { if (result != null) {
if (result.error != null) { if (result.error != null) {
Toast.makeText(activity, result.error.getMessage(), Toast.LENGTH_LONG).show(); Toast.makeText(activity, result.error.getMessage(), Toast.LENGTH_LONG).show();
@ -951,8 +962,9 @@ public class ImportHelper {
} }
} else { } else {
if (save) { if (save) {
new SaveAsyncTask(result, name, useImportDir).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); new SaveAsyncTask(result, name, useImportDir, showInDetailsActivity)
} else { .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else if (showInDetailsActivity) {
showGpxInDetailsActivity(result); showGpxInDetailsActivity(result);
} }
if (gpxImportCompleteListener != null) { if (gpxImportCompleteListener != null) {
@ -1057,11 +1069,13 @@ public class ImportHelper {
private final GPXFile result; private final GPXFile result;
private final String name; private final String name;
private final boolean useImportDir; private final boolean useImportDir;
private boolean showInDetailsActivity;
private SaveAsyncTask(GPXFile result, final String name, boolean useImportDir) { private SaveAsyncTask(GPXFile result, final String name, boolean useImportDir, boolean showInDetailsActivity) {
this.result = result; this.result = result;
this.name = name; this.name = name;
this.useImportDir = useImportDir; this.useImportDir = useImportDir;
this.showInDetailsActivity = showInDetailsActivity;
} }
@Override @Override
@ -1072,11 +1086,23 @@ public class ImportHelper {
@Override @Override
protected void onPostExecute(final String warning) { protected void onPostExecute(final String warning) {
if (Algorithms.isEmpty(warning)) { if (Algorithms.isEmpty(warning)) {
if (showInDetailsActivity) {
showGpxInDetailsActivity(result); showGpxInDetailsActivity(result);
} else {
showPlanRouteFragment();
}
} else { } else {
Toast.makeText(activity, warning, Toast.LENGTH_LONG).show(); Toast.makeText(activity, warning, Toast.LENGTH_LONG).show();
} }
} }
private void showPlanRouteFragment() {
MeasurementToolFragment fragment = (MeasurementToolFragment) activity.getSupportFragmentManager()
.findFragmentByTag(MeasurementToolFragment.TAG);
if (fragment != null && !fragment.isDetached() && !fragment.isRemoving()) {
fragment.addNewGpxData(result);
}
}
} }
private MapActivity getMapActivity() { private MapActivity getMapActivity() {

View file

@ -50,6 +50,7 @@ import net.osmand.GPXUtilities.TrkSegment;
import net.osmand.GPXUtilities.WptPt; import net.osmand.GPXUtilities.WptPt;
import net.osmand.IndexConstants; import net.osmand.IndexConstants;
import net.osmand.data.LatLon; import net.osmand.data.LatLon;
import net.osmand.data.QuadRect;
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;
@ -79,6 +80,8 @@ import net.osmand.plus.views.MapControlsLayer;
import net.osmand.plus.views.controls.ReorderItemTouchHelperCallback; import net.osmand.plus.views.controls.ReorderItemTouchHelperCallback;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory; import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarController; import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarController;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarControllerType;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarView;
import java.io.File; import java.io.File;
import java.text.MessageFormat; import java.text.MessageFormat;
@ -89,6 +92,8 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import static net.osmand.IndexConstants.GPX_FILE_EXT; import static net.osmand.IndexConstants.GPX_FILE_EXT;
import static net.osmand.plus.measurementtool.SelectFileBottomSheet.SelectFileListener;
import static net.osmand.plus.measurementtool.StartPlanRouteBottomSheet.StartPlanRouteListener;
public class MeasurementToolFragment extends BaseOsmAndFragment { public class MeasurementToolFragment extends BaseOsmAndFragment {
@ -117,6 +122,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
private boolean wasCollapseButtonVisible; private boolean wasCollapseButtonVisible;
private boolean progressBarVisible; private boolean progressBarVisible;
private boolean pointsListOpened; private boolean pointsListOpened;
private boolean planRouteMode = false;
private Boolean saved; private Boolean saved;
private boolean portrait; private boolean portrait;
private boolean nightMode; private boolean nightMode;
@ -140,6 +146,10 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
this.initialPoint = initialPoint; this.initialPoint = initialPoint;
} }
public void setPlanRouteMode(boolean planRouteMode) {
this.planRouteMode = planRouteMode;
}
@Nullable @Nullable
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@ -198,7 +208,6 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
hidePointsListFragment(); hidePointsListFragment();
} }
editingCtx.getCommandManager().resetMeasurementLayer(measurementLayer);
nightMode = mapActivity.getMyApplication().getDaynightHelper().isNightModeForMapControls(); nightMode = mapActivity.getMyApplication().getDaynightHelper().isNightModeForMapControls();
portrait = AndroidUiHelper.isOrientationPortrait(mapActivity); portrait = AndroidUiHelper.isOrientationPortrait(mapActivity);
@ -318,17 +327,13 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
editingCtx.getCommandManager().undo(); editingCtx.getCommandManager().undo();
if (editingCtx.getCommandManager().canUndo()) { updateUndoRedoButton(editingCtx.getCommandManager().canUndo(), undoBtn);
enable(undoBtn);
} else {
disable(undoBtn);
}
hidePointsListIfNoPoints(); hidePointsListIfNoPoints();
if (editingCtx.getPointsCount() > 0) { if (editingCtx.getPointsCount() > 0) {
enable(upDownBtn); enable(upDownBtn);
} }
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
enable(redoBtn); updateUndoRedoButton(true, redoBtn);
updateText(); updateText();
} }
}); });
@ -339,17 +344,13 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
editingCtx.getCommandManager().redo(); editingCtx.getCommandManager().redo();
if (editingCtx.getCommandManager().canRedo()) { updateUndoRedoButton(editingCtx.getCommandManager().canRedo(), redoBtn);
enable(redoBtn);
} else {
disable(redoBtn);
}
hidePointsListIfNoPoints(); hidePointsListIfNoPoints();
if (editingCtx.getPointsCount() > 0) { if (editingCtx.getPointsCount() > 0) {
enable(upDownBtn); enable(upDownBtn);
} }
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
enable(undoBtn); updateUndoRedoButton(true, undoBtn);
updateText(); updateText();
} }
}); });
@ -385,8 +386,8 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
String azimuthStr = OsmAndFormatter.getFormattedAzimuth(bearing, getMyApplication()); String azimuthStr = OsmAndFormatter.getFormattedAzimuth(bearing, getMyApplication());
distanceToCenterTv.setText(String.format("%1$s • %2$s", distStr, azimuthStr)); distanceToCenterTv.setText(String.format("%1$s • %2$s", distStr, azimuthStr));
TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration( TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(
distanceToCenterTv, 12, 18, 2, TypedValue.COMPLEX_UNIT_SP distanceToCenterTv, 14, 18, 2,
); TypedValue.COMPLEX_UNIT_SP);
} }
}); });
@ -401,16 +402,16 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
}); });
if (!editingCtx.getCommandManager().canUndo()) { if (!editingCtx.getCommandManager().canUndo()) {
disable(undoBtn); updateUndoRedoButton(false, undoBtn);
} }
if (!editingCtx.getCommandManager().canRedo()) { if (!editingCtx.getCommandManager().canRedo()) {
disable(redoBtn); updateUndoRedoButton(false, redoBtn);
} }
if (editingCtx.getPointsCount() < 1) { if (editingCtx.getPointsCount() < 1) {
disable(upDownBtn); disable(upDownBtn);
} }
toolBarController = new MeasurementToolBarController(newGpxData); toolBarController = new MeasurementToolBarController();
if (editingCtx.getSelectedPointPosition() != -1) { if (editingCtx.getSelectedPointPosition() != -1) {
int navigationIconResId = AndroidUtils.getNavigationIconResId(mapActivity); int navigationIconResId = AndroidUtils.getNavigationIconResId(mapActivity);
toolBarController.setBackBtnIconIds(navigationIconResId, navigationIconResId); toolBarController.setBackBtnIconIds(navigationIconResId, navigationIconResId);
@ -427,7 +428,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
toolBarController.setTitle(getString(R.string.edit_line)); toolBarController.setTitle(getString(R.string.edit_line));
} }
} else { } else {
toolBarController.setTitle(getString(R.string.measurement_tool_action_bar)); toolBarController.setTitle(getString(R.string.plan_route));
} }
toolBarController.setOnBackButtonClickListener(new View.OnClickListener() { toolBarController.setOnBackButtonClickListener(new View.OnClickListener() {
@Override @Override
@ -451,7 +452,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
} else { } else {
if (newGpxData == null) { if (newGpxData == null) {
final File dir = mapActivity.getMyApplication().getAppPath(IndexConstants.GPX_INDEX_DIR); final File dir = mapActivity.getMyApplication().getAppPath(IndexConstants.GPX_INDEX_DIR);
String fileName = getSuggestedName(dir); String fileName = getSuggestedName(dir) + GPX_FILE_EXT;
saveNewGpx(dir, fileName, true, SaveType.ROUTE_POINT, true); saveNewGpx(dir, fileName, true, SaveType.ROUTE_POINT, true);
} else { } else {
addToGpx(mapActivity); addToGpx(mapActivity);
@ -485,6 +486,17 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
pointsRv.setLayoutManager(new LinearLayoutManager(getContext())); pointsRv.setLayoutManager(new LinearLayoutManager(getContext()));
pointsRv.setAdapter(adapter); pointsRv.setAdapter(adapter);
initMeasurementMode(newGpxData);
if (planRouteMode) {
StartPlanRouteBottomSheet.showInstance(mapActivity.getSupportFragmentManager(),
createStartPlanRouteListener());
}
return view;
}
private void initMeasurementMode(NewGpxData newGpxData) {
editingCtx.getCommandManager().resetMeasurementLayer(getMapActivity().getMapLayers().getMeasurementToolLayer());
enterMeasurementMode(); enterMeasurementMode();
showSnapToRoadControls(); showSnapToRoadControls();
@ -503,8 +515,6 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
if (saved == null) { if (saved == null) {
saved = newGpxData != null && (newGpxData.getActionType() == ActionType.ADD_ROUTE_POINTS || newGpxData.getActionType() == ActionType.EDIT_SEGMENT); saved = newGpxData != null && (newGpxData.getActionType() == ActionType.ADD_ROUTE_POINTS || newGpxData.getActionType() == ActionType.EDIT_SEGMENT);
} }
return view;
} }
@Override @Override
@ -675,7 +685,8 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
if (pointsListOpened) { if (pointsListOpened) {
hidePointsList(); hidePointsList();
} }
disable(redoBtn, upDownBtn); updateUndoRedoButton(false, redoBtn);
disable(upDownBtn);
updateText(); updateText();
saved = false; saved = false;
} }
@ -765,11 +776,77 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
}; };
} }
private StartPlanRouteListener createStartPlanRouteListener() {
return new StartPlanRouteListener() {
@Override
public void openExistingTrackOnClick() {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
SelectFileBottomSheet.showInstance(mapActivity.getSupportFragmentManager(),
createSelectFileListener());
}
}
@Override
public void openLastEditTrackOnClick(GPXFile gpxFile) {
addNewGpxData(gpxFile);
}
@Override
public void dismissButtonOnClick() {
quit(true);
}
};
}
private SelectFileListener createSelectFileListener() {
return new SelectFileListener() {
@Override
public void selectFileOnCLick(GPXFile gpxFile) {
addNewGpxData(gpxFile);
}
@Override
public void dismissButtonOnClick() {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
StartPlanRouteBottomSheet.showInstance(mapActivity.getSupportFragmentManager(),
createStartPlanRouteListener());
}
}
};
}
public void addNewGpxData(GPXFile gpxFile) {
QuadRect rect = gpxFile.getRect();
TrkSegment segment = getTrkSegment(gpxFile);
NewGpxData newGpxData = new NewGpxData(gpxFile, rect, ActionType.EDIT_SEGMENT, segment);
editingCtx.setNewGpxData(newGpxData);
initMeasurementMode(newGpxData);
QuadRect qr = newGpxData.getRect();
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.getMapView().fitRectToMap(qr.left, qr.right, qr.top, qr.bottom,
(int) qr.width(), (int) qr.height(), 0);
}
}
private TrkSegment getTrkSegment(GPXFile gpxFile) {
for (GPXUtilities.Track t : gpxFile.tracks) {
for (TrkSegment s : t.segments) {
if (s.points.size() > 0) {
return s;
}
}
}
return null;
}
private void removePoint(MeasurementToolLayer layer, int position) { private void removePoint(MeasurementToolLayer layer, int position) {
editingCtx.getCommandManager().execute(new RemovePointCommand(layer, position)); editingCtx.getCommandManager().execute(new RemovePointCommand(layer, position));
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
enable(undoBtn); updateUndoRedoButton(true, undoBtn);
disable(redoBtn); updateUndoRedoButton(false, redoBtn);
updateText(); updateText();
saved = false; saved = false;
hidePointsListIfNoPoints(); hidePointsListIfNoPoints();
@ -831,7 +908,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
if (toPosition >= 0 && fromPosition >= 0 && toPosition != fromPosition) { if (toPosition >= 0 && fromPosition >= 0 && toPosition != fromPosition) {
editingCtx.getCommandManager().execute(new ReorderPointCommand(measurementLayer, fromPosition, toPosition)); editingCtx.getCommandManager().execute(new ReorderPointCommand(measurementLayer, fromPosition, toPosition));
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
disable(redoBtn); updateUndoRedoButton(false, redoBtn);
updateText(); updateText();
mapActivity.refreshMap(); mapActivity.refreshMap();
saved = false; saved = false;
@ -1114,8 +1191,9 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
} }
private void doAddOrMovePointCommonStuff() { private void doAddOrMovePointCommonStuff() {
enable(undoBtn, upDownBtn); enable(upDownBtn);
disable(redoBtn); updateUndoRedoButton(true, undoBtn);
updateUndoRedoButton(false, redoBtn);
updateText(); updateText();
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
saved = false; saved = false;
@ -1486,6 +1564,8 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
} }
} }
}); });
snackbar.getView().<TextView>findViewById(com.google.android.material.R.id.snackbar_action)
.setAllCaps(false);
UiUtilities.setupSnackbar(snackbar, nightMode); UiUtilities.setupSnackbar(snackbar, nightMode);
snackbar.show(); snackbar.show();
dismiss(mapActivity); dismiss(mapActivity);
@ -1502,19 +1582,25 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
private void enable(View... views) { private void updateUndoRedoButton(boolean enable, View view) {
for (View view : views) { view.setEnabled(enable);
int color = enable
? nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light
: nightMode ? R.color.icon_color_secondary_dark : R.color.icon_color_secondary_light;
ImageView imageView = ((ImageView) view);
imageView.setImageDrawable(UiUtilities.tintDrawable(imageView.getDrawable(),
ContextCompat.getColor(view.getContext(), color)));
}
private void enable(View view) {
view.setEnabled(true); view.setEnabled(true);
view.setAlpha(1); view.setAlpha(1);
} }
}
private void disable(View... views) { private void disable(View view) {
for (View view : views) {
view.setEnabled(false); view.setEnabled(false);
view.setAlpha(.5f); view.setAlpha(.5f);
} }
}
private void updateText() { private void updateText() {
MeasurementToolLayer measurementLayer = getMeasurementLayer(); MeasurementToolLayer measurementLayer = getMeasurementLayer();
@ -1534,11 +1620,9 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
final File dir = mapActivity.getMyApplication().getAppPath(IndexConstants.GPX_INDEX_DIR); final File dir = mapActivity.getMyApplication().getAppPath(IndexConstants.GPX_INDEX_DIR);
toolBarController.setTitle(getSuggestedName(dir)); toolBarController.setTitle(getSuggestedName(dir));
toolBarController.setDescription(getString(R.string.plan_route)); toolBarController.setDescription(getString(R.string.plan_route));
toolBarController.setSaveViewVisible(true);
} else { } else {
toolBarController.setTitle(getString(R.string.measurement_tool_action_bar)); toolBarController.setTitle(getString(R.string.plan_route));
toolBarController.setDescription(null); toolBarController.setDescription(null);
toolBarController.setSaveViewVisible(false);
} }
mapActivity.showTopToolbar(toolBarController); mapActivity.showTopToolbar(toolBarController);
} }
@ -1699,7 +1783,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
} else { } else {
visibleSnapToRoadIcon(false); visibleSnapToRoadIcon(false);
} }
if (editingCtx.getNewGpxData() != null) { if (editingCtx.getNewGpxData() != null && !planRouteMode) {
GPXFile gpx = editingCtx.getNewGpxData().getGpxFile(); GPXFile gpx = editingCtx.getNewGpxData().getGpxFile();
Intent newIntent = new Intent(mapActivity, mapActivity.getMyApplication().getAppCustomization().getTrackActivity()); Intent newIntent = new Intent(mapActivity, mapActivity.getMyApplication().getAppCustomization().getTrackActivity());
newIntent.putExtra(TrackActivity.TRACK_FILE_NAME, gpx.path); newIntent.putExtra(TrackActivity.TRACK_FILE_NAME, gpx.path);
@ -1726,7 +1810,9 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
} }
public static boolean showInstance(FragmentManager fragmentManager) { public static boolean showInstance(FragmentManager fragmentManager) {
return showFragment(new MeasurementToolFragment(), fragmentManager); MeasurementToolFragment fragment = new MeasurementToolFragment();
fragment.setPlanRouteMode(true);
return showFragment(fragment, fragmentManager);
} }
private static boolean showFragment(MeasurementToolFragment fragment, FragmentManager fragmentManager) { private static boolean showFragment(MeasurementToolFragment fragment, FragmentManager fragmentManager) {
@ -1743,29 +1829,44 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
private class MeasurementToolBarController extends TopToolbarController { private class MeasurementToolBarController extends TopToolbarController {
MeasurementToolBarController(NewGpxData newGpxData) { MeasurementToolBarController() {
super(MapInfoWidgetsFactory.TopToolbarControllerType.MEASUREMENT_TOOL); super(TopToolbarControllerType.MEASUREMENT_TOOL);
setBackBtnIconClrIds(0, 0); setBackBtnIconClrIds(0, 0);
setTitleTextClrIds(R.color.text_color_tab_active_light, R.color.text_color_tab_active_dark); setTitleTextClrIds(R.color.text_color_tab_active_light, R.color.text_color_tab_active_dark);
setDescrTextClrIds(R.color.text_color_tab_active_light, R.color.text_color_tab_active_dark); setDescrTextClrIds(R.color.text_color_tab_active_light, R.color.text_color_tab_active_dark);
setBgIds(R.drawable.gradient_toolbar, R.drawable.gradient_toolbar, setBgIds(R.drawable.gradient_toolbar, R.drawable.gradient_toolbar,
R.drawable.gradient_toolbar, R.drawable.gradient_toolbar); R.drawable.gradient_toolbar, R.drawable.gradient_toolbar);
setCloseBtnVisible(false); setCloseBtnVisible(false);
if (newGpxData != null) {
setSaveViewVisible(true); setSaveViewVisible(true);
}
setSingleLineTitle(false); setSingleLineTitle(false);
setSaveViewTextId(R.string.shared_string_done);
} }
@Override @Override
public void updateToolbar(MapInfoWidgetsFactory.TopToolbarView view) { public void updateToolbar(TopToolbarView view) {
super.updateToolbar(view); super.updateToolbar(view);
setupDoneButton(view);
View shadow = view.getShadowView(); View shadow = view.getShadowView();
if (shadow != null) { if (shadow != null) {
shadow.setVisibility(View.GONE); shadow.setVisibility(View.GONE);
} }
} }
private void setupDoneButton(TopToolbarView view) {
TextView done = view.getSaveView();
Context ctx = done.getContext();
done.setAllCaps(false);
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) done.getLayoutParams();
layoutParams.height = ctx.getResources().getDimensionPixelSize(R.dimen.measurement_tool_button_height);
layoutParams.leftMargin = ctx.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_large);
layoutParams.rightMargin = ctx.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_large);
int paddingH = ctx.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_large);
int paddingV = ctx.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_small);
done.setPadding(paddingH, paddingV, paddingH, paddingV);
AndroidUtils.setBackground(ctx, done, nightMode, R.drawable.dlg_btn_stroked_light,
R.drawable.dlg_btn_stroked_dark);
}
@Override @Override
public int getStatusBarColor(Context context, boolean night) { public int getStatusBarColor(Context context, boolean night) {
return NO_COLOR; return NO_COLOR;

View file

@ -0,0 +1,171 @@
package net.osmand.plus.measurementtool;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.IndexConstants;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.helpers.GpxTrackAdapter;
import net.osmand.plus.helpers.GpxTrackAdapter.OnItemClickListener;
import net.osmand.plus.helpers.GpxUiHelper.GPXInfo;
import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter;
import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter.HorizontalSelectionAdapterListener;
import net.osmand.util.Algorithms;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static net.osmand.plus.helpers.GpxUiHelper.getSortedGPXFilesInfo;
public class SelectFileBottomSheet extends MenuBottomSheetDialogFragment {
public static final String TAG = SelectFileBottomSheet.class.getSimpleName();
public static final int BOTTOM_SHEET_HEIGHT_DP = 427;
protected View mainView;
protected GpxTrackAdapter adapter;
private SelectFileListener listener;
private Map<String, List<GPXInfo>> gpxInfoMap;
public void setListener(SelectFileListener listener) {
this.listener = listener;
}
@Override
public void createMenuItems(Bundle savedInstanceState) {
final int themeRes = nightMode ? R.style.OsmandDarkTheme : R.style.OsmandLightTheme;
Context context = requireContext();
OsmandApplication app = requiredMyApplication();
mainView = View.inflate(new ContextThemeWrapper(context, themeRes),
R.layout.bottom_sheet_plan_route_select_file, null);
final RecyclerView filesRecyclerView = mainView.findViewById(R.id.gpx_track_list);
filesRecyclerView.setLayoutManager(new LinearLayoutManager(context));
List<File> dirs = new ArrayList<>();
final File gpxDir = app.getAppPath(IndexConstants.GPX_INDEX_DIR);
collectDirs(gpxDir, dirs);
List<String> dirItems = new ArrayList<>();
for (File dir : dirs) {
dirItems.add(dir.getName());
}
String allFilesFolder = context.getString(R.string.shared_string_all);
dirItems.add(0, allFilesFolder);
final List<GPXInfo> allGpxList = getSortedGPXFilesInfo(gpxDir, null, false);
gpxInfoMap = new HashMap<>();
gpxInfoMap.put(allFilesFolder, allGpxList);
for (GPXInfo gpxInfo : allGpxList) {
String folderName = getFolderName(gpxInfo);
List<GPXInfo> gpxList = gpxInfoMap.get(folderName);
if (gpxList == null) {
gpxList = new ArrayList<>();
gpxInfoMap.put(folderName, gpxList);
}
gpxList.add(gpxInfo);
}
adapter = new GpxTrackAdapter(requireContext(), allGpxList, false);
adapter.setAdapterListener(new OnItemClickListener() {
@Override
public void onItemClick(int position) {
if (position != RecyclerView.NO_POSITION && position < allGpxList.size()) {
String fileName = allGpxList.get(position).getFileName();
GPXFile gpxFile = GPXUtilities.loadGPXFile(new File(gpxDir, fileName));
if (listener != null) {
listener.selectFileOnCLick(gpxFile);
}
}
dismiss();
}
});
filesRecyclerView.setAdapter(adapter);
final RecyclerView foldersRecyclerView = mainView.findViewById(R.id.folder_list);
foldersRecyclerView.setLayoutManager(new LinearLayoutManager(context,
RecyclerView.HORIZONTAL, false));
final HorizontalSelectionAdapter folderAdapter = new HorizontalSelectionAdapter(app, nightMode);
folderAdapter.setItems(dirItems);
folderAdapter.setSelectedItem(allFilesFolder);
foldersRecyclerView.setAdapter(folderAdapter);
folderAdapter.setListener(new HorizontalSelectionAdapterListener() {
@Override
public void onItemSelected(String item) {
List<GPXInfo> gpxInfoList = gpxInfoMap.get(item);
adapter.setGpxInfoList(gpxInfoList != null ? gpxInfoList : new ArrayList<GPXInfo>());
adapter.notifyDataSetChanged();
folderAdapter.notifyDataSetChanged();
}
});
items.add(new BaseBottomSheetItem.Builder().setCustomView(mainView).create());
}
private String getFolderName(GPXInfo gpxInfo) {
int fileNameStartIndex = gpxInfo.getFileName().lastIndexOf(File.separator);
return fileNameStartIndex != -1
? gpxInfo.getFileName().substring(0, fileNameStartIndex)
: IndexConstants.GPX_INDEX_DIR.substring(0, IndexConstants.GPX_INDEX_DIR.length() - 1);
}
private void collectDirs(File dir, List<File> dirs) {
File[] listFiles = dir.listFiles();
if (listFiles != null) {
Arrays.sort(listFiles);
for (File f : listFiles) {
if (f.isDirectory()) {
dirs.add(f);
collectDirs(f, dirs);
}
}
}
}
@Override
protected int getCustomHeight() {
return AndroidUtils.dpToPx(mainView.getContext(), BOTTOM_SHEET_HEIGHT_DP);
}
public static void showInstance(FragmentManager fragmentManager, SelectFileListener listener) {
if (!fragmentManager.isStateSaved()) {
SelectFileBottomSheet fragment = new SelectFileBottomSheet();
fragment.setUsedOnMap(true);
fragment.setRetainInstance(true);
fragment.setListener(listener);
fragment.show(fragmentManager, SelectFileBottomSheet.TAG);
}
}
@Override
protected int getDismissButtonTextId() {
return R.string.shared_string_cancel;
}
@Override
protected void onDismissButtonClickAction() {
if (listener != null) {
listener.dismissButtonOnClick();
}
}
interface SelectFileListener {
void selectFileOnCLick(GPXFile gpxFile);
void dismissButtonOnClick();
}
}

View file

@ -0,0 +1,229 @@
package net.osmand.plus.measurementtool;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerHalfItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
import net.osmand.plus.helpers.GpxTrackAdapter;
import net.osmand.plus.helpers.GpxUiHelper.GPXInfo;
import net.osmand.plus.helpers.ImportHelper;
import org.apache.commons.logging.Log;
import java.io.File;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static net.osmand.plus.helpers.GpxUiHelper.getSortedGPXFilesInfo;
public class StartPlanRouteBottomSheet extends MenuBottomSheetDialogFragment {
public static final String TAG = StartPlanRouteBottomSheet.class.getSimpleName();
private static final Log LOG = PlatformUtil.getLog(StartPlanRouteBottomSheet.class);
public static final int BOTTOM_SHEET_HEIGHT_DP = 427;
private static final int OPEN_GPX_DOCUMENT_REQUEST = 1001;
protected View mainView;
protected GpxTrackAdapter adapter;
private StartPlanRouteListener listener;
private ImportHelper importHelper;
public void setListener(StartPlanRouteListener listener) {
this.listener = listener;
}
@Override
public void createMenuItems(Bundle savedInstanceState) {
importHelper = new ImportHelper((AppCompatActivity) getActivity(), getMyApplication(), null);
final int themeRes = nightMode ? R.style.OsmandDarkTheme : R.style.OsmandLightTheme;
mainView = View.inflate(new ContextThemeWrapper(getContext(), themeRes),
R.layout.bottom_sheet_plan_route_start, null);
items.add(new TitleItem(getString(R.string.plan_route)));
BaseBottomSheetItem createNewRouteItem = new BottomSheetItemWithDescription.Builder()
.setIcon(getContentIcon(R.drawable.ic_notification_track))
.setTitle(getString(R.string.plan_route_create_new_route))
.setLayoutId(R.layout.bottom_sheet_item_simple_pad_32dp)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
})
.create();
items.add(createNewRouteItem);
BaseBottomSheetItem openExistingTrackItem = new BottomSheetItemWithDescription.Builder()
.setIcon(getContentIcon(R.drawable.ic_action_folder))
.setTitle(getString(R.string.plan_route_open_existing_track))
.setLayoutId(R.layout.bottom_sheet_item_simple_pad_32dp)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
listener.openExistingTrackOnClick();
}
dismiss();
}
})
.create();
items.add(openExistingTrackItem);
BaseBottomSheetItem importTrackItem = new BottomSheetItemWithDescription.Builder()
.setIcon(getContentIcon(R.drawable.ic_action_phone))
.setTitle(getString(R.string.plan_route_import_track))
.setLayoutId(R.layout.bottom_sheet_item_simple_pad_32dp)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
importTrack();
}
})
.create();
items.add(importTrackItem);
items.add(new DividerHalfItem(getContext()));
final RecyclerView recyclerView = mainView.findViewById(R.id.gpx_track_list);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
OsmandApplication app = getMyApplication();
if (app == null) {
return;
}
File gpxDir = app.getAppPath(IndexConstants.GPX_INDEX_DIR);
List<GPXInfo> gpxList = getSortedGPXFilesInfo(gpxDir, null, false);
Collections.sort(gpxList, new Comparator<GPXInfo>() {
@Override
public int compare(GPXInfo lhs, GPXInfo rhs) {
return lhs.getLastModified() > rhs.getLastModified()
? -1 : (lhs.getLastModified() == rhs.getLastModified() ? 0 : 1);
}
});
final List<GPXInfo> gpxTopList = gpxList.subList(0, Math.min(5, gpxList.size()));
adapter = new GpxTrackAdapter(requireContext(), gpxList, false);
adapter.setAdapterListener(new GpxTrackAdapter.OnItemClickListener() {
@Override
public void onItemClick(int position) {
StartPlanRouteBottomSheet.this.onItemClick(position, gpxTopList);
}
});
recyclerView.setAdapter(adapter);
items.add(new BaseBottomSheetItem.Builder().setCustomView(mainView).create());
}
@Override
protected int getCustomHeight() {
return AndroidUtils.dpToPx(mainView.getContext(), BOTTOM_SHEET_HEIGHT_DP);
}
private void onItemClick(int position, List<GPXInfo> gpxInfoList) {
if (position != RecyclerView.NO_POSITION && position < gpxInfoList.size()) {
OsmandApplication app = requiredMyApplication();
String fileName = gpxInfoList.get(position).getFileName();
GPXFile gpxFile = GPXUtilities.loadGPXFile(new File(app.getAppPath(IndexConstants.GPX_INDEX_DIR), fileName));
if (listener != null) {
listener.openLastEditTrackOnClick(gpxFile);
}
}
dismiss();
}
private void importTrack() {
Intent intent = new Intent();
String action;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
action = Intent.ACTION_OPEN_DOCUMENT;
} else {
action = Intent.ACTION_GET_CONTENT;
}
intent.setAction(action);
intent.setType("*/*");
try {
startActivityForResult(intent, OPEN_GPX_DOCUMENT_REQUEST);
} catch (ActivityNotFoundException e) {
LOG.error(e.getMessage(), e);
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == OPEN_GPX_DOCUMENT_REQUEST && resultCode == Activity.RESULT_OK) {
if (data != null) {
Uri uri = data.getData();
importHelper.setGpxImportCompleteListener(new ImportHelper.OnGpxImportCompleteListener() {
@Override
public void onComplete(boolean success) {
finishImport(success);
importHelper.setGpxImportCompleteListener(null);
}
});
importHelper.handleGpxImport(uri, false, false);
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
void finishImport(boolean success) {
if (success) {
dismiss();
}
}
public static void showInstance(FragmentManager fragmentManager, StartPlanRouteListener listener) {
if (!fragmentManager.isStateSaved()) {
StartPlanRouteBottomSheet fragment = new StartPlanRouteBottomSheet();
fragment.setUsedOnMap(true);
fragment.setRetainInstance(true);
fragment.setListener(listener);
fragment.show(fragmentManager, StartPlanRouteBottomSheet.TAG);
}
}
@Override
protected int getDismissButtonTextId() {
return R.string.shared_string_cancel;
}
@Override
protected void onDismissButtonClickAction() {
if (listener != null) {
listener.dismissButtonOnClick();
}
}
interface StartPlanRouteListener {
void openExistingTrackOnClick();
void openLastEditTrackOnClick(GPXFile gpxFile);
void dismissButtonOnClick();
}
}