Merge pull request #8756 from osmandapp/select_gpx_track

Select gpx track
This commit is contained in:
vshcherb 2020-04-08 14:55:08 +02:00 committed by GitHub
commit 38d1215a8f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 385 additions and 62 deletions

View file

@ -0,0 +1,69 @@
<?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:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/select_track_file"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_medium" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/counter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_regular"
tools:text="10" />
</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
android:id="@+id/buttons_container"
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="vertical"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding_small"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding_small">
<include
android:id="@+id/dismiss_button"
layout="@layout/bottom_sheet_dialog_button"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,126 @@
<?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="@dimen/settings_divider_margin_start"
android:background="?attr/selectableItemBackground"
android:orientation="horizontal">
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/list_content_padding"
android:layout_marginLeft="@dimen/list_content_padding"
android:layout_marginEnd="@dimen/list_content_padding"
android:layout_marginRight="@dimen/list_content_padding"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_action_polygom_dark"
android:visibility="visible"
android:contentDescription="@string/shared_string_icon" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/list_content_padding"
android:layout_marginLeft="@dimen/list_content_padding"
android:layout_marginEnd="@dimen/list_content_padding"
android:layout_marginRight="@dimen/list_content_padding"
android:layout_weight="1"
android:orientation="vertical"
android:paddingTop="@dimen/content_padding_small"
android:paddingBottom="@dimen/content_padding_small">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
tools:text="@string/current_track" />
<LinearLayout
android:id="@+id/read_section"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="@dimen/subHeaderPadding"
android:paddingBottom="@dimen/subHeaderPadding"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="visible">
<ImageView
android:id="@+id/distance_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/content_padding_half"
android:layout_marginRight="@dimen/content_padding_half"
android:src="@drawable/ic_action_distance_16"
android:contentDescription="@string/distance" />
<TextView
android:id="@+id/distance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size" />
<ImageView
android:id="@+id/points_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/content_padding_half"
android:layout_marginRight="@dimen/content_padding_half"
android:src="@drawable/ic_action_waypoint_16"
android:contentDescription="@string/track_points" />
<TextView
android:id="@+id/points_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
tools:text="0" />
<ImageView
android:id="@+id/time_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/content_padding_half"
android:layout_marginRight="@dimen/content_padding_half"
android:src="@drawable/ic_action_time_16"
android:contentDescription="@string/shared_string_time_moving" />
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size" />
</LinearLayout>
<LinearLayout
android:id="@+id/unknown_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone">
<TextView
android:id="@+id/date_and_size_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View file

@ -11,6 +11,7 @@
Thx - Hardy Thx - Hardy
--> -->
<string name="select_track_file">Select track file</string>
<string name="settings_item_import_error">Could not import %1$s.</string> <string name="settings_item_import_error">Could not import %1$s.</string>
<string name="settings_item_write_error">Could not write %1$s.</string> <string name="settings_item_write_error">Could not write %1$s.</string>
<string name="settings_item_read_error">Could not read %1$s.</string> <string name="settings_item_read_error">Could not read %1$s.</string>

View file

@ -0,0 +1,159 @@
package net.osmand.plus.helpers;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities;
import net.osmand.IndexConstants;
import net.osmand.plus.GPXDatabase;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.util.Algorithms;
import java.io.File;
import java.text.DateFormat;
import java.util.Date;
import java.util.List;
public class GpxTrackAdapter extends RecyclerView.Adapter<GpxTrackAdapter.TrackViewHolder> {
private LayoutInflater themedInflater;
private List<GpxUiHelper.GPXInfo> gpxInfoList;
private OsmandApplication app;
private boolean showCurrentGpx;
private OnItemClickListener onItemClickListener;
private UiUtilities iconsCache;
GpxTrackAdapter(Activity activity, List<GpxUiHelper.GPXInfo> gpxInfoList, boolean showCurrentGpx,
OnItemClickListener onItemClickListener) {
this.showCurrentGpx = showCurrentGpx;
this.onItemClickListener = onItemClickListener;
app = (OsmandApplication) activity.getApplication();
boolean nightMode = app.getDaynightHelper().isNightModeForMapControls();
themedInflater = UiUtilities.getInflater(activity, nightMode);
this.gpxInfoList = gpxInfoList;
iconsCache = app.getUIUtilities();
}
@NonNull
@Override
public GpxTrackAdapter.TrackViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = themedInflater.inflate(R.layout.gpx_track_select_item, parent, false);
ImageView distanceIcon = view.findViewById(R.id.distance_icon);
distanceIcon.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_distance_16));
ImageView pointsIcon = view.findViewById(R.id.points_icon);
pointsIcon.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_waypoint_16));
ImageView timeIcon = view.findViewById(R.id.time_icon);
timeIcon.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_time_16));
return new TrackViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull final GpxTrackAdapter.TrackViewHolder holder, final int position) {
boolean currentlyRecordingTrack = (showCurrentGpx && position == 0);
if (currentlyRecordingTrack) {
holder.icon.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_track_recordable));
} else {
holder.icon.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_polygom_dark));
}
final int adapterPosition = holder.getAdapterPosition();
GpxUiHelper.GPXInfo info = gpxInfoList.get(adapterPosition);
GPXDatabase.GpxDataItem dataItem = getDataItem(info);
String itemTitle = GpxUiHelper.getGpxTitle(info.getFileName());
updateGpxInfoView(holder, itemTitle, info, dataItem, currentlyRecordingTrack, app);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onItemClickListener.onItemClick(adapterPosition);
}
});
}
@Override
public int getItemCount() {
return gpxInfoList.size();
}
private void updateGpxInfoView(TrackViewHolder holder, String itemTitle, GpxUiHelper.GPXInfo info,
GPXDatabase.GpxDataItem dataItem, boolean currentlyRecordingTrack,
OsmandApplication app) {
holder.name.setText(itemTitle.replace("/", "").trim());
GPXUtilities.GPXTrackAnalysis analysis = null;
if (currentlyRecordingTrack) {
analysis = app.getSavingTrackHelper().getCurrentTrack().getTrackAnalysis(app);
} else if (dataItem != null) {
analysis = dataItem.getAnalysis();
}
if (analysis == null) {
holder.readSection.setVisibility(View.GONE);
holder.unknownSection.setVisibility(View.VISIBLE);
String date = "";
String size = "";
if (info.getFileSize() >= 0) {
size = AndroidUtils.formatSize(app, info.getFileSize());
}
DateFormat df = app.getResourceManager().getDateFormat();
long fd = info.getLastModified();
if (fd > 0) {
date = (df.format(new Date(fd)));
}
holder.dateAndSize.setText(String.format(app.getString(R.string.ltr_or_rtl_combine_via_bold_point), date, size));
} else {
holder.readSection.setVisibility(View.VISIBLE);
holder.unknownSection.setVisibility(View.GONE);
holder.pointsCount.setText(String.valueOf(analysis.wptPoints));
holder.distance.setText(OsmAndFormatter.getFormattedDistance(analysis.totalDistance, app));
if (analysis.isTimeSpecified()) {
holder.time.setText(Algorithms.formatDuration((int) (analysis.timeSpan / 1000), app.accessibilityEnabled()));
} else {
holder.time.setText("");
}
}
}
private GPXDatabase.GpxDataItem getDataItem(GpxUiHelper.GPXInfo info) {
return app.getGpxDbHelper().getItem(new File(app.getAppPath(IndexConstants.GPX_INDEX_DIR), info.getFileName()));
}
static class TrackViewHolder extends RecyclerView.ViewHolder {
ImageView icon;
TextView name;
TextView distance;
TextView pointsCount;
TextView time;
LinearLayout readSection;
LinearLayout unknownSection;
TextView dateAndSize;
TrackViewHolder(View itemView) {
super(itemView);
icon = itemView.findViewById(R.id.icon);
name = itemView.findViewById(R.id.name);
distance = itemView.findViewById(R.id.distance);
pointsCount = itemView.findViewById(R.id.points_count);
time = itemView.findViewById(R.id.time);
readSection = itemView.findViewById(R.id.read_section);
unknownSection = itemView.findViewById(R.id.unknown_section);
dateAndSize = itemView.findViewById(R.id.date_and_size_details);
}
}
public interface OnItemClickListener {
void onItemClick(int position);
}
}

View file

@ -15,7 +15,6 @@ import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.text.SpannableString; import android.text.SpannableString;
import android.text.style.StyleSpan; import android.text.style.StyleSpan;
import android.util.TypedValue;
import android.view.ContextThemeWrapper; import android.view.ContextThemeWrapper;
import android.view.Gravity; import android.view.Gravity;
import android.view.View; import android.view.View;
@ -38,6 +37,8 @@ import androidx.appcompat.widget.ListPopupWindow;
import androidx.appcompat.widget.SwitchCompat; import androidx.appcompat.widget.SwitchCompat;
import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.github.mikephil.charting.charts.HorizontalBarChart; import com.github.mikephil.charting.charts.HorizontalBarChart;
import com.github.mikephil.charting.charts.LineChart; import com.github.mikephil.charting.charts.LineChart;
@ -355,60 +356,19 @@ public class GpxUiHelper {
final List<GPXInfo> list, final List<GPXInfo> list,
final ContextMenuAdapter adapter) { final ContextMenuAdapter adapter) {
final OsmandApplication app = (OsmandApplication) activity.getApplication(); final OsmandApplication app = (OsmandApplication) activity.getApplication();
final UiUtilities iconsCache = app.getUIUtilities(); boolean nightMode = app.getDaynightHelper().isNightModeForMapControls();
final File dir = app.getAppPath(IndexConstants.GPX_INDEX_DIR); final View customLayout = UiUtilities.getInflater(activity, nightMode).inflate(R.layout.gpx_track_select_dialog, null);
AlertDialog.Builder builder = new AlertDialog.Builder(activity); AlertDialog.Builder builder = new AlertDialog.Builder(UiUtilities.getThemedContext(activity, nightMode));
final int layout = R.layout.list_menu_item_native_singlechoice; builder.setView(customLayout);
final AlertDialog dlg = builder.create();
final ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(activity, layout, R.id.text1, View cancelButton = customLayout.findViewById(R.id.dismiss_button);
adapter.getItemNames()) { UiUtilities.setupDialogButton(nightMode, cancelButton, UiUtilities.DialogButtonType.SECONDARY, R.string.shared_string_cancel);
TextView gpxCounter = customLayout.findViewById(R.id.counter);
gpxCounter.setText(String.valueOf(adapter.length()));
GpxTrackAdapter gpxTrackAdapter = new GpxTrackAdapter(activity, list, showCurrentGpx,
new GpxTrackAdapter.OnItemClickListener() {
@Override @Override
public View getView(final int position, View convertView, ViewGroup parent) { public void onItemClick(int position) {
// User super class to create the View
View v = convertView;
if (v == null) {
v = activity.getLayoutInflater().inflate(layout, null);
}
final ContextMenuItem item = adapter.getItem(position);
TextView tv = (TextView) v.findViewById(R.id.text1);
Drawable icon;
if (showCurrentGpx && position == 0) {
icon = null;
} else {
icon = iconsCache.getThemedIcon(item.getIcon());
}
tv.setCompoundDrawablePadding(AndroidUtils.dpToPx(activity, 10f));
tv.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
tv.setText(item.getTitle());
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
return v;
}
};
int selectedIndex = 0;
String prevSelectedGpx = app.getSettings().LAST_SELECTED_GPX_TRACK_FOR_NEW_POINT.get();
if (prevSelectedGpx != null) {
selectedIndex = list.indexOf(prevSelectedGpx);
}
if (selectedIndex == -1) {
selectedIndex = 0;
}
final int[] selectedPosition = {selectedIndex};
builder.setSingleChoiceItems(listAdapter, selectedIndex, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int position) {
selectedPosition[0] = position;
}
});
builder.setTitle(R.string.select_gpx)
.setPositiveButton(R.string.shared_string_ok, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
int position = selectedPosition[0];
if (position != -1 && position < list.size()) { if (position != -1 && position < list.size()) {
if (showCurrentGpx && position == 0) { if (showCurrentGpx && position == 0) {
callbackWithObject.processResult(null); callbackWithObject.processResult(null);
@ -419,19 +379,27 @@ public class GpxUiHelper {
SelectedGpxFile selectedGpxFile = SelectedGpxFile selectedGpxFile =
app.getSelectedGpxHelper().getSelectedFileByName(fileName); app.getSelectedGpxHelper().getSelectedFileByName(fileName);
if (selectedGpxFile != null) { if (selectedGpxFile != null) {
callbackWithObject.processResult(new GPXFile[]{selectedGpxFile.getGpxFile()}); callbackWithObject.processResult(new GPXUtilities.GPXFile[]{selectedGpxFile.getGpxFile()});
} else { } else {
loadGPXFileInDifferentThread(activity, callbackWithObject, dir, null, fileName); File dir = app.getAppPath(IndexConstants.GPX_INDEX_DIR);
GpxUiHelper.loadGPXFileInDifferentThread(activity, callbackWithObject, dir, null, fileName);
} }
} }
} }
dlg.dismiss();
} }
}) });
.setNegativeButton(R.string.shared_string_cancel, null); RecyclerView recyclerView = customLayout.findViewById(R.id.gpx_track_list);
recyclerView.setAdapter(gpxTrackAdapter);
final AlertDialog dlg = builder.create(); recyclerView.setLayoutManager(new LinearLayoutManager(app, LinearLayoutManager.VERTICAL, false));
dlg.setCanceledOnTouchOutside(false); dlg.setCanceledOnTouchOutside(false);
dlg.show(); dlg.show();
cancelButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dlg.dismiss();
}
});
try { try {
dlg.getListView().setFastScrollEnabled(true); dlg.getListView().setFastScrollEnabled(true);
} catch (Exception e) { } catch (Exception e) {
@ -1007,7 +975,7 @@ public class GpxUiHelper {
} }
private static void loadGPXFileInDifferentThread(final Activity activity, final CallbackWithObject<GPXFile[]> callbackWithObject, static void loadGPXFileInDifferentThread(final Activity activity, final CallbackWithObject<GPXFile[]> callbackWithObject,
final File dir, final GPXFile currentFile, final String... filename) { final File dir, final GPXFile currentFile, final String... filename) {
final ProgressDialog dlg = ProgressDialog.show(activity, activity.getString(R.string.loading_smth, ""), final ProgressDialog dlg = ProgressDialog.show(activity, activity.getString(R.string.loading_smth, ""),
activity.getString(R.string.loading_data)); activity.getString(R.string.loading_data));