From 93a642d3225e452761f9f5c507a6f2ed97d97f26 Mon Sep 17 00:00:00 2001 From: androiddevkotlin <64539346+androiddevkotlin@users.noreply.github.com> Date: Wed, 3 Feb 2021 15:16:07 +0200 Subject: [PATCH 01/45] Select segment bottom sheet --- .../layout/bottom_sheet_select_segment.xml | 70 +++++++++ OsmAnd/res/layout/gpx_segment_list_item.xml | 96 ++++++++++++ OsmAnd/res/values/strings.xml | 3 + .../helpers/TrackSelectSegmentAdapter.java | 144 ++++++++++++++++++ .../track/TrackSelectSegmentBottomSheet.java | 74 +++++++++ 5 files changed, 387 insertions(+) create mode 100644 OsmAnd/res/layout/bottom_sheet_select_segment.xml create mode 100644 OsmAnd/res/layout/gpx_segment_list_item.xml create mode 100644 OsmAnd/src/net/osmand/plus/helpers/TrackSelectSegmentAdapter.java create mode 100644 OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java diff --git a/OsmAnd/res/layout/bottom_sheet_select_segment.xml b/OsmAnd/res/layout/bottom_sheet_select_segment.xml new file mode 100644 index 0000000000..de758bc182 --- /dev/null +++ b/OsmAnd/res/layout/bottom_sheet_select_segment.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/layout/gpx_segment_list_item.xml b/OsmAnd/res/layout/gpx_segment_list_item.xml new file mode 100644 index 0000000000..f591d86e50 --- /dev/null +++ b/OsmAnd/res/layout/gpx_segment_list_item.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 2c3358dda4..bde3e4040a 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -14,6 +14,9 @@ Select edits for upload Uploaded %1$d of %2$d + Segment %1$d + %1$s contains more than one segment, you need to select the needed part for the navigation. + Select segments Uploading %1$d of %2$d Upload completed Uploading diff --git a/OsmAnd/src/net/osmand/plus/helpers/TrackSelectSegmentAdapter.java b/OsmAnd/src/net/osmand/plus/helpers/TrackSelectSegmentAdapter.java new file mode 100644 index 0000000000..0ca79ab891 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/helpers/TrackSelectSegmentAdapter.java @@ -0,0 +1,144 @@ +package net.osmand.plus.helpers; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import net.osmand.GPXUtilities.TrkSegment; +import net.osmand.GPXUtilities.WptPt; +import net.osmand.plus.GPXDatabase; +import net.osmand.plus.GpxSelectionHelper; +import net.osmand.plus.OsmAndFormatter; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.UiUtilities; +import net.osmand.plus.measurementtool.MeasurementEditingContext; +import net.osmand.util.MapUtils; + +import java.util.List; + +public class TrackSelectSegmentAdapter extends RecyclerView.Adapter { + private final OsmandApplication app; + private final LayoutInflater themedInflater; + private final UiUtilities iconsCache; + private GpxTrackAdapter.OnItemClickListener onItemClickListener; + + private final List segments; + + public TrackSelectSegmentAdapter(Context ctx, List segments) { + app = (OsmandApplication) ctx.getApplicationContext(); + themedInflater = UiUtilities.getInflater(ctx, app.getDaynightHelper().isNightModeForMapControls()); + iconsCache = app.getUIUtilities(); + this.segments = segments; + } + + @NonNull + @Override + public TrackSelectSegmentAdapter.TrackViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = themedInflater.inflate(R.layout.gpx_segment_list_item, parent, false); + ImageView distanceIcon = view.findViewById(R.id.distance_icon); + distanceIcon.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_split_interval)); + ImageView timeIcon = view.findViewById(R.id.time_icon); + timeIcon.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_time_moving_16)); + return new TrackSelectSegmentAdapter.TrackViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull final TrackSelectSegmentAdapter.TrackViewHolder holder, final int position) { + holder.icon.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_split_interval)); + + TrkSegment segment = segments.get(position); + + String segmentTitle = app.getResources().getString(R.string.segments_count, position + 1); + holder.name.setText(segmentTitle); + + double distance = getDistance(segment); + long time = getSegmentTime(segment); + holder.time.setText(OsmAndFormatter.getFormattedDurationShort((int) (time / 1000))); + holder.distance.setText(OsmAndFormatter.getFormattedDistance((float) distance, app)); +// updateTrackSegmentInfoView(holder, info, gpxSegmentList, dataItem, app); + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (onItemClickListener != null) { + onItemClickListener.onItemClick(holder.getAdapterPosition()); + } + } + }); + } + + private long getSegmentTime(TrkSegment segment) { + long segmentTime; + long startTime = Long.MAX_VALUE; + long endTime = Long.MIN_VALUE; + for (int i = 0; i < segment.points.size(); i++) { + WptPt point = segment.points.get(i); + long time = point.time; + if (time != 0) { + startTime = Math.min(startTime, time); + endTime = Math.max(endTime, time); + } + } + segmentTime = endTime - startTime; + + return segmentTime; + } + + private double getDistance(TrkSegment segment) { + double distance = 0; + WptPt prevPoint = null; + for (int i = 0; i < segment.points.size(); i++) { + WptPt point = segment.points.get(i); + if (prevPoint != null) { + distance += MapUtils.getDistance(prevPoint.getLatitude(), prevPoint.getLongitude(), point.getLatitude(), point.getLongitude()); + } + prevPoint = point; + } + + return distance; + } + + @Override + public int getItemCount() { + return segments.size(); + } + + private void updateTrackSegmentInfoView(TrackSelectSegmentAdapter.TrackViewHolder holder, MeasurementEditingContext info, GpxSelectionHelper.SelectedGpxFile gpxSegmentList, + GPXDatabase.GpxDataItem dataItem, + OsmandApplication app) { + + } + + + public void setAdapterListener(GpxTrackAdapter.OnItemClickListener onItemClickListener) { + this.onItemClickListener = onItemClickListener; + } + + public interface OnItemClickListener { + + void onItemClick(int position); + + } + + static class TrackViewHolder extends RecyclerView.ViewHolder { + + ImageView icon; + TextView name; + TextView distance; + TextView time; + + TrackViewHolder(View itemView) { + super(itemView); + icon = itemView.findViewById(R.id.icon); + name = itemView.findViewById(R.id.name); + distance = itemView.findViewById(R.id.distance); + time = itemView.findViewById(R.id.time_interval); + } + } +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java b/OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java new file mode 100644 index 0000000000..199e30c1cd --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java @@ -0,0 +1,74 @@ +package net.osmand.plus.track; + +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import net.osmand.GPXUtilities.TrkSegment; +import net.osmand.plus.GpxSelectionHelper; +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.BottomSheetItemWithDescription; +import net.osmand.plus.helpers.GpxTrackAdapter; +import net.osmand.plus.helpers.TrackSelectSegmentAdapter; +import net.osmand.plus.widgets.TextViewEx; +import net.osmand.util.Algorithms; + +import java.util.List; + +public class TrackSelectSegmentBottomSheet extends MenuBottomSheetDialogFragment { + + public static final String TAG = TrackSelectSegmentBottomSheet.class.getSimpleName(); + protected TrackSelectSegmentAdapter adapterSegments; + private GpxSelectionHelper.SelectedGpxFile file; + + public static void showInstance(@NonNull FragmentManager fragmentManager, @NonNull GpxSelectionHelper.SelectedGpxFile file) { + if (!fragmentManager.isStateSaved()) { + TrackSelectSegmentBottomSheet fragment = new TrackSelectSegmentBottomSheet(); + fragment.file = file; + fragment.show(fragmentManager, TAG); + } + } + + @Override + public void createMenuItems(Bundle savedInstanceState) { + Context context = requireContext(); + + LayoutInflater inflater = UiUtilities.getInflater(context, nightMode); + View itemView = inflater.inflate(R.layout.bottom_sheet_select_segment, null, false); + String titleGpxTrack = Algorithms.getFileWithoutDirs(file.getGpxFile().path); + + items.add(new BottomSheetItemWithDescription.Builder() + .setDescription(getString(R.string.select_segments_description, titleGpxTrack)) + .setCustomView(itemView) + .create()); + + OsmandApplication app = getMyApplication(); + if (app == null) { + return; + } + TextViewEx titleGpxTrackView = itemView.findViewById(R.id.title_gpx_track); + titleGpxTrackView.setText(titleGpxTrack); + + final RecyclerView recyclerView = itemView.findViewById(R.id.gpx_segment_list); + recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + recyclerView.setNestedScrollingEnabled(false); + List segments = file.getPointsToDisplay(); + adapterSegments = new TrackSelectSegmentAdapter(requireContext(), segments); + adapterSegments.setAdapterListener(new GpxTrackAdapter.OnItemClickListener() { + @Override + public void onItemClick(int position) { + } + }); + recyclerView.setAdapter(adapterSegments); + + } +} From 1c8fcefcc0d5966be27365c7e1ced4e523f027fc Mon Sep 17 00:00:00 2001 From: Skalii Date: Thu, 4 Feb 2021 12:13:05 +0200 Subject: [PATCH 02/45] add bottom sheet for track recording process --- .../layout/bottom_sheet_button_with_icon.xml | 59 +++++ OsmAnd/res/layout/item_gpx_stat_block.xml | 2 + .../layout/trip_recording_active_fragment.xml | 155 +++++++++++ OsmAnd/res/values/strings.xml | 1 + .../monitoring/OsmandMonitoringPlugin.java | 4 +- .../TripRecordingActiveBottomSheet.java | 244 ++++++++++++++++++ 6 files changed, 464 insertions(+), 1 deletion(-) create mode 100644 OsmAnd/res/layout/bottom_sheet_button_with_icon.xml create mode 100644 OsmAnd/res/layout/trip_recording_active_fragment.xml create mode 100644 OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java diff --git a/OsmAnd/res/layout/bottom_sheet_button_with_icon.xml b/OsmAnd/res/layout/bottom_sheet_button_with_icon.xml new file mode 100644 index 0000000000..ba24cc289c --- /dev/null +++ b/OsmAnd/res/layout/bottom_sheet_button_with_icon.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/layout/item_gpx_stat_block.xml b/OsmAnd/res/layout/item_gpx_stat_block.xml index dd0ed2a571..f180bdb73f 100644 --- a/OsmAnd/res/layout/item_gpx_stat_block.xml +++ b/OsmAnd/res/layout/item_gpx_stat_block.xml @@ -31,6 +31,7 @@ android:layout_height="match_parent" android:layout_weight="1" android:background="@null" + android:letterSpacing="@dimen/description_letter_spacing" android:lines="1" android:textColor="?android:attr/textColorPrimary" android:textSize="@dimen/default_desc_text_size" @@ -61,6 +62,7 @@ android:layout_height="wrap_content" android:background="@null" android:ellipsize="end" + android:letterSpacing="@dimen/description_letter_spacing" android:lines="1" android:maxWidth="@dimen/grid_menu_item_width" android:textColor="?android:attr/textColorSecondary" diff --git a/OsmAnd/res/layout/trip_recording_active_fragment.xml b/OsmAnd/res/layout/trip_recording_active_fragment.xml new file mode 100644 index 0000000000..4f45d49fc9 --- /dev/null +++ b/OsmAnd/res/layout/trip_recording_active_fragment.xml @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 1d23e9db07..20294eb4e9 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -12,6 +12,7 @@ --> + On pause Hillshade / Slope / Contour lines Select edits for upload Uploaded %1$d of %2$d diff --git a/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java b/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java index 42bae2ab62..1ddb443891 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java @@ -318,7 +318,9 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { } public void controlDialog(final Activity activity, final boolean showTrackSelection) { - final boolean wasTrackMonitored = settings.SAVE_GLOBAL_TRACK_TO_GPX.get(); + FragmentActivity fragmentActivity = (FragmentActivity) activity; + TripRecordingActiveBottomSheet.showInstance(fragmentActivity.getSupportFragmentManager()); + /*final boolean wasTrackMonitored = settings.SAVE_GLOBAL_TRACK_TO_GPX.get(); final boolean nightMode; if (activity instanceof MapActivity) { nightMode = app.getDaynightHelper().isNightModeForMapControls(); diff --git a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java new file mode 100644 index 0000000000..6234d58b18 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java @@ -0,0 +1,244 @@ +package net.osmand.plus.monitoring; + +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.ColorRes; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.appcompat.content.res.AppCompatResources; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.appcompat.widget.SwitchCompat; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.FragmentManager; + +import net.osmand.plus.GpxSelectionHelper; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.UiUtilities; +import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.base.MenuBottomSheetDialogFragment; +import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription; +import net.osmand.plus.helpers.AndroidUiHelper; +import net.osmand.plus.settings.backend.OsmandSettings; +import net.osmand.plus.track.TrackAppearanceFragment; +import net.osmand.plus.widgets.TextViewEx; +import net.osmand.util.Algorithms; + +import static net.osmand.plus.UiUtilities.CompoundButtonType.PROFILE_DEPENDENT; + +public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragment { + + public static final String TAG = TripRecordingActiveBottomSheet.class.getSimpleName(); + + private OsmandApplication app; + private OsmandSettings settings; + + @Override + public void createMenuItems(Bundle savedInstanceState) { + app = requiredMyApplication(); + settings = app.getSettings(); + Context context = requireContext(); + + LayoutInflater inflater = UiUtilities.getInflater(context, nightMode); + View itemView = inflater.inflate(R.layout.trip_recording_active_fragment, null, false); + items.add(new BottomSheetItemWithDescription.Builder() + .setCustomView(itemView) + .create()); + + TextView statusTitle = itemView.findViewById(R.id.status); + statusTitle.setText(ItemType.SEARCHING_GPS.titleId); + statusTitle.setTextColor(ContextCompat.getColor(app, getSecondaryTextColorId())); + ImageView statusIcon = itemView.findViewById(R.id.icon_status); + Drawable statusDrawable = UiUtilities.tintDrawable( + AppCompatResources.getDrawable(app, ItemType.SEARCHING_GPS.iconId), + ContextCompat.getColor(app, nightMode ? R.color.icon_color_default_dark : R.color.icon_color_default_light) + ); + statusIcon.setImageDrawable(statusDrawable); + + View buttonClear = itemView.findViewById(R.id.button_clear); + View buttonStart = itemView.findViewById(R.id.button_start); + View buttonSave = itemView.findViewById(R.id.button_save); + View buttonPause = itemView.findViewById(R.id.button_pause); + View buttonStop = itemView.findViewById(R.id.button_stop); + + createButton(buttonClear, ItemType.CLEAR_DATA, true, null); + createButton(buttonStart, ItemType.START_SEGMENT, true, null); + createButton(buttonSave, ItemType.SAVE, true, "17 min. ago"); + createButton(buttonPause, ItemType.PAUSE, true, null); + createButton(buttonStop, ItemType.STOP, true, null); + + LinearLayout showTrackOnMapView = itemView.findViewById(R.id.show_track_on_map); + TextView showTrackOnMapTitle = showTrackOnMapView.findViewById(R.id.title); + showTrackOnMapTitle.setText(R.string.show_track_on_map); + + ImageView trackAppearanceIcon = showTrackOnMapView.findViewById(R.id.icon_after_divider); + + int color = settings.CURRENT_TRACK_COLOR.get(); + String width = settings.CURRENT_TRACK_WIDTH.get(); + boolean showArrows = settings.CURRENT_TRACK_SHOW_ARROWS.get(); + Drawable drawable = TrackAppearanceFragment.getTrackIcon(app, width, showArrows, color); + + trackAppearanceIcon.setImageDrawable(drawable); + trackAppearanceIcon.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + MapActivity mapActivity = getMapActivity(); + if (mapActivity != null) { + hide(); + GpxSelectionHelper.SelectedGpxFile selectedGpxFile = app.getSavingTrackHelper().getCurrentTrack(); + TrackAppearanceFragment.showInstance(mapActivity, selectedGpxFile, TripRecordingActiveBottomSheet.this); + } + } + }); + + final SwitchCompat showTrackOnMapButton = showTrackOnMapView.findViewById(R.id.switch_button); + showTrackOnMapButton.setChecked(app.getSelectedGpxHelper().getSelectedCurrentRecordingTrack() != null); + View basicItem = itemView.findViewById(R.id.basic_item_body); + basicItem.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + boolean checked = !showTrackOnMapButton.isChecked(); + showTrackOnMapButton.setChecked(checked); + app.getSelectedGpxHelper().selectGpxFile(app.getSavingTrackHelper().getCurrentGpx(), checked, false); + } + }); + UiUtilities.setupCompoundButton(showTrackOnMapButton, nightMode, PROFILE_DEPENDENT); + + } + + private void createButton(View view, ItemType type, boolean enabled, @Nullable String description) { + + Context ctx = view.getContext(); + + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { + view.setBackground(AppCompatResources.getDrawable(ctx, nightMode ? R.drawable.dlg_btn_secondary_dark : R.drawable.dlg_btn_secondary_light)); + } else { + view.setBackgroundDrawable(AppCompatResources.getDrawable(ctx, nightMode ? R.drawable.dlg_btn_secondary_dark : R.drawable.dlg_btn_secondary_light)); + } + + TextViewEx title = view.findViewById(R.id.title); + TextViewEx desc = view.findViewById(R.id.desc); + AppCompatImageView icon = view.findViewById(R.id.icon); + + title.setText(type.getTitleId()); + title.setTextColor(ContextCompat.getColor(ctx, type == ItemType.CLEAR_DATA ? R.color.color_osm_edit_delete + : enabled ? getActiveTextColorId() : getSecondaryTextColorId())); + + Drawable tintDrawable = UiUtilities.tintDrawable( + AppCompatResources.getDrawable(ctx, type.iconId), + ContextCompat.getColor(ctx, type == ItemType.CLEAR_DATA ? R.color.color_osm_edit_delete + : enabled ? getActiveIconColorId() : getSecondaryIconColorId()) + ); + icon.setBackgroundDrawable(tintDrawable); + + boolean isShowDesc = !Algorithms.isBlank(description); + int marginSingle = app.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_medium); + AndroidUiHelper.updateVisibility(desc, isShowDesc); + UiUtilities.setMargins(title, 0, isShowDesc ? 0 : marginSingle, 0, isShowDesc ? 0 : marginSingle); + desc.setText(description); + } + + enum ItemType { + SEARCHING_GPS(R.string.searching_gps, R.drawable.ic_action_gps_info), + RECORDING(R.string.recording_default_name, R.drawable.ic_action_track_recordable), + ON_PAUSE(R.string.on_pause, R.drawable.ic_pause), + CLEAR_DATA(R.string.clear_recorded_data, R.drawable.ic_action_delete_dark), + START_SEGMENT(R.string.gpx_start_new_segment, R.drawable.ic_action_new_segment), + SAVE(R.string.shared_string_save, R.drawable.ic_action_save_to_file), + PAUSE(R.string.shared_string_pause, R.drawable.ic_pause), + STOP(R.string.shared_string_control_stop, R.drawable.ic_action_rec_stop); + + @StringRes + private int titleId; + @DrawableRes + private int iconId; + + ItemType(@StringRes int titleId, @DrawableRes int iconId) { + this.titleId = titleId; + this.iconId = iconId; + } + + public int getTitleId() { + return titleId; + } + + public int getIconId() { + return iconId; + } + } + + @ColorRes + protected int getActiveTextColorId() { + return nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light; + } + + @ColorRes + protected int getSecondaryTextColorId() { + return nightMode ? R.color.text_color_secondary_dark : R.color.text_color_secondary_light; + } + + @ColorRes + protected int getActiveIconColorId() { + return nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light; + } + + @ColorRes + protected int getSecondaryIconColorId() { + return nightMode ? R.color.icon_color_secondary_dark : R.color.icon_color_secondary_light; + } + + @ColorRes + protected int getOsmandIconColorId() { + return nightMode ? R.color.icon_color_osmand_dark : R.color.icon_color_osmand_light; + } + + @Override + protected int getDismissButtonHeight() { + return getResources().getDimensionPixelSize(R.dimen.bottom_sheet_cancel_button_height); + } + + @Override + protected int getDismissButtonTextId() { + return R.string.shared_string_close; + } + + @Override + protected boolean useVerticalButtons() { + return true; + } + + @Nullable + public MapActivity getMapActivity() { + Activity activity = getActivity(); + if (activity instanceof MapActivity) { + return (MapActivity) activity; + } + return null; + } + + public void hide() { + Dialog dialog = getDialog(); + if (dialog != null) { + dialog.hide(); + } + } + + public static void showInstance(@NonNull FragmentManager fragmentManager) { + if (!fragmentManager.isStateSaved()) { + TripRecordingActiveBottomSheet fragment = new TripRecordingActiveBottomSheet(); + fragment.show(fragmentManager, TAG); + } + } +} From 06617378a0ad56d030ae3324d9b8ceca39f7d281 Mon Sep 17 00:00:00 2001 From: androiddevkotlin <64539346+androiddevkotlin@users.noreply.github.com> Date: Thu, 4 Feb 2021 15:03:41 +0200 Subject: [PATCH 03/45] Segment navigation --- .../layout/bottom_sheet_select_segment.xml | 88 ++++++++++--------- OsmAnd/res/layout/gpx_segment_list_item.xml | 4 +- .../FollowTrackFragment.java | 15 +++- .../track/TrackSelectSegmentBottomSheet.java | 49 +++++++++-- 4 files changed, 104 insertions(+), 52 deletions(-) diff --git a/OsmAnd/res/layout/bottom_sheet_select_segment.xml b/OsmAnd/res/layout/bottom_sheet_select_segment.xml index de758bc182..427d0d93a8 100644 --- a/OsmAnd/res/layout/bottom_sheet_select_segment.xml +++ b/OsmAnd/res/layout/bottom_sheet_select_segment.xml @@ -5,51 +5,58 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="@dimen/bottom_sheet_selected_item_title_height" - android:orientation="vertical" - android:paddingStart="@dimen/content_padding" - android:paddingLeft="@dimen/content_padding" - android:paddingTop="@dimen/measurement_tool_menu_title_padding_top" - android:paddingEnd="@dimen/content_padding" - android:paddingRight="@dimen/content_padding" - android:paddingBottom="@dimen/content_padding_small"> + android:orientation="vertical"> - + android:orientation="vertical" + android:paddingStart="@dimen/content_padding" + android:paddingLeft="@dimen/content_padding" + android:paddingTop="@dimen/measurement_tool_menu_title_padding_top" + android:paddingEnd="@dimen/content_padding" + android:paddingRight="@dimen/content_padding" + android:paddingBottom="@dimen/content_padding_small"> - + - + + + + - \ No newline at end of file diff --git a/OsmAnd/res/layout/gpx_segment_list_item.xml b/OsmAnd/res/layout/gpx_segment_list_item.xml index f591d86e50..8266775053 100644 --- a/OsmAnd/res/layout/gpx_segment_list_item.xml +++ b/OsmAnd/res/layout/gpx_segment_list_item.xml @@ -6,6 +6,8 @@ android:layout_height="wrap_content" android:background="?attr/selectableItemBackground" android:minHeight="@dimen/favorites_list_item_height" + android:paddingTop="@dimen/list_header_settings_top_margin" + android:paddingBottom="@dimen/list_header_settings_top_margin" android:orientation="horizontal"> + osmand:srcCompat="@drawable/ic_action_distance_16" /> 1; String fileName = null; File file = null; if (!Algorithms.isEmpty(gpxFile.path)) { file = new File(gpxFile.path); - fileName = file.getName(); + if (isTrackContainsMultiSegment) { + fileName = Algorithms.getFileNameWithoutExtension(file.getName()); + } else { + fileName = Algorithms.getFileNameWithoutExtension(file.getName()); + } } else if (!Algorithms.isEmpty(gpxFile.tracks)) { fileName = gpxFile.tracks.get(0).name; } @@ -489,9 +494,12 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca GPXInfo gpxInfo = card.getGpxInfoList().get(index); String fileName = gpxInfo.getFileName(); SelectedGpxFile selectedGpxFile = app.getSelectedGpxHelper().getSelectedFileByName(fileName); - if (selectedGpxFile != null) { + boolean isTrackContainsMultiSegment = selectedGpxFile.getGpxFile().getNonEmptySegmentsCount() > 1; + if (selectedGpxFile != null && !isTrackContainsMultiSegment) { selectTrackToFollow(selectedGpxFile.getGpxFile()); updateSelectionMode(false); + } else if (selectedGpxFile != null && isTrackContainsMultiSegment) { + TrackSelectSegmentBottomSheet.showInstance(getFragmentManager(), selectedGpxFile); } else { CallbackWithObject callback = new CallbackWithObject() { @Override @@ -702,6 +710,7 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca } } + @Override public void routeWasCancelled() { diff --git a/OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java b/OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java index 199e30c1cd..03065539e8 100644 --- a/OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java @@ -1,7 +1,11 @@ package net.osmand.plus.track; import android.content.Context; +import android.graphics.Typeface; import android.os.Bundle; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.style.ForegroundColorSpan; import android.view.LayoutInflater; import android.view.View; @@ -10,15 +14,19 @@ import androidx.fragment.app.FragmentManager; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import net.osmand.GPXUtilities; import net.osmand.GPXUtilities.TrkSegment; import net.osmand.plus.GpxSelectionHelper; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; +import net.osmand.plus.activities.MapActivity; import net.osmand.plus.base.MenuBottomSheetDialogFragment; import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription; +import net.osmand.plus.helpers.FontCache; import net.osmand.plus.helpers.GpxTrackAdapter; import net.osmand.plus.helpers.TrackSelectSegmentAdapter; +import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.widgets.TextViewEx; import net.osmand.util.Algorithms; @@ -44,31 +52,58 @@ public class TrackSelectSegmentBottomSheet extends MenuBottomSheetDialogFragment LayoutInflater inflater = UiUtilities.getInflater(context, nightMode); View itemView = inflater.inflate(R.layout.bottom_sheet_select_segment, null, false); - String titleGpxTrack = Algorithms.getFileWithoutDirs(file.getGpxFile().path); - - items.add(new BottomSheetItemWithDescription.Builder() - .setDescription(getString(R.string.select_segments_description, titleGpxTrack)) - .setCustomView(itemView) - .create()); OsmandApplication app = getMyApplication(); if (app == null) { return; } + + String titleGpxTrack = Algorithms.getFileWithoutDirs(file.getGpxFile().path); + Typeface typeface = FontCache.getRobotoMedium(app); + SpannableString spannable = UiUtilities.createCustomFontSpannable(typeface, titleGpxTrack, titleGpxTrack, titleGpxTrack); + int descriptionColor = getResolvedColor(nightMode ? R.color.text_color_secondary_dark : R.color.text_color_secondary_light); + ForegroundColorSpan colorSpan = new ForegroundColorSpan(descriptionColor); + spannable.setSpan(colorSpan, 0, titleGpxTrack.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + items.add(new BottomSheetItemWithDescription.Builder() + .setDescription(getString(R.string.select_segments_description, spannable)) + .setCustomView(itemView) + .create()); + TextViewEx titleGpxTrackView = itemView.findViewById(R.id.title_gpx_track); titleGpxTrackView.setText(titleGpxTrack); final RecyclerView recyclerView = itemView.findViewById(R.id.gpx_segment_list); recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); recyclerView.setNestedScrollingEnabled(false); - List segments = file.getPointsToDisplay(); + final List segments = file.getPointsToDisplay(); adapterSegments = new TrackSelectSegmentAdapter(requireContext(), segments); adapterSegments.setAdapterListener(new GpxTrackAdapter.OnItemClickListener() { @Override public void onItemClick(int position) { + selectSegmentToFollow(segments.get(position), file); + dismiss(); } }); recyclerView.setAdapter(adapterSegments); } + + private void selectSegmentToFollow(TrkSegment segment, GpxSelectionHelper.SelectedGpxFile file) { + MapActivity mapActivity = (MapActivity) getActivity(); + if (mapActivity != null) { + List points = segment.points; + if (!points.isEmpty()) { + ApplicationMode mode = ApplicationMode.valueOfStringKey(points.get(0).getProfileType(), null); + if (mode != null) { + getMyApplication().getRoutingHelper().setAppMode(mode); + getMyApplication().initVoiceCommandPlayer(mapActivity, mode, true, null, false, false, true); + } + } + mapActivity.getMapActions().setGPXRouteParams(file.getGpxFile()); + getMyApplication().getTargetPointsHelper().updateRouteAndRefresh(true); + getMyApplication().getRoutingHelper().onSettingsChanged(true); + } + } } + From 5605e33c3238941e798da548fad99886d61648bd Mon Sep 17 00:00:00 2001 From: cepprice Date: Fri, 5 Feb 2021 19:31:57 +0500 Subject: [PATCH 04/45] Add bottom sheet dialogs to clear recoderd data and stop trip recording --- .../bottom_sheet_item_button_with_icon.xml | 69 +++++++ OsmAnd/res/values/sizes.xml | 2 + OsmAnd/res/values/strings.xml | 4 + .../ClearRecordedDataBottomSheetFragment.java | 160 +++++++++++++++ .../StopTrackRecordingBottomFragment.java | 187 ++++++++++++++++++ 5 files changed, 422 insertions(+) create mode 100644 OsmAnd/res/layout/bottom_sheet_item_button_with_icon.xml create mode 100644 OsmAnd/src/net/osmand/plus/monitoring/ClearRecordedDataBottomSheetFragment.java create mode 100644 OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java diff --git a/OsmAnd/res/layout/bottom_sheet_item_button_with_icon.xml b/OsmAnd/res/layout/bottom_sheet_item_button_with_icon.xml new file mode 100644 index 0000000000..9b2b395ccb --- /dev/null +++ b/OsmAnd/res/layout/bottom_sheet_item_button_with_icon.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/values/sizes.xml b/OsmAnd/res/values/sizes.xml index a086849297..afdc8438af 100644 --- a/OsmAnd/res/values/sizes.xml +++ b/OsmAnd/res/values/sizes.xml @@ -413,4 +413,6 @@ 32dp 24dp + + 0dp \ No newline at end of file diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index a15fb40cbd..905a947661 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -12,6 +12,10 @@ --> + Are you sure you want to stop recording?\nAll unsaved data will be lost. + Track recording stopped + Save and stop recording + Stop without saving Login to OpenPlaceReviews Use test.openplacereviews.org OpenPlaceReviews diff --git a/OsmAnd/src/net/osmand/plus/monitoring/ClearRecordedDataBottomSheetFragment.java b/OsmAnd/src/net/osmand/plus/monitoring/ClearRecordedDataBottomSheetFragment.java new file mode 100644 index 0000000000..971bfd01e0 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/monitoring/ClearRecordedDataBottomSheetFragment.java @@ -0,0 +1,160 @@ +package net.osmand.plus.monitoring; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; + +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.BaseBottomSheetItem; +import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription; +import net.osmand.plus.widgets.TextViewEx; + +import androidx.annotation.DimenRes; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; + +public class ClearRecordedDataBottomSheetFragment extends MenuBottomSheetDialogFragment implements View.OnClickListener { + + public static final String TAG = ClearRecordedDataBottomSheetFragment.class.getSimpleName(); + + private OsmandApplication app; + + @Override + public void createMenuItems(Bundle savedInstanceState) { + app = requiredMyApplication(); + + items.add(new BottomSheetItemWithDescription.Builder() + .setDescription(app.getString(R.string.clear_recorded_data_warning)) + .setDescriptionColorId(!nightMode ? R.color.text_color_primary_light : R.color.text_color_primary_dark) + .setDescriptionMaxLines(2) + .setTitle(app.getString(R.string.clear_recorded_data)) + .setLayoutId(R.layout.bottom_sheet_item_title_with_description) + .create()); + + LayoutInflater inflater = UiUtilities.getInflater(getContext(), nightMode); + + items.add(new BaseBottomSheetItem.Builder() + .setCustomView(setupBtn(inflater, ButtonType.CLEAR)) + .setOnClickListener(this) + .create()); + + items.add(new BaseBottomSheetItem.Builder() + .setCustomView(setupBtn(inflater, ButtonType.CANCEL)) + .setOnClickListener(this) + .create()); + + } + + private View setupBtn(LayoutInflater inflater, ButtonType type) { + View button = inflater.inflate(R.layout.bottom_sheet_item_button_with_icon, null); + button.setTag(type); + Context context = button.getContext(); + + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); + int horizontal = context.getResources().getDimensionPixelSize(R.dimen.content_padding); + int top = context.getResources().getDimensionPixelSize(type.topMarginRes); + int bottom = context.getResources().getDimensionPixelSize(R.dimen.content_padding_small); + params.setMargins(horizontal, top, horizontal, bottom); + button.setLayoutParams(params); + + UiUtilities.setupDialogButton(nightMode, button, type.effect, type.titleId); + + TextViewEx title = button.findViewById(R.id.button_text); + int margin = context.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_medium); + UiUtilities.setMargins(title, 0, margin, 0, margin); + + int colorRes; + if (type.effect == UiUtilities.DialogButtonType.SECONDARY_HARMFUL) { + colorRes = R.color.color_osm_edit_delete; + } else { + colorRes = nightMode ? R.color.dlg_btn_secondary_text_dark : R.color.dlg_btn_secondary_text_light; + } + AppCompatImageView icon = button.findViewById(R.id.icon); + icon.setImageDrawable(getIcon(type.iconRes, colorRes)); + + return button; + } + + @Override + public void onClick(View v) { + Object o = v.getTag(); + if (!(o instanceof ButtonType)) { + return; + } + + ButtonType tag = (ButtonType) o; + if (tag == ButtonType.CLEAR) { + app.getSavingTrackHelper().clearRecordedData(true); + } + dismiss(); + } + + @Override + public void onResume() { + super.onResume(); + // Replace later with tTripRecordingActiveBottomSheet.hide() + Fragment target = getTargetFragment(); + if (target instanceof TripRecordingActiveBottomSheet) { + Dialog dialog = ((TripRecordingActiveBottomSheet) target).getDialog(); + if (dialog != null) { + dialog.hide(); + } + } + } + + @Override + public void onPause() { + super.onPause(); + // Replace later with tTripRecordingActiveBottomSheet.show() + Fragment target = getTargetFragment(); + if (target instanceof TripRecordingActiveBottomSheet) { + Dialog dialog = ((TripRecordingActiveBottomSheet) target).getDialog(); + if (dialog != null) { + dialog.show(); + } + } + } + + enum ButtonType { + CLEAR(R.string.clear_recorded_data, R.drawable.ic_action_delete_dark, R.dimen.dialog_content_margin, UiUtilities.DialogButtonType.SECONDARY_HARMFUL), + CANCEL(R.string.shared_string_cancel, R.drawable.ic_action_close, R.dimen.content_padding_small, UiUtilities.DialogButtonType.SECONDARY); + + @StringRes + private final int titleId; + @DrawableRes + private final int iconRes; + @DimenRes + private final int topMarginRes; + private final UiUtilities.DialogButtonType effect; + + ButtonType(int titleId, int iconRes, int topMarginRes, UiUtilities.DialogButtonType effect) { + this.titleId = titleId; + this.iconRes = iconRes; + this.topMarginRes = topMarginRes; + this.effect = effect; + } + } + + @Override + protected boolean hideButtonsContainer() { + return true; + } + + public static void showInstance(@NonNull FragmentManager fragmentManager, @NonNull Fragment target) { + if (!fragmentManager.isStateSaved()) { + ClearRecordedDataBottomSheetFragment fragment = new ClearRecordedDataBottomSheetFragment(); + fragment.setTargetFragment(target, 0); + fragment.show(fragmentManager, TAG); + } + } +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java b/OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java new file mode 100644 index 0000000000..b7bf829457 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java @@ -0,0 +1,187 @@ +package net.osmand.plus.monitoring; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; + +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.OsmandPlugin; +import net.osmand.plus.R; +import net.osmand.plus.UiUtilities; +import net.osmand.plus.UiUtilities.DialogButtonType; +import net.osmand.plus.base.MenuBottomSheetDialogFragment; +import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem; +import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription; +import net.osmand.plus.settings.backend.OsmandSettings; +import net.osmand.plus.widgets.TextViewEx; + +import androidx.annotation.DimenRes; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; + +public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragment implements View.OnClickListener { + + public static final String TAG = StopTrackRecordingBottomFragment.class.getSimpleName(); + + private OsmandApplication app; + private OsmandSettings settings; + private OsmandMonitoringPlugin plugin; + + @Override + public void createMenuItems(Bundle savedInstanceState) { + app = requiredMyApplication(); + settings = app.getSettings(); + plugin = OsmandPlugin.getPlugin(OsmandMonitoringPlugin.class); + + items.add(new BottomSheetItemWithDescription.Builder() + .setDescription(app.getString(R.string.track_recording_description)) + .setDescriptionColorId(!nightMode ? R.color.text_color_primary_light : R.color.text_color_primary_dark) + .setDescriptionMaxLines(4) + .setTitle(app.getString(R.string.track_recording_title)) + .setLayoutId(R.layout.bottom_sheet_item_title_with_description) + .create()); + + LayoutInflater inflater = UiUtilities.getInflater(getContext(), nightMode); + + items.add(new BaseBottomSheetItem.Builder() + .setCustomView(setupButton(inflater, ButtonType.STOP_AND_DISCARD)) + .setOnClickListener(this) + .create()); + + items.add(new BaseBottomSheetItem.Builder() + .setCustomView(setupButton(inflater, ButtonType.SAVE_AND_STOP)) + .setOnClickListener(this) + .create()); + + items.add(new BaseBottomSheetItem.Builder() + .setCustomView(setupButton(inflater, ButtonType.CANCEL)) + .setOnClickListener(this) + .create()); + } + + private View setupButton(LayoutInflater inflater, ButtonType type) { + View button = inflater.inflate(R.layout.bottom_sheet_item_button_with_icon, null); + button.setTag(type); + Context context = button.getContext(); + + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); + int horizontal = context.getResources().getDimensionPixelSize(R.dimen.content_padding); + int top = context.getResources().getDimensionPixelSize(type.topMarginRes); + int bottom = context.getResources().getDimensionPixelSize(R.dimen.content_padding_small); + params.setMargins(horizontal, top, horizontal, bottom); + button.setLayoutParams(params); + + UiUtilities.setupDialogButton(nightMode, button, type.effect, type.titleId); + + TextViewEx title = button.findViewById(R.id.button_text); + int margin = context.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_medium); + UiUtilities.setMargins(title, 0, margin, 0, margin); + + int colorRes; + if (type.effect == DialogButtonType.SECONDARY_HARMFUL) { + colorRes = R.color.color_osm_edit_delete; + } else { + colorRes = nightMode ? R.color.dlg_btn_secondary_text_dark : R.color.dlg_btn_secondary_text_light; + } + AppCompatImageView icon = button.findViewById(R.id.icon); + icon.setImageDrawable(getIcon(type.iconRes, colorRes)); + + if (type == ButtonType.STOP_AND_DISCARD) { + int size = context.getResources().getDimensionPixelSize(R.dimen.map_widget_height); + LinearLayout.LayoutParams iconParams = new LinearLayout.LayoutParams(size, size); + icon.setLayoutParams(iconParams); + } + + return button; + } + + @Override + public void onClick(View v) { + Object o = v.getTag(); + if (!(o instanceof ButtonType)) { + return; + } + + ButtonType tag = (ButtonType) o; + if (tag == ButtonType.STOP_AND_DISCARD) { + if (plugin != null && settings.SAVE_GLOBAL_TRACK_TO_GPX.get()) { + plugin.stopRecording(); + app.getNotificationHelper().refreshNotifications(); + } + app.getSavingTrackHelper().clearRecordedData(true); + } else if (tag == ButtonType.SAVE_AND_STOP) { + if (plugin != null && settings.SAVE_GLOBAL_TRACK_TO_GPX.get()) { + plugin.saveCurrentTrack(); + app.getNotificationHelper().refreshNotifications(); + } + } + dismiss(); + } + + @Override + public void onResume() { + super.onResume(); + // Replace later with tTripRecordingActiveBottomSheet.hide() + Fragment target = getTargetFragment(); + if (target instanceof TripRecordingActiveBottomSheet) { + Dialog dialog = ((TripRecordingActiveBottomSheet) target).getDialog(); + if (dialog != null) { + dialog.hide(); + } + } + } + + @Override + public void onPause() { + super.onPause(); + // Replace later with tTripRecordingActiveBottomSheet.show() + Fragment target = getTargetFragment(); + if (target instanceof TripRecordingActiveBottomSheet) { + Dialog dialog = ((TripRecordingActiveBottomSheet) target).getDialog(); + if (dialog != null) { + dialog.show(); + } + } + } + + enum ButtonType { + STOP_AND_DISCARD(R.string.track_recording_stop_without_saving, R.drawable.ic_action_rec_stop, R.dimen.dialog_content_margin, DialogButtonType.SECONDARY_HARMFUL), + SAVE_AND_STOP(R.string.track_recording_save_and_stop, R.drawable.ic_action_save_to_file, R.dimen.content_padding_small, DialogButtonType.SECONDARY), + CANCEL(R.string.shared_string_cancel, R.drawable.ic_action_close, R.dimen.zero, DialogButtonType.SECONDARY); + + @StringRes + private final int titleId; + @DrawableRes + private final int iconRes; + @DimenRes + private final int topMarginRes; + private final DialogButtonType effect; + + ButtonType(int titleId, int iconRes, int topMarginRes, DialogButtonType type) { + this.titleId = titleId; + this.iconRes = iconRes; + this.topMarginRes = topMarginRes; + this.effect = type; + } + } + + @Override + protected boolean hideButtonsContainer() { + return true; + } + + public static void showInstance(@NonNull FragmentManager fragmentManager, @NonNull Fragment target) { + if (!fragmentManager.isStateSaved()) { + StopTrackRecordingBottomFragment fragment = new StopTrackRecordingBottomFragment(); + fragment.setTargetFragment(target, 0); + fragment.show(fragmentManager, TAG); + } + } +} From 3f2e78671ffce8fce61ca83ece70537ad4d7cebc Mon Sep 17 00:00:00 2001 From: androiddevkotlin <64539346+androiddevkotlin@users.noreply.github.com> Date: Sun, 7 Feb 2021 11:38:59 +0200 Subject: [PATCH 05/45] Spannable string description, null check --- .../FollowTrackFragment.java | 15 ++++++----- .../track/TrackSelectSegmentBottomSheet.java | 26 ++++++++++++------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/FollowTrackFragment.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/FollowTrackFragment.java index e36cfcde15..b4bd04037e 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/FollowTrackFragment.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/FollowTrackFragment.java @@ -494,12 +494,15 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca GPXInfo gpxInfo = card.getGpxInfoList().get(index); String fileName = gpxInfo.getFileName(); SelectedGpxFile selectedGpxFile = app.getSelectedGpxHelper().getSelectedFileByName(fileName); - boolean isTrackContainsMultiSegment = selectedGpxFile.getGpxFile().getNonEmptySegmentsCount() > 1; - if (selectedGpxFile != null && !isTrackContainsMultiSegment) { - selectTrackToFollow(selectedGpxFile.getGpxFile()); - updateSelectionMode(false); - } else if (selectedGpxFile != null && isTrackContainsMultiSegment) { - TrackSelectSegmentBottomSheet.showInstance(getFragmentManager(), selectedGpxFile); + FragmentManager fragmentManager = getFragmentManager(); + if (selectedGpxFile != null && fragmentManager != null) { + boolean isTrackContainsMultiSegment = selectedGpxFile.getGpxFile().getNonEmptySegmentsCount() > 1; + if (!isTrackContainsMultiSegment) { + selectTrackToFollow(selectedGpxFile.getGpxFile()); + updateSelectionMode(false); + } else { + TrackSelectSegmentBottomSheet.showInstance(fragmentManager, selectedGpxFile); + } } else { CallbackWithObject callback = new CallbackWithObject() { @Override diff --git a/OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java b/OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java index 03065539e8..da9c729d84 100644 --- a/OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java @@ -3,8 +3,8 @@ package net.osmand.plus.track; import android.content.Context; import android.graphics.Typeface; import android.os.Bundle; +import android.text.Spannable; import android.text.SpannableString; -import android.text.Spanned; import android.text.style.ForegroundColorSpan; import android.view.LayoutInflater; import android.view.View; @@ -19,6 +19,7 @@ import net.osmand.GPXUtilities.TrkSegment; import net.osmand.plus.GpxSelectionHelper; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; +import net.osmand.plus.TargetPointsHelper; import net.osmand.plus.UiUtilities; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.base.MenuBottomSheetDialogFragment; @@ -26,8 +27,10 @@ import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription; import net.osmand.plus.helpers.FontCache; import net.osmand.plus.helpers.GpxTrackAdapter; import net.osmand.plus.helpers.TrackSelectSegmentAdapter; +import net.osmand.plus.routing.RoutingHelper; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.widgets.TextViewEx; +import net.osmand.plus.widgets.style.CustomTypefaceSpan; import net.osmand.util.Algorithms; import java.util.List; @@ -60,13 +63,16 @@ public class TrackSelectSegmentBottomSheet extends MenuBottomSheetDialogFragment String titleGpxTrack = Algorithms.getFileWithoutDirs(file.getGpxFile().path); Typeface typeface = FontCache.getRobotoMedium(app); - SpannableString spannable = UiUtilities.createCustomFontSpannable(typeface, titleGpxTrack, titleGpxTrack, titleGpxTrack); + String selectSegmentDescription = getString(R.string.select_segments_description, titleGpxTrack); + SpannableString gpxTrackName = new SpannableString(selectSegmentDescription); + int startIndex = selectSegmentDescription.indexOf(titleGpxTrack); int descriptionColor = getResolvedColor(nightMode ? R.color.text_color_secondary_dark : R.color.text_color_secondary_light); - ForegroundColorSpan colorSpan = new ForegroundColorSpan(descriptionColor); - spannable.setSpan(colorSpan, 0, titleGpxTrack.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + int endIndex = startIndex + titleGpxTrack.length(); + gpxTrackName.setSpan(new CustomTypefaceSpan(typeface), startIndex, endIndex, 0); + gpxTrackName.setSpan(new ForegroundColorSpan(descriptionColor), startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); items.add(new BottomSheetItemWithDescription.Builder() - .setDescription(getString(R.string.select_segments_description, spannable)) + .setDescription(gpxTrackName) .setCustomView(itemView) .create()); @@ -92,17 +98,19 @@ public class TrackSelectSegmentBottomSheet extends MenuBottomSheetDialogFragment private void selectSegmentToFollow(TrkSegment segment, GpxSelectionHelper.SelectedGpxFile file) { MapActivity mapActivity = (MapActivity) getActivity(); if (mapActivity != null) { + TargetPointsHelper targetPointsHelper = mapActivity.getMyApplication().getTargetPointsHelper(); + RoutingHelper routingHelper = mapActivity.getMyApplication().getRoutingHelper(); List points = segment.points; if (!points.isEmpty()) { ApplicationMode mode = ApplicationMode.valueOfStringKey(points.get(0).getProfileType(), null); if (mode != null) { - getMyApplication().getRoutingHelper().setAppMode(mode); - getMyApplication().initVoiceCommandPlayer(mapActivity, mode, true, null, false, false, true); + routingHelper.setAppMode(mode); + mapActivity.getMyApplication().initVoiceCommandPlayer(mapActivity, mode, true, null, false, false, true); } } mapActivity.getMapActions().setGPXRouteParams(file.getGpxFile()); - getMyApplication().getTargetPointsHelper().updateRouteAndRefresh(true); - getMyApplication().getRoutingHelper().onSettingsChanged(true); + targetPointsHelper.updateRouteAndRefresh(true); + routingHelper.onSettingsChanged(true); } } } From 3b0b49ae1b12b7b08613b173f4296f056110de02 Mon Sep 17 00:00:00 2001 From: androiddevkotlin <64539346+androiddevkotlin@users.noreply.github.com> Date: Mon, 8 Feb 2021 02:35:54 +0200 Subject: [PATCH 06/45] First part integration --- .../aidlapi/OsmAndCustomizationConstants.java | 1 + .../bottom_sheet_item_button_with_icon.xml | 3 +- OsmAnd/res/values/strings.xml | 2 +- .../plus/activities/MapActivityActions.java | 20 +++ .../monitoring/OsmandMonitoringPlugin.java | 13 +- .../TripRecordingActiveBottomSheet.java | 151 +++++++++++++----- 6 files changed, 144 insertions(+), 46 deletions(-) diff --git a/OsmAnd-api/src/net/osmand/aidlapi/OsmAndCustomizationConstants.java b/OsmAnd-api/src/net/osmand/aidlapi/OsmAndCustomizationConstants.java index af48552bc4..53e838a9a7 100644 --- a/OsmAnd-api/src/net/osmand/aidlapi/OsmAndCustomizationConstants.java +++ b/OsmAnd-api/src/net/osmand/aidlapi/OsmAndCustomizationConstants.java @@ -11,6 +11,7 @@ public interface OsmAndCustomizationConstants { String DRAWER_MY_PLACES_ID = DRAWER_ITEM_ID_SCHEME + "my_places"; String DRAWER_SEARCH_ID = DRAWER_ITEM_ID_SCHEME + "search"; String DRAWER_DIRECTIONS_ID = DRAWER_ITEM_ID_SCHEME + "directions"; + String DRAWER_TRIP_RECORDING_ID = DRAWER_ITEM_ID_SCHEME + "trip_recording"; String DRAWER_CONFIGURE_MAP_ID = DRAWER_ITEM_ID_SCHEME + "configure_map"; String DRAWER_DOWNLOAD_MAPS_ID = DRAWER_ITEM_ID_SCHEME + "download_maps"; String DRAWER_OSMAND_LIVE_ID = DRAWER_ITEM_ID_SCHEME + "osmand_live"; diff --git a/OsmAnd/res/layout/bottom_sheet_item_button_with_icon.xml b/OsmAnd/res/layout/bottom_sheet_item_button_with_icon.xml index 9b2b395ccb..3d2d1bbab1 100644 --- a/OsmAnd/res/layout/bottom_sheet_item_button_with_icon.xml +++ b/OsmAnd/res/layout/bottom_sheet_item_button_with_icon.xml @@ -34,7 +34,6 @@ android:layout_height="wrap_content" android:duplicateParentState="true" android:textSize="@dimen/default_desc_text_size" - osmand:letterSpacing="@dimen/description_letter_spacing" osmand:typeface="@string/font_roboto_medium" tools:text="Title" tools:textColor="@color/text_color_secondary_light" /> @@ -47,7 +46,7 @@ android:textColor="@color/text_color_secondary_light" android:textSize="@dimen/default_desc_text_size" android:visibility="gone" - osmand:letterSpacing="@dimen/description_letter_spacing" + android:letterSpacing="@dimen/description_letter_spacing" osmand:typeface="@string/font_roboto_medium" tools:text="Description" tools:visibility="visible" /> diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 905a947661..b2a92f75c2 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -11,7 +11,7 @@ Thx - Hardy --> - + On pause Are you sure you want to stop recording?\nAll unsaved data will be lost. Track recording stopped Save and stop recording diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java index 258ed7be38..625396e5e3 100644 --- a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java +++ b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java @@ -22,6 +22,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.core.content.ContextCompat; +import androidx.fragment.app.FragmentActivity; import net.osmand.AndroidUtils; import net.osmand.GPXUtilities; @@ -62,6 +63,8 @@ import net.osmand.plus.mapmarkers.MarkersPlanRouteContext; import net.osmand.plus.measurementtool.MeasurementToolFragment; import net.osmand.plus.measurementtool.StartPlanRouteBottomSheet; import net.osmand.plus.monitoring.OsmandMonitoringPlugin; +import net.osmand.plus.monitoring.TripRecordingActiveBottomSheet; +import net.osmand.plus.monitoring.TripRecordingBottomSheet; import net.osmand.plus.osmedit.dialogs.DismissRouteBottomSheetFragment; import net.osmand.plus.profiles.ProfileDataObject; import net.osmand.plus.profiles.ProfileDataUtils; @@ -98,6 +101,7 @@ import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_CONFIGURE_P import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_CONFIGURE_SCREEN_ID; import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_DASHBOARD_ID; import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_DIRECTIONS_ID; +import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_TRIP_RECORDING_ID; import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_DIVIDER_ID; import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_DOWNLOAD_MAPS_ID; import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_HELP_ID; @@ -839,6 +843,22 @@ public class MapActivityActions implements DialogProvider { } }).createItem()); + boolean isTripRecordingPluginOn = OsmandPlugin.getEnabledPlugin(OsmandMonitoringPlugin.class) != null; + if (isTripRecordingPluginOn) { + optionsMenuHelper.addItem(new ItemBuilder().setTitleId(R.string.map_widget_monitoring, mapActivity) + .setId(DRAWER_TRIP_RECORDING_ID) + .setIcon(R.drawable.ic_action_track_recordable) + .setListener(new ItemClickListener() { + @Override + public boolean onContextMenuClick(ArrayAdapter adapter, int itemId, int pos, boolean isChecked, int[] viewCoordinates) { + app.logEvent("trip_recording_open"); + MapActivity.clearPrevActivityIntent(); + TripRecordingBottomSheet.showInstance(mapActivity.getSupportFragmentManager()); + return true; + } + }).createItem()); + } + optionsMenuHelper.addItem(new ItemBuilder().setTitleId(R.string.get_directions, mapActivity) .setId(DRAWER_DIRECTIONS_ID) diff --git a/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java b/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java index 1ddb443891..65538733b0 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java @@ -43,6 +43,7 @@ import net.osmand.plus.dashboard.tools.DashFragmentData; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.settings.fragments.BaseSettingsFragment.SettingsScreenType; +import net.osmand.plus.track.TrackDisplayHelper; import net.osmand.plus.views.OsmandMapLayer.DrawSettings; import net.osmand.plus.views.OsmandMapTileView; import net.osmand.plus.views.layers.MapInfoLayer; @@ -318,9 +319,7 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { } public void controlDialog(final Activity activity, final boolean showTrackSelection) { - FragmentActivity fragmentActivity = (FragmentActivity) activity; - TripRecordingActiveBottomSheet.showInstance(fragmentActivity.getSupportFragmentManager()); - /*final boolean wasTrackMonitored = settings.SAVE_GLOBAL_TRACK_TO_GPX.get(); + final boolean wasTrackMonitored = settings.SAVE_GLOBAL_TRACK_TO_GPX.get(); final boolean nightMode; if (activity instanceof MapActivity) { nightMode = app.getDaynightHelper().isNightModeForMapControls(); @@ -329,6 +328,8 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { } AlertDialog.Builder bld = new AlertDialog.Builder(UiUtilities.getThemedContext(activity, nightMode)); final TIntArrayList items = new TIntArrayList(); + FragmentActivity fragmentActivity = (FragmentActivity) activity; + TripRecordingActiveBottomSheet.showInstance(fragmentActivity.getSupportFragmentManager()); if (wasTrackMonitored) { items.add(R.string.gpx_monitoring_stop); items.add(R.string.gpx_start_new_segment); @@ -417,7 +418,7 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { run.run(); } }); - bld.show(); +// bld.show(); } } @@ -538,7 +539,7 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { } public static LinearLayout createIntervalChooseLayout(final OsmandApplication app, - final Context uiCtx, + final Context uiCtx, final String patternMsg, final int[] seconds, final int[] minutes, final ValueHolder choice, final ValueHolder v, @@ -598,7 +599,7 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { } } } - + ll.setOrientation(LinearLayout.VERTICAL); ll.addView(tv); ll.addView(sliderContainer); diff --git a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java index 6234d58b18..3e3fad8b75 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java @@ -4,8 +4,10 @@ import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.graphics.drawable.Drawable; +import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; +import android.text.format.DateUtils; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; @@ -21,34 +23,84 @@ import androidx.appcompat.content.res.AppCompatResources; import androidx.appcompat.widget.AppCompatImageView; import androidx.appcompat.widget.SwitchCompat; import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; +import com.google.android.material.snackbar.Snackbar; + +import net.osmand.GPXUtilities; import net.osmand.plus.GpxSelectionHelper; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.activities.SavingTrackHelper; import net.osmand.plus.base.MenuBottomSheetDialogFragment; import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription; import net.osmand.plus.helpers.AndroidUiHelper; +import net.osmand.plus.myplaces.SaveCurrentTrackTask; import net.osmand.plus.settings.backend.OsmandSettings; +import net.osmand.plus.track.SaveGpxAsyncTask; import net.osmand.plus.track.TrackAppearanceFragment; import net.osmand.plus.widgets.TextViewEx; import net.osmand.util.Algorithms; +import java.lang.ref.WeakReference; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.TimeZone; + import static net.osmand.plus.UiUtilities.CompoundButtonType.PROFILE_DEPENDENT; public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragment { public static final String TAG = TripRecordingActiveBottomSheet.class.getSimpleName(); - private OsmandApplication app; - private OsmandSettings settings; + SaveGpxAsyncTask.SaveGpxListener saveGpxListener = new SaveGpxAsyncTask.SaveGpxListener() { + + @Override + public void gpxSavingStarted() { + + } + + @Override + public void gpxSavingFinished(Exception errorMessage) { + String gpxFileName = Algorithms.getFileWithoutDirs(app.getSavingTrackHelper().getCurrentTrack().getGpxFile().path); + final MapActivity mapActivity = getMapActivity(); + SavingTrackHelper helper = app.getSavingTrackHelper(); + final SavingTrackHelper.SaveGpxResult result = helper.saveDataToGpx(app.getAppCustomization().getTracksDir()); + if (mapActivity != null) { + Snackbar snackbar = Snackbar.make(mapActivity.getLayout(), + getString(R.string.shared_string_file_is_saved, gpxFileName), + Snackbar.LENGTH_LONG) + .setAction(R.string.shared_string_undo, new View.OnClickListener() { + @Override + public void onClick(View view) { + final WeakReference mapActivityRef = new WeakReference<>(mapActivity); + final FragmentActivity fragmentActivity = mapActivityRef.get(); + SaveGPXBottomSheetFragment.showInstance(fragmentActivity.getSupportFragmentManager(), result.getFilenames()); + } + }); + UiUtilities.setupSnackbar(snackbar, nightMode); + snackbar.show(); + dismiss(); + } + } + + }; + + public static void showInstance(@NonNull FragmentManager fragmentManager) { + if (!fragmentManager.isStateSaved()) { + TripRecordingActiveBottomSheet fragment = new TripRecordingActiveBottomSheet(); + fragment.show(fragmentManager, TAG); + } + } @Override public void createMenuItems(Bundle savedInstanceState) { app = requiredMyApplication(); - settings = app.getSettings(); + OsmandSettings settings = app.getSettings(); Context context = requireContext(); LayoutInflater inflater = UiUtilities.getInflater(context, nightMode); @@ -67,6 +119,19 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen ); statusIcon.setImageDrawable(statusDrawable); + String timeTrackSaved = String.valueOf(app.getSavingTrackHelper().getLastTimeUpdated()); + SimpleDateFormat sdf = new SimpleDateFormat("MMM dd,yyyy HH:mm"); + sdf.setTimeZone(TimeZone.getTimeZone("GMT")); + CharSequence formattedTimeTrackSaved = null; + try { + long time = sdf.parse(timeTrackSaved).getTime(); + long now = System.currentTimeMillis(); + formattedTimeTrackSaved = + DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS); + } catch (ParseException e) { + e.printStackTrace(); + } + View buttonClear = itemView.findViewById(R.id.button_clear); View buttonStart = itemView.findViewById(R.id.button_start); View buttonSave = itemView.findViewById(R.id.button_save); @@ -75,7 +140,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen createButton(buttonClear, ItemType.CLEAR_DATA, true, null); createButton(buttonStart, ItemType.START_SEGMENT, true, null); - createButton(buttonSave, ItemType.SAVE, true, "17 min. ago"); + createButton(buttonSave, ItemType.SAVE, true, (String) formattedTimeTrackSaved); createButton(buttonPause, ItemType.PAUSE, true, null); createButton(buttonStop, ItemType.STOP, true, null); @@ -116,6 +181,25 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen }); UiUtilities.setupCompoundButton(showTrackOnMapButton, nightMode, PROFILE_DEPENDENT); + buttonSave.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + final GPXUtilities.GPXFile gpxFile = app.getSavingTrackHelper().getCurrentTrack().getGpxFile(); + new SaveCurrentTrackTask(app, gpxFile, saveGpxListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + + } + }); + + buttonStop.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + FragmentManager fragmentManager = getFragmentManager(); + Fragment targetFragment = getTargetFragment(); + if (fragmentManager != null && targetFragment != null) { + StopTrackRecordingBottomFragment.showInstance(fragmentManager, targetFragment); + } + } + }); } private void createButton(View view, ItemType type, boolean enabled, @Nullable String description) { @@ -150,35 +234,6 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen desc.setText(description); } - enum ItemType { - SEARCHING_GPS(R.string.searching_gps, R.drawable.ic_action_gps_info), - RECORDING(R.string.recording_default_name, R.drawable.ic_action_track_recordable), - ON_PAUSE(R.string.on_pause, R.drawable.ic_pause), - CLEAR_DATA(R.string.clear_recorded_data, R.drawable.ic_action_delete_dark), - START_SEGMENT(R.string.gpx_start_new_segment, R.drawable.ic_action_new_segment), - SAVE(R.string.shared_string_save, R.drawable.ic_action_save_to_file), - PAUSE(R.string.shared_string_pause, R.drawable.ic_pause), - STOP(R.string.shared_string_control_stop, R.drawable.ic_action_rec_stop); - - @StringRes - private int titleId; - @DrawableRes - private int iconId; - - ItemType(@StringRes int titleId, @DrawableRes int iconId) { - this.titleId = titleId; - this.iconId = iconId; - } - - public int getTitleId() { - return titleId; - } - - public int getIconId() { - return iconId; - } - } - @ColorRes protected int getActiveTextColorId() { return nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light; @@ -235,10 +290,32 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen } } - public static void showInstance(@NonNull FragmentManager fragmentManager) { - if (!fragmentManager.isStateSaved()) { - TripRecordingActiveBottomSheet fragment = new TripRecordingActiveBottomSheet(); - fragment.show(fragmentManager, TAG); + enum ItemType { + SEARCHING_GPS(R.string.searching_gps, R.drawable.ic_action_gps_info), + RECORDING(R.string.recording_default_name, R.drawable.ic_action_track_recordable), + ON_PAUSE(R.string.on_pause, R.drawable.ic_pause), + CLEAR_DATA(R.string.clear_recorded_data, R.drawable.ic_action_delete_dark), + START_SEGMENT(R.string.gpx_start_new_segment, R.drawable.ic_action_new_segment), + SAVE(R.string.shared_string_save, R.drawable.ic_action_save_to_file), + PAUSE(R.string.shared_string_pause, R.drawable.ic_pause), + STOP(R.string.shared_string_control_stop, R.drawable.ic_action_rec_stop); + + @StringRes + private int titleId; + @DrawableRes + private int iconId; + + ItemType(@StringRes int titleId, @DrawableRes int iconId) { + this.titleId = titleId; + this.iconId = iconId; + } + + public int getTitleId() { + return titleId; + } + + public int getIconId() { + return iconId; } } } From 38ab4a14fdb819a88e46609f51f7869cae206055 Mon Sep 17 00:00:00 2001 From: androiddevkotlin <64539346+androiddevkotlin@users.noreply.github.com> Date: Mon, 8 Feb 2021 12:39:29 +0200 Subject: [PATCH 07/45] Update TripRecordingActiveBottomSheet.java --- .../TripRecordingActiveBottomSheet.java | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java index 3e3fad8b75..f085c581bd 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java @@ -49,6 +49,7 @@ import net.osmand.util.Algorithms; import java.lang.ref.WeakReference; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Date; import java.util.TimeZone; import static net.osmand.plus.UiUtilities.CompoundButtonType.PROFILE_DEPENDENT; @@ -102,6 +103,8 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen app = requiredMyApplication(); OsmandSettings settings = app.getSettings(); Context context = requireContext(); + final FragmentManager fragmentManager = getFragmentManager(); + final Fragment targetFragment = getTargetFragment(); LayoutInflater inflater = UiUtilities.getInflater(context, nightMode); View itemView = inflater.inflate(R.layout.trip_recording_active_fragment, null, false); @@ -119,12 +122,14 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen ); statusIcon.setImageDrawable(statusDrawable); - String timeTrackSaved = String.valueOf(app.getSavingTrackHelper().getLastTimeUpdated()); - SimpleDateFormat sdf = new SimpleDateFormat("MMM dd,yyyy HH:mm"); + long timeTrackSaved = app.getSavingTrackHelper().getLastTimeUpdated(); + SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy HH:mm:ss:SSS Z"); sdf.setTimeZone(TimeZone.getTimeZone("GMT")); + Date resultDate = new Date(timeTrackSaved); + String sdfFormatted = sdf.format(resultDate); CharSequence formattedTimeTrackSaved = null; try { - long time = sdf.parse(timeTrackSaved).getTime(); + long time = sdf.parse(sdfFormatted).getTime(); long now = System.currentTimeMillis(); formattedTimeTrackSaved = DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS); @@ -186,20 +191,26 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen public void onClick(View v) { final GPXUtilities.GPXFile gpxFile = app.getSavingTrackHelper().getCurrentTrack().getGpxFile(); new SaveCurrentTrackTask(app, gpxFile, saveGpxListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } }); buttonStop.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - FragmentManager fragmentManager = getFragmentManager(); - Fragment targetFragment = getTargetFragment(); - if (fragmentManager != null && targetFragment != null) { + if (fragmentManager != null) { StopTrackRecordingBottomFragment.showInstance(fragmentManager, targetFragment); } } }); + + buttonClear.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (fragmentManager != null) { + ClearRecordedDataBottomSheetFragment.showInstance(fragmentManager, targetFragment); + } + } + }); } private void createButton(View view, ItemType type, boolean enabled, @Nullable String description) { From b79e4bd9964e4515c19ac15f43702bf12117814e Mon Sep 17 00:00:00 2001 From: androiddevkotlin <64539346+androiddevkotlin@users.noreply.github.com> Date: Mon, 8 Feb 2021 14:08:30 +0200 Subject: [PATCH 08/45] Snackbar top --- .../monitoring/TripRecordingActiveBottomSheet.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java index f085c581bd..8c37b6903e 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java @@ -8,8 +8,10 @@ import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.text.format.DateUtils; +import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; +import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; @@ -29,6 +31,7 @@ import androidx.fragment.app.FragmentManager; import com.google.android.material.snackbar.Snackbar; +import net.osmand.AndroidUtils; import net.osmand.GPXUtilities; import net.osmand.plus.GpxSelectionHelper; import net.osmand.plus.OsmandApplication; @@ -69,9 +72,10 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen public void gpxSavingFinished(Exception errorMessage) { String gpxFileName = Algorithms.getFileWithoutDirs(app.getSavingTrackHelper().getCurrentTrack().getGpxFile().path); final MapActivity mapActivity = getMapActivity(); + final Context context = getContext(); SavingTrackHelper helper = app.getSavingTrackHelper(); final SavingTrackHelper.SaveGpxResult result = helper.saveDataToGpx(app.getAppCustomization().getTracksDir()); - if (mapActivity != null) { + if (mapActivity != null && context != null) { Snackbar snackbar = Snackbar.make(mapActivity.getLayout(), getString(R.string.shared_string_file_is_saved, gpxFileName), Snackbar.LENGTH_LONG) @@ -83,9 +87,13 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen SaveGPXBottomSheetFragment.showInstance(fragmentActivity.getSupportFragmentManager(), result.getFilenames()); } }); + View view = snackbar.getView(); + FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) view.getLayoutParams(); + params.gravity = Gravity.TOP; + AndroidUtils.setMargins(params, 0, AndroidUtils.getStatusBarHeight(context), 0, 0); + view.setLayoutParams(params); UiUtilities.setupSnackbar(snackbar, nightMode); snackbar.show(); - dismiss(); } } @@ -309,6 +317,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen START_SEGMENT(R.string.gpx_start_new_segment, R.drawable.ic_action_new_segment), SAVE(R.string.shared_string_save, R.drawable.ic_action_save_to_file), PAUSE(R.string.shared_string_pause, R.drawable.ic_pause), + RESUME(R.string.shared_string_pause, R.drawable.ic_play_dark), STOP(R.string.shared_string_control_stop, R.drawable.ic_action_rec_stop); @StringRes From 4ec42791365d754d7c72eb7617002cb7ea047eaa Mon Sep 17 00:00:00 2001 From: Skalii Date: Mon, 8 Feb 2021 17:31:14 +0200 Subject: [PATCH 09/45] add block statistics; show current recording status; many fixes; the basis is prepared for the implementation of the functionality --- .../btn_background_active_dark.xml | 6 + .../btn_background_inactive_dark.xml | 6 + .../btn_background_inactive_light.xml | 6 + .../btn_background_stroked_active_dark.xml | 6 + .../btn_background_stroked_active_light.xml | 6 + .../btn_background_stroked_inactive_dark.xml | 6 + .../btn_background_stroked_inactive_light.xml | 6 + .../drawable/btn_background_active_light.xml | 6 + .../layout/bottom_sheet_button_with_icon.xml | 104 ++-- .../layout/trip_recording_active_fragment.xml | 10 +- .../monitoring/OsmandMonitoringPlugin.java | 35 +- .../TripRecordingActiveBottomSheet.java | 444 +++++++++++++----- .../plus/track/GpxBlockStatisticsBuilder.java | 297 ++++++++++++ 13 files changed, 750 insertions(+), 188 deletions(-) create mode 100644 OsmAnd/res/drawable-mdpi/btn_background_active_dark.xml create mode 100644 OsmAnd/res/drawable-mdpi/btn_background_inactive_dark.xml create mode 100644 OsmAnd/res/drawable-mdpi/btn_background_inactive_light.xml create mode 100644 OsmAnd/res/drawable-mdpi/btn_background_stroked_active_dark.xml create mode 100644 OsmAnd/res/drawable-mdpi/btn_background_stroked_active_light.xml create mode 100644 OsmAnd/res/drawable-mdpi/btn_background_stroked_inactive_dark.xml create mode 100644 OsmAnd/res/drawable-mdpi/btn_background_stroked_inactive_light.xml create mode 100644 OsmAnd/res/drawable/btn_background_active_light.xml create mode 100644 OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java diff --git a/OsmAnd/res/drawable-mdpi/btn_background_active_dark.xml b/OsmAnd/res/drawable-mdpi/btn_background_active_dark.xml new file mode 100644 index 0000000000..88873ec3b4 --- /dev/null +++ b/OsmAnd/res/drawable-mdpi/btn_background_active_dark.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/OsmAnd/res/drawable-mdpi/btn_background_inactive_dark.xml b/OsmAnd/res/drawable-mdpi/btn_background_inactive_dark.xml new file mode 100644 index 0000000000..07c3aed3e9 --- /dev/null +++ b/OsmAnd/res/drawable-mdpi/btn_background_inactive_dark.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/OsmAnd/res/drawable-mdpi/btn_background_inactive_light.xml b/OsmAnd/res/drawable-mdpi/btn_background_inactive_light.xml new file mode 100644 index 0000000000..03ca0abfe5 --- /dev/null +++ b/OsmAnd/res/drawable-mdpi/btn_background_inactive_light.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/OsmAnd/res/drawable-mdpi/btn_background_stroked_active_dark.xml b/OsmAnd/res/drawable-mdpi/btn_background_stroked_active_dark.xml new file mode 100644 index 0000000000..1cdfa50a92 --- /dev/null +++ b/OsmAnd/res/drawable-mdpi/btn_background_stroked_active_dark.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/OsmAnd/res/drawable-mdpi/btn_background_stroked_active_light.xml b/OsmAnd/res/drawable-mdpi/btn_background_stroked_active_light.xml new file mode 100644 index 0000000000..543dd7ef1f --- /dev/null +++ b/OsmAnd/res/drawable-mdpi/btn_background_stroked_active_light.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/OsmAnd/res/drawable-mdpi/btn_background_stroked_inactive_dark.xml b/OsmAnd/res/drawable-mdpi/btn_background_stroked_inactive_dark.xml new file mode 100644 index 0000000000..f669c9d34f --- /dev/null +++ b/OsmAnd/res/drawable-mdpi/btn_background_stroked_inactive_dark.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/OsmAnd/res/drawable-mdpi/btn_background_stroked_inactive_light.xml b/OsmAnd/res/drawable-mdpi/btn_background_stroked_inactive_light.xml new file mode 100644 index 0000000000..feacf12888 --- /dev/null +++ b/OsmAnd/res/drawable-mdpi/btn_background_stroked_inactive_light.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/OsmAnd/res/drawable/btn_background_active_light.xml b/OsmAnd/res/drawable/btn_background_active_light.xml new file mode 100644 index 0000000000..4d8d8e82a5 --- /dev/null +++ b/OsmAnd/res/drawable/btn_background_active_light.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/OsmAnd/res/layout/bottom_sheet_button_with_icon.xml b/OsmAnd/res/layout/bottom_sheet_button_with_icon.xml index ba24cc289c..79b89d1213 100644 --- a/OsmAnd/res/layout/bottom_sheet_button_with_icon.xml +++ b/OsmAnd/res/layout/bottom_sheet_button_with_icon.xml @@ -1,59 +1,69 @@ - + android:layout_height="wrap_content"> + android:id="@+id/button_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:clickable="true" + android:focusable="true" + android:gravity="center_vertical" + android:orientation="horizontal" + android:paddingStart="@dimen/content_padding_small" + android:paddingLeft="@dimen/content_padding_small" + android:paddingTop="@dimen/text_margin_small" + android:paddingEnd="@dimen/content_padding_small" + android:paddingRight="@dimen/content_padding_small" + android:paddingBottom="@dimen/text_margin_small" + tools:ignore="UselessParent"> - + android:layout_weight="1" + android:duplicateParentState="true" + android:orientation="vertical"> - + + + + + + + - - - \ No newline at end of file + \ No newline at end of file diff --git a/OsmAnd/res/layout/trip_recording_active_fragment.xml b/OsmAnd/res/layout/trip_recording_active_fragment.xml index 4f45d49fc9..df687a1bc5 100644 --- a/OsmAnd/res/layout/trip_recording_active_fragment.xml +++ b/OsmAnd/res/layout/trip_recording_active_fragment.xml @@ -30,14 +30,17 @@ osmand:typeface="@string/font_roboto_medium" /> + android:layout_marginRight="@dimen/content_padding" + android:layout_marginBottom="@dimen/content_padding" /> choice, final ValueHolder v, @@ -569,11 +580,11 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) { String s; int progress = (int) value; - if(progress == 0) { + if (progress == 0) { s = uiCtx.getString(R.string.int_continuosly); v.value = 0; } else { - if(progress < secondsLength) { + if (progress < secondsLength) { s = seconds[progress] + " " + uiCtx.getString(R.string.int_seconds); v.value = seconds[progress] * 1000; } else { @@ -598,7 +609,7 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { } } } - + ll.setOrientation(LinearLayout.VERTICAL); ll.addView(tv); ll.addView(sliderContainer); diff --git a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java index 6234d58b18..5f5c662882 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java @@ -1,14 +1,18 @@ package net.osmand.plus.monitoring; +import android.annotation.SuppressLint; import android.app.Activity; import android.app.Dialog; import android.content.Context; +import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; +import android.os.Handler; +import android.util.TypedValue; import android.view.LayoutInflater; +import android.view.MotionEvent; import android.view.View; -import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; @@ -22,8 +26,12 @@ import androidx.appcompat.widget.AppCompatImageView; import androidx.appcompat.widget.SwitchCompat; import androidx.core.content.ContextCompat; import androidx.fragment.app.FragmentManager; +import androidx.recyclerview.widget.RecyclerView; -import net.osmand.plus.GpxSelectionHelper; +import net.osmand.AndroidUtils; +import net.osmand.Location; +import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile; +import net.osmand.plus.OsmAndLocationProvider; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; @@ -31,7 +39,9 @@ import net.osmand.plus.activities.MapActivity; import net.osmand.plus.base.MenuBottomSheetDialogFragment; import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription; import net.osmand.plus.helpers.AndroidUiHelper; +import net.osmand.plus.helpers.FontCache; import net.osmand.plus.settings.backend.OsmandSettings; +import net.osmand.plus.track.GpxBlockStatisticsBuilder; import net.osmand.plus.track.TrackAppearanceFragment; import net.osmand.plus.widgets.TextViewEx; import net.osmand.util.Algorithms; @@ -44,179 +54,205 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen private OsmandApplication app; private OsmandSettings settings; + private SelectedGpxFile selectedGpxFile; + private GpxBlockStatisticsBuilder blockStatisticsBuilder; + private boolean wasTrackMonitored = false; + private boolean hasDataToSave = false; + private boolean searchingGPS = false; + + private View statusContainer; + + private final Handler handler = new Handler(); + private Runnable updatingGPS; + + public void setSelectedGpxFile(SelectedGpxFile selectedGpxFile) { + this.selectedGpxFile = selectedGpxFile; + } + + public void setWasTrackMonitored(boolean wasTrackMonitored) { + this.wasTrackMonitored = wasTrackMonitored; + } + + public void setHasDataToSave(boolean hasDataToSave) { + this.hasDataToSave = hasDataToSave; + } + + public void setSearchingGPS(boolean searchingGPS) { + this.searchingGPS = searchingGPS; + } @Override public void createMenuItems(Bundle savedInstanceState) { app = requiredMyApplication(); settings = app.getSettings(); - Context context = requireContext(); + LayoutInflater inflater = UiUtilities.getInflater(getContext(), nightMode); - LayoutInflater inflater = UiUtilities.getInflater(context, nightMode); View itemView = inflater.inflate(R.layout.trip_recording_active_fragment, null, false); items.add(new BottomSheetItemWithDescription.Builder() .setCustomView(itemView) .create()); - TextView statusTitle = itemView.findViewById(R.id.status); - statusTitle.setText(ItemType.SEARCHING_GPS.titleId); - statusTitle.setTextColor(ContextCompat.getColor(app, getSecondaryTextColorId())); - ImageView statusIcon = itemView.findViewById(R.id.icon_status); - Drawable statusDrawable = UiUtilities.tintDrawable( - AppCompatResources.getDrawable(app, ItemType.SEARCHING_GPS.iconId), - ContextCompat.getColor(app, nightMode ? R.color.icon_color_default_dark : R.color.icon_color_default_light) - ); - statusIcon.setImageDrawable(statusDrawable); - View buttonClear = itemView.findViewById(R.id.button_clear); View buttonStart = itemView.findViewById(R.id.button_start); View buttonSave = itemView.findViewById(R.id.button_save); - View buttonPause = itemView.findViewById(R.id.button_pause); + final View buttonPause = itemView.findViewById(R.id.button_pause); View buttonStop = itemView.findViewById(R.id.button_stop); - createButton(buttonClear, ItemType.CLEAR_DATA, true, null); - createButton(buttonStart, ItemType.START_SEGMENT, true, null); - createButton(buttonSave, ItemType.SAVE, true, "17 min. ago"); - createButton(buttonPause, ItemType.PAUSE, true, null); - createButton(buttonStop, ItemType.STOP, true, null); + createItem(buttonClear, ItemType.CLEAR_DATA, hasDataToSave, null); + createItem(buttonStart, ItemType.START_SEGMENT, wasTrackMonitored, null); + createItem(buttonSave, ItemType.SAVE, hasDataToSave, "..."); + createItem(buttonPause, wasTrackMonitored ? ItemType.PAUSE : ItemType.RESUME, true, null); + createItem(buttonStop, ItemType.STOP, true, null); - LinearLayout showTrackOnMapView = itemView.findViewById(R.id.show_track_on_map); - TextView showTrackOnMapTitle = showTrackOnMapView.findViewById(R.id.title); - showTrackOnMapTitle.setText(R.string.show_track_on_map); + statusContainer = itemView.findViewById(R.id.status_container); + updateStatus(); - ImageView trackAppearanceIcon = showTrackOnMapView.findViewById(R.id.icon_after_divider); - - int color = settings.CURRENT_TRACK_COLOR.get(); - String width = settings.CURRENT_TRACK_WIDTH.get(); - boolean showArrows = settings.CURRENT_TRACK_SHOW_ARROWS.get(); - Drawable drawable = TrackAppearanceFragment.getTrackIcon(app, width, showArrows, color); - - trackAppearanceIcon.setImageDrawable(drawable); - trackAppearanceIcon.setOnClickListener(new View.OnClickListener() { + // todo example, need to check + buttonPause.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - MapActivity mapActivity = getMapActivity(); - if (mapActivity != null) { - hide(); - GpxSelectionHelper.SelectedGpxFile selectedGpxFile = app.getSavingTrackHelper().getCurrentTrack(); - TrackAppearanceFragment.showInstance(mapActivity, selectedGpxFile, TripRecordingActiveBottomSheet.this); - } + boolean wasTrackMonitored = !settings.SAVE_GLOBAL_TRACK_TO_GPX.get(); + createItem(buttonPause, wasTrackMonitored ? ItemType.PAUSE : ItemType.RESUME, true, null); + TripRecordingActiveBottomSheet.this.wasTrackMonitored = wasTrackMonitored; + settings.SAVE_GLOBAL_TRACK_TO_GPX.set(wasTrackMonitored); + updateStatus(); } }); - final SwitchCompat showTrackOnMapButton = showTrackOnMapView.findViewById(R.id.switch_button); + RecyclerView statBlocks = itemView.findViewById(R.id.block_statistics); + blockStatisticsBuilder = new GpxBlockStatisticsBuilder(app, selectedGpxFile, null); + blockStatisticsBuilder.setBlocksView(statBlocks); + blockStatisticsBuilder.initStatBlocks(null, ContextCompat.getColor(app, getActiveTextColorId(nightMode)), nightMode); + + LinearLayout showTrackOnMapView = itemView.findViewById(R.id.show_track_on_map); + final LinearLayout basicItemBody = showTrackOnMapView.findViewById(R.id.basic_item_body); + + TextView showTrackTitle = basicItemBody.findViewById(R.id.title); + showTrackTitle.setText(ItemType.SHOW_TRACK.getTitleId()); + showTrackTitle.setTextColor(ContextCompat.getColor(app, getActiveIconColorId(nightMode))); + showTrackTitle.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimensionPixelSize(R.dimen.default_desc_text_size)); + Typeface typeface = FontCache.getFont(app, app.getResources().getString(R.string.font_roboto_medium)); + showTrackTitle.setTypeface(typeface); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + float letterSpacing = AndroidUtils.getFloatValueFromRes(app, R.dimen.description_letter_spacing); + showTrackTitle.setLetterSpacing(letterSpacing); + } + final SwitchCompat showTrackOnMapButton = basicItemBody.findViewById(R.id.switch_button); showTrackOnMapButton.setChecked(app.getSelectedGpxHelper().getSelectedCurrentRecordingTrack() != null); - View basicItem = itemView.findViewById(R.id.basic_item_body); - basicItem.setOnClickListener(new View.OnClickListener() { + UiUtilities.setupCompoundButton(showTrackOnMapButton, nightMode, PROFILE_DEPENDENT); + + final LinearLayout additionalButton = showTrackOnMapView.findViewById(R.id.additional_button); + View divider = additionalButton.getChildAt(0); + AndroidUiHelper.setVisibility(View.GONE, divider); + int marginS = app.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_small); + UiUtilities.setMargins(additionalButton, marginS, 0, 0, 0); + String width = settings.CURRENT_TRACK_WIDTH.get(); + boolean showArrows = settings.CURRENT_TRACK_SHOW_ARROWS.get(); + int color = settings.CURRENT_TRACK_COLOR.get(); + Drawable appearanceDrawable = TrackAppearanceFragment.getTrackIcon(app, width, showArrows, color); + AppCompatImageView appearanceIcon = additionalButton.findViewById(R.id.icon_after_divider); + int marginTrackIconH = app.getResources().getDimensionPixelSize(R.dimen.content_padding_small); + UiUtilities.setMargins(appearanceIcon, marginTrackIconH, 0, marginTrackIconH, 0); + appearanceIcon.setImageDrawable(appearanceDrawable); + additionalButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (showTrackOnMapButton.isChecked()) { + MapActivity mapActivity = getMapActivity(); + if (mapActivity != null) { + hide(); + SelectedGpxFile selectedGpxFile = app.getSavingTrackHelper().getCurrentTrack(); + TrackAppearanceFragment.showInstance(mapActivity, selectedGpxFile, TripRecordingActiveBottomSheet.this); + } + } + } + }); + createItem(additionalButton, ItemType.APPEARANCE, showTrackOnMapButton.isChecked(), null); + setShowOnMapBackgroundInactive(basicItemBody, app, showTrackOnMapButton.isChecked(), nightMode); + basicItemBody.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { boolean checked = !showTrackOnMapButton.isChecked(); showTrackOnMapButton.setChecked(checked); app.getSelectedGpxHelper().selectGpxFile(app.getSavingTrackHelper().getCurrentGpx(), checked, false); + setShowOnMapBackgroundInactive(basicItemBody, app, checked, nightMode); + createItem(additionalButton, ItemType.APPEARANCE, checked, null); } }); - UiUtilities.setupCompoundButton(showTrackOnMapButton, nightMode, PROFILE_DEPENDENT); - } - private void createButton(View view, ItemType type, boolean enabled, @Nullable String description) { + private void updateStatus() { + TextView statusTitle = statusContainer.findViewById(R.id.text_status); + AppCompatImageView statusIcon = statusContainer.findViewById(R.id.icon_status); + ItemType status = searchingGPS ? ItemType.SEARCHING_GPS : !wasTrackMonitored ? ItemType.ON_PAUSE : ItemType.RECORDING; + statusTitle.setText(status.getTitleId()); + int colorText = status.equals(ItemType.SEARCHING_GPS) ? getSecondaryTextColorId(nightMode) : getOsmandIconColorId(nightMode); + statusTitle.setTextColor(ContextCompat.getColor(app, colorText)); + int colorDrawable = ContextCompat.getColor(app, + status.equals(ItemType.SEARCHING_GPS) ? getSecondaryIconColorId(nightMode) : getOsmandIconColorId(nightMode)); + Drawable statusDrawable = UiUtilities.tintDrawable(AppCompatResources.getDrawable(app, status.getIconId()), colorDrawable); + statusIcon.setImageDrawable(statusDrawable); + } - Context ctx = view.getContext(); + private void createItem(View view, ItemType type, boolean enabled, @Nullable String description) { + view.setTag(type); + LinearLayout button = view.findViewById(R.id.button_container); - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { - view.setBackground(AppCompatResources.getDrawable(ctx, nightMode ? R.drawable.dlg_btn_secondary_dark : R.drawable.dlg_btn_secondary_light)); - } else { - view.setBackgroundDrawable(AppCompatResources.getDrawable(ctx, nightMode ? R.drawable.dlg_btn_secondary_dark : R.drawable.dlg_btn_secondary_light)); - } - - TextViewEx title = view.findViewById(R.id.title); - TextViewEx desc = view.findViewById(R.id.desc); AppCompatImageView icon = view.findViewById(R.id.icon); - - title.setText(type.getTitleId()); - title.setTextColor(ContextCompat.getColor(ctx, type == ItemType.CLEAR_DATA ? R.color.color_osm_edit_delete - : enabled ? getActiveTextColorId() : getSecondaryTextColorId())); - - Drawable tintDrawable = UiUtilities.tintDrawable( - AppCompatResources.getDrawable(ctx, type.iconId), - ContextCompat.getColor(ctx, type == ItemType.CLEAR_DATA ? R.color.color_osm_edit_delete - : enabled ? getActiveIconColorId() : getSecondaryIconColorId()) - ); - icon.setBackgroundDrawable(tintDrawable); - - boolean isShowDesc = !Algorithms.isBlank(description); - int marginSingle = app.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_medium); - AndroidUiHelper.updateVisibility(desc, isShowDesc); - UiUtilities.setMargins(title, 0, isShowDesc ? 0 : marginSingle, 0, isShowDesc ? 0 : marginSingle); - desc.setText(description); - } - - enum ItemType { - SEARCHING_GPS(R.string.searching_gps, R.drawable.ic_action_gps_info), - RECORDING(R.string.recording_default_name, R.drawable.ic_action_track_recordable), - ON_PAUSE(R.string.on_pause, R.drawable.ic_pause), - CLEAR_DATA(R.string.clear_recorded_data, R.drawable.ic_action_delete_dark), - START_SEGMENT(R.string.gpx_start_new_segment, R.drawable.ic_action_new_segment), - SAVE(R.string.shared_string_save, R.drawable.ic_action_save_to_file), - PAUSE(R.string.shared_string_pause, R.drawable.ic_pause), - STOP(R.string.shared_string_control_stop, R.drawable.ic_action_rec_stop); - - @StringRes - private int titleId; - @DrawableRes - private int iconId; - - ItemType(@StringRes int titleId, @DrawableRes int iconId) { - this.titleId = titleId; - this.iconId = iconId; + if (icon != null) { + type.setTintedIcon(icon, app, enabled, false, nightMode); } - public int getTitleId() { - return titleId; + TextView title = view.findViewById(R.id.title); + if (title != null) { + title.setText(type.getTitleId()); + type.setTextColor(title, app, enabled, false, nightMode); } - public int getIconId() { - return iconId; + setItemBackgroundInactive(button != null ? button : (LinearLayout) view, app, nightMode); + type.changeOnTouch(button != null ? button : (LinearLayout) view, icon, title, app, enabled, nightMode); + + TextViewEx desc = view.findViewById(R.id.desc); + if (desc != null) { + boolean isShowDesc = !Algorithms.isBlank(description); + int marginDesc = isShowDesc ? 0 : app.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_medium); + AndroidUiHelper.updateVisibility(desc, isShowDesc); + UiUtilities.setMargins(title, 0, marginDesc, 0, marginDesc); + desc.setText(description); } } - @ColorRes - protected int getActiveTextColorId() { - return nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light; - } - - @ColorRes - protected int getSecondaryTextColorId() { - return nightMode ? R.color.text_color_secondary_dark : R.color.text_color_secondary_light; - } - - @ColorRes - protected int getActiveIconColorId() { - return nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light; - } - - @ColorRes - protected int getSecondaryIconColorId() { - return nightMode ? R.color.icon_color_secondary_dark : R.color.icon_color_secondary_light; - } - - @ColorRes - protected int getOsmandIconColorId() { - return nightMode ? R.color.icon_color_osmand_dark : R.color.icon_color_osmand_light; + @Override + public void onResume() { + super.onResume(); + blockStatisticsBuilder.runUpdatingStatBlocks(); + runUpdatingGPS(); } @Override - protected int getDismissButtonHeight() { - return getResources().getDimensionPixelSize(R.dimen.bottom_sheet_cancel_button_height); + public void onPause() { + super.onPause(); + blockStatisticsBuilder.stopUpdatingStatBlocks(); + stopUpdatingGPS(); } - @Override - protected int getDismissButtonTextId() { - return R.string.shared_string_close; + public void stopUpdatingGPS() { + handler.removeCallbacks(updatingGPS); } - @Override - protected boolean useVerticalButtons() { - return true; + public void runUpdatingGPS() { + updatingGPS = new Runnable() { + @Override + public void run() { + int interval = app.getSettings().SAVE_GLOBAL_TRACK_INTERVAL.get(); + OsmAndLocationProvider locationProvider = app.getLocationProvider(); + Location lastKnownLocation = locationProvider.getLastKnownLocation(); + searchingGPS = lastKnownLocation == null; + updateStatus(); + handler.postDelayed(this, Math.max(1000, interval)); + } + }; + handler.post(updatingGPS); } @Nullable @@ -235,9 +271,165 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen } } - public static void showInstance(@NonNull FragmentManager fragmentManager) { + private static void setItemBackgroundActive(LinearLayout view, Context context, boolean nightMode) { + Drawable background = AppCompatResources.getDrawable(context, + nightMode ? R.drawable.btn_background_active_dark : R.drawable.btn_background_active_light); + view.setBackgroundDrawable(background); + } + + private static void setItemBackgroundInactive(LinearLayout view, Context context, boolean nightMode) { + Drawable background = AppCompatResources.getDrawable(context, + nightMode ? R.drawable.btn_background_inactive_dark : R.drawable.btn_background_inactive_light); + view.setBackgroundDrawable(background); + } + + private static void setShowOnMapBackgroundActive(LinearLayout view, Context context, boolean checked, boolean nightMode) { + Drawable background = AppCompatResources.getDrawable(context, + nightMode ? checked ? R.drawable.btn_background_active_dark : R.drawable.btn_background_stroked_active_dark + : checked ? R.drawable.btn_background_active_light : R.drawable.btn_background_stroked_active_light); + view.setBackgroundDrawable(background); + } + + private static void setShowOnMapBackgroundInactive(LinearLayout view, Context context, boolean checked, boolean nightMode) { + Drawable background = AppCompatResources.getDrawable(context, + nightMode ? checked ? R.drawable.btn_background_inactive_dark : R.drawable.btn_background_stroked_inactive_dark + : checked ? R.drawable.btn_background_inactive_light : R.drawable.btn_background_stroked_inactive_light); + view.setBackgroundDrawable(background); + } + + enum ItemType { + SHOW_TRACK(R.string.shared_string_show_on_map, null), + APPEARANCE(null, null), + SEARCHING_GPS(R.string.searching_gps, R.drawable.ic_action_gps_info), + RECORDING(R.string.recording_default_name, R.drawable.ic_action_track_recordable), + ON_PAUSE(R.string.on_pause, R.drawable.ic_pause), + CLEAR_DATA(R.string.clear_recorded_data, R.drawable.ic_action_delete_dark), + START_SEGMENT(R.string.gpx_start_new_segment, R.drawable.ic_action_new_segment), + SAVE(R.string.shared_string_save, R.drawable.ic_action_save_to_file), + PAUSE(R.string.shared_string_pause, R.drawable.ic_pause), + RESUME(R.string.shared_string_resume, R.drawable.ic_play_dark), + STOP(R.string.shared_string_control_stop, R.drawable.ic_action_rec_stop); + + @StringRes + private final Integer titleId; + @DrawableRes + private final Integer iconId; + + ItemType(@Nullable @StringRes Integer titleId, @Nullable @DrawableRes Integer iconId) { + this.titleId = titleId; + this.iconId = iconId; + } + + public Integer getTitleId() { + return titleId; + } + + public Integer getIconId() { + return iconId; + } + + public void setTextColor(TextView tv, Context context, boolean enabled, boolean pressed, boolean nightMode) { + if (tv != null) { + tv.setTextColor(ContextCompat.getColor(context, + enabled ? pressed ? getPressedColorId(nightMode) + : equals(ItemType.CLEAR_DATA) ? R.color.color_osm_edit_delete + : getActiveTextColorId(nightMode) : getSecondaryTextColorId(nightMode))); + } + } + + public void setTintedIcon(AppCompatImageView iv, Context context, boolean enabled, boolean pressed, boolean nightMode) { + if (iv != null) { + int iconColor = ContextCompat.getColor(context, + enabled ? pressed ? getPressedColorId(nightMode) + : equals(ItemType.CLEAR_DATA) ? R.color.color_osm_edit_delete + : getActiveIconColorId(nightMode) : getSecondaryIconColorId(nightMode)); + Drawable icon = UiUtilities.createTintedDrawable(context, iconId, iconColor); + iv.setImageDrawable(icon); + } + } + + @SuppressLint("ClickableViewAccessibility") + private void changeOnTouch(final LinearLayout button, @Nullable final AppCompatImageView iv, @Nullable final TextView tv, + final Context context, final boolean enabled, final boolean nightMode) { + button.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (enabled) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: { + setItemBackgroundActive(button, context, nightMode); + setTintedIcon(iv, context, enabled, true, nightMode); + setTextColor(tv, context, enabled, true, nightMode); + break; + } + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: { + setItemBackgroundInactive(button, context, nightMode); + setTintedIcon(iv, context, enabled, false, nightMode); + setTextColor(tv, context, enabled, false, nightMode); + break; + } + } + } + return false; + } + }); + } + } + + @ColorRes + private static int getActiveTextColorId(boolean nightMode) { + return nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light; + } + + @ColorRes + private static int getSecondaryTextColorId(boolean nightMode) { + return nightMode ? R.color.text_color_secondary_dark : R.color.text_color_secondary_light; + } + + @ColorRes + private static int getActiveIconColorId(boolean nightMode) { + return nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light; + } + + @ColorRes + private static int getSecondaryIconColorId(boolean nightMode) { + return nightMode ? R.color.icon_color_secondary_dark : R.color.icon_color_secondary_light; + } + + @ColorRes + private static int getOsmandIconColorId(boolean nightMode) { + return nightMode ? R.color.icon_color_osmand_dark : R.color.icon_color_osmand_light; + } + + @ColorRes + private static int getPressedColorId(boolean nightMode) { + return nightMode ? R.color.active_buttons_and_links_text_dark : R.color.active_buttons_and_links_text_light; + } + + @Override + protected int getDismissButtonHeight() { + return getResources().getDimensionPixelSize(R.dimen.bottom_sheet_cancel_button_height); + } + + @Override + protected int getDismissButtonTextId() { + return R.string.shared_string_close; + } + + @Override + protected boolean useVerticalButtons() { + return true; + } + + public static void showInstance(@NonNull FragmentManager fragmentManager, SelectedGpxFile selectedGpxFile, + boolean wasTrackMonitored, boolean hasDataToSave, boolean searchingGPS) { if (!fragmentManager.isStateSaved()) { TripRecordingActiveBottomSheet fragment = new TripRecordingActiveBottomSheet(); + fragment.setSelectedGpxFile(selectedGpxFile); + fragment.setWasTrackMonitored(wasTrackMonitored); + fragment.setHasDataToSave(hasDataToSave); + fragment.setSearchingGPS(searchingGPS); fragment.show(fragmentManager, TAG); } } diff --git a/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java b/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java new file mode 100644 index 0000000000..d132de4ede --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java @@ -0,0 +1,297 @@ +package net.osmand.plus.track; + +import android.graphics.drawable.Drawable; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.ColorInt; +import androidx.annotation.ColorRes; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import net.osmand.AndroidUtils; +import net.osmand.GPXUtilities.GPXTrackAnalysis; +import net.osmand.plus.GpxSelectionHelper.GpxDisplayGroup; +import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem; +import net.osmand.plus.GpxSelectionHelper.GpxDisplayItemType; +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.helpers.AndroidUiHelper; +import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetType; +import net.osmand.plus.myplaces.SegmentActionsListener; +import net.osmand.plus.widgets.TextViewEx; +import net.osmand.util.Algorithms; + +import java.util.ArrayList; +import java.util.List; + +import android.os.Handler; + +public class GpxBlockStatisticsBuilder { + + private final OsmandApplication app; + private RecyclerView blocksView; + private final SelectedGpxFile selectedGpxFile; + private final TrackDisplayHelper displayHelper; + private final GpxDisplayItemType[] filterTypes = {GpxDisplayItemType.TRACK_SEGMENT}; + + private BlockStatisticsAdapter bsAdapter; + private final List items = new ArrayList<>(); + + private final Handler handler = new Handler(); + private Runnable updatingStats; + + public GpxBlockStatisticsBuilder(OsmandApplication app, SelectedGpxFile selectedGpxFile, TrackDisplayHelper displayHelper) { + this.app = app; + this.selectedGpxFile = selectedGpxFile; + this.displayHelper = displayHelper; + } + + public void setBlocksView(RecyclerView blocksView) { + this.blocksView = blocksView; + } + + private GPXTrackAnalysis getAnalysis() { + return selectedGpxFile.getTrackAnalysis(app); + } + + public void initStatBlocks(@Nullable SegmentActionsListener actionsListener, @ColorInt int activeColor, boolean nightMode) { + initItems(); + if (Algorithms.isEmpty(items)) { + AndroidUiHelper.updateVisibility(blocksView, false); + } else { + bsAdapter = new BlockStatisticsAdapter(actionsListener, activeColor, nightMode); + bsAdapter.setItems(items); + blocksView.setLayoutManager(new LinearLayoutManager(app, LinearLayoutManager.HORIZONTAL, false)); + blocksView.setAdapter(bsAdapter); + } + } + + public void stopUpdatingStatBlocks() { + handler.removeCallbacks(updatingStats); + } + + public void runUpdatingStatBlocks() { + updatingStats = new Runnable() { + @Override + public void run() { + Log.d("BlockStatisticsBuilder", "run: working"); + if (bsAdapter != null) { + initItems(); + bsAdapter.setItems(items); + } + int interval = app.getSettings().SAVE_GLOBAL_TRACK_INTERVAL.get(); + handler.postDelayed(this, Math.max(1000, interval)); + } + }; + handler.post(updatingStats); + } + + public void initItems() { + GPXTrackAnalysis analysis = getAnalysis(); + float totalDistance = analysis.totalDistance; + float timeSpan = analysis.timeSpan; + String asc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationUp, app); + String desc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationDown, app); + String avg = OsmAndFormatter.getFormattedSpeed(analysis.avgSpeed, app); + String max = OsmAndFormatter.getFormattedSpeed(analysis.maxSpeed, app); + + items.clear(); + prepareData(analysis, app.getString(R.string.distance), OsmAndFormatter.getFormattedDistance(totalDistance, app), + R.drawable.ic_action_track_16, R.color.icon_color_default_light, GPXDataSetType.ALTITUDE, GPXDataSetType.SPEED, ItemType.ITEM_DISTANCE); + prepareData(analysis, app.getString(R.string.altitude_ascent), asc, + R.drawable.ic_action_arrow_up_16, R.color.gpx_chart_red, GPXDataSetType.SLOPE, null, ItemType.ITEM_ALTITUDE); + prepareData(analysis, app.getString(R.string.altitude_descent), desc, + R.drawable.ic_action_arrow_down_16, R.color.gpx_pale_green, GPXDataSetType.ALTITUDE, GPXDataSetType.SLOPE, ItemType.ITEM_ALTITUDE); + prepareData(analysis, app.getString(R.string.average_speed), avg, + R.drawable.ic_action_speed_16, R.color.icon_color_default_light, GPXDataSetType.SPEED, null, ItemType.ITEM_SPEED); + prepareData(analysis, app.getString(R.string.max_speed), max, + R.drawable.ic_action_max_speed_16, R.color.icon_color_default_light, GPXDataSetType.SPEED, null, ItemType.ITEM_SPEED); + prepareData(analysis, app.getString(R.string.shared_string_time_span), + Algorithms.formatDuration((int) (timeSpan / 1000), app.accessibilityEnabled()), + R.drawable.ic_action_time_span_16, R.color.icon_color_default_light, GPXDataSetType.SPEED, null, ItemType.ITEM_TIME); + } + + public void prepareData(GPXTrackAnalysis analysis, String title, String value, + @DrawableRes int imageResId, @ColorRes int imageColorId, + GPXDataSetType firstType, GPXDataSetType secondType, ItemType itemType) { + StatBlock statBlock = new StatBlock(title, value, imageResId, imageColorId, firstType, secondType, itemType); + switch (statBlock.itemType) { + case ITEM_DISTANCE: { + if (analysis.totalDistance != 0f) { + items.add(statBlock); + } + break; + } + case ITEM_ALTITUDE: { + if (analysis.hasElevationData) { + items.add(statBlock); + } + break; + } + case ITEM_SPEED: { + if (analysis.isSpeedSpecified()) { + items.add(statBlock); + } + break; + } + case ITEM_TIME: { + if (analysis.hasSpeedData) { + items.add(statBlock); + } + break; + } + } + } + + private void setImageDrawable(ImageView iv, @DrawableRes Integer resId, @ColorRes int color) { + Drawable icon = resId != null ? app.getUIUtilities().getIcon(resId, color) + : UiUtilities.tintDrawable(iv.getDrawable(), getResolvedColor(color)); + iv.setImageDrawable(icon); + } + + @ColorInt + protected int getResolvedColor(@ColorRes int colorId) { + return ContextCompat.getColor(app, colorId); + } + + public class StatBlock { + + private final String title; + private final String value; + private final int imageResId; + private final int imageColorId; + private final GPXDataSetType firstType; + private final GPXDataSetType secondType; + private final ItemType itemType; + + public StatBlock(String title, String value, @DrawableRes int imageResId, @ColorRes int imageColorId, + GPXDataSetType firstType, GPXDataSetType secondType, ItemType itemType) { + this.title = title; + this.value = value; + this.imageResId = imageResId; + this.imageColorId = imageColorId; + this.firstType = firstType; + this.secondType = secondType; + this.itemType = itemType; + } + } + + public enum ItemType { + ITEM_DISTANCE, + ITEM_ALTITUDE, + ITEM_SPEED, + ITEM_TIME; + } + + private class BlockStatisticsAdapter extends RecyclerView.Adapter { + + @ColorInt + private final int activeColor; + private final List statBlocks = new ArrayList<>(); + private final boolean nightMode; + private final SegmentActionsListener actionsListener; + + public BlockStatisticsAdapter(@Nullable SegmentActionsListener actionsListener, @ColorInt int activeColor, boolean nightMode) { + this.actionsListener = actionsListener; + this.activeColor = activeColor; + this.nightMode = nightMode; + } + + @Override + public int getItemCount() { + return statBlocks.size(); + } + + @NonNull + @Override + public BlockStatisticsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View itemView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.item_gpx_stat_block, parent, false); + return new BlockStatisticsViewHolder(itemView); + } + + @Override + public void onBindViewHolder(final BlockStatisticsViewHolder holder, int position) { + final StatBlock item = statBlocks.get(position); + holder.valueText.setText(item.value); + holder.titleText.setText(item.title); + if (handler.hasCallbacks(updatingStats)) { + holder.titleText.setWidth(app.getResources().getDimensionPixelSize(R.dimen.map_route_buttons_width)); + } + holder.valueText.setTextColor(activeColor); + holder.titleText.setTextColor(app.getResources().getColor(R.color.text_color_secondary_light)); + if (actionsListener != null && displayHelper != null) { + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + List groups = displayHelper.getDisplayGroups(filterTypes); + GpxDisplayGroup group = null; + for (GpxDisplayGroup g : groups) { + if (g.isGeneralTrack()) { + group = g; + } + } + if (group == null && !groups.isEmpty()) { + group = groups.get(0); + } + if (group != null) { + GpxDisplayItem displayItem = group.getModifiableList().get(0); + if (displayItem != null && displayItem.analysis != null) { + ArrayList list = new ArrayList<>(); + if (displayItem.analysis.hasElevationData || displayItem.analysis.isSpeedSpecified() || displayItem.analysis.hasSpeedData) { + if (item.firstType != null) { + list.add(item.firstType); + } + if (item.secondType != null) { + list.add(item.secondType); + } + } + displayItem.chartTypes = list.size() > 0 ? list.toArray(new GPXDataSetType[0]) : null; + displayItem.locationOnMap = displayItem.locationStart; + actionsListener.openAnalyzeOnMap(displayItem); + } + } + } + }); + } + setImageDrawable(holder.imageView, item.imageResId, item.imageColorId); + AndroidUtils.setBackgroundColor(app, holder.divider, nightMode, R.color.divider_color_light, R.color.divider_color_dark); + AndroidUiHelper.updateVisibility(holder.divider, position != statBlocks.size() - 1); + } + + public void setItems(List statBlocks) { + this.statBlocks.clear(); + this.statBlocks.addAll(statBlocks); + notifyItemRangeChanged(0, getItemCount()); + } + } + + private class BlockStatisticsViewHolder extends RecyclerView.ViewHolder { + + private final TextViewEx valueText; + private final TextView titleText; + private final AppCompatImageView imageView; + private final View divider; + + public BlockStatisticsViewHolder(View view) { + super(view); + valueText = view.findViewById(R.id.value); + titleText = view.findViewById(R.id.title); + imageView = view.findViewById(R.id.image); + divider = view.findViewById(R.id.divider); + } + } +} From 6c32861ebd653d680da0594c4832ac001ec32518 Mon Sep 17 00:00:00 2001 From: Skalii Date: Mon, 8 Feb 2021 18:27:01 +0200 Subject: [PATCH 10/45] test commit --- .../src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java b/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java index 838944a988..a7b23e18ec 100644 --- a/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java +++ b/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java @@ -190,7 +190,7 @@ public class GpxBlockStatisticsBuilder { ITEM_DISTANCE, ITEM_ALTITUDE, ITEM_SPEED, - ITEM_TIME; + ITEM_TIME } private class BlockStatisticsAdapter extends RecyclerView.Adapter { @@ -292,3 +292,4 @@ public class GpxBlockStatisticsBuilder { } } } +// \ No newline at end of file From 7315679c8fb9f25161a4f8c08732436a6fd27b77 Mon Sep 17 00:00:00 2001 From: Skalii Date: Tue, 9 Feb 2021 05:19:04 +0200 Subject: [PATCH 11/45] implementation of functionality; many fixes; --- .../layout/bottom_sheet_button_with_icon.xml | 9 +- .../bottom_sheet_item_button_with_icon.xml | 9 +- .../plus/activities/MapActivityActions.java | 27 +- .../ClearRecordedDataBottomSheetFragment.java | 12 +- .../monitoring/OsmandMonitoringPlugin.java | 34 ++- .../StopTrackRecordingBottomFragment.java | 12 +- .../TripRecordingActiveBottomSheet.java | 235 +++++++++++------- .../monitoring/TripRecordingBottomSheet.java | 8 +- .../plus/track/GpxBlockStatisticsBuilder.java | 3 +- .../plus/track/TrackAppearanceFragment.java | 3 + 10 files changed, 221 insertions(+), 131 deletions(-) diff --git a/OsmAnd/res/layout/bottom_sheet_button_with_icon.xml b/OsmAnd/res/layout/bottom_sheet_button_with_icon.xml index 79b89d1213..b184a3bea7 100644 --- a/OsmAnd/res/layout/bottom_sheet_button_with_icon.xml +++ b/OsmAnd/res/layout/bottom_sheet_button_with_icon.xml @@ -19,6 +19,7 @@ android:paddingEnd="@dimen/content_padding_small" android:paddingRight="@dimen/content_padding_small" android:paddingBottom="@dimen/text_margin_small" + tools:background="@drawable/btn_background_inactive_dark" tools:ignore="UselessParent"> + tools:textColor="@color/active_color_primary_dark" /> @@ -62,7 +63,7 @@ android:layout_marginLeft="@dimen/context_menu_padding_margin_large" android:duplicateParentState="true" tools:srcCompat="@drawable/ic_action_appearance" - tools:tint="@color/icon_color_secondary_light" /> + tools:tint="@color/icon_color_active_dark" /> diff --git a/OsmAnd/res/layout/bottom_sheet_item_button_with_icon.xml b/OsmAnd/res/layout/bottom_sheet_item_button_with_icon.xml index 3d2d1bbab1..2e1c2cd881 100644 --- a/OsmAnd/res/layout/bottom_sheet_item_button_with_icon.xml +++ b/OsmAnd/res/layout/bottom_sheet_item_button_with_icon.xml @@ -1,7 +1,7 @@ @@ -9,9 +9,9 @@ android:id="@+id/button_container" android:layout_width="match_parent" android:layout_height="wrap_content" + android:duplicateParentState="true" android:gravity="center_vertical" android:orientation="horizontal" - android:duplicateParentState="true" android:paddingStart="@dimen/content_padding_small" android:paddingLeft="@dimen/content_padding_small" android:paddingTop="@dimen/text_margin_small" @@ -33,6 +33,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:duplicateParentState="true" + android:letterSpacing="@dimen/description_letter_spacing" android:textSize="@dimen/default_desc_text_size" osmand:typeface="@string/font_roboto_medium" tools:text="Title" @@ -43,10 +44,10 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:duplicateParentState="true" + android:letterSpacing="@dimen/description_letter_spacing" android:textColor="@color/text_color_secondary_light" android:textSize="@dimen/default_desc_text_size" android:visibility="gone" - android:letterSpacing="@dimen/description_letter_spacing" osmand:typeface="@string/font_roboto_medium" tools:text="Description" tools:visibility="visible" /> @@ -57,9 +58,9 @@ android:id="@+id/icon" android:layout_width="@dimen/map_widget_icon" android:layout_height="@dimen/map_widget_icon" - android:duplicateParentState="true" android:layout_marginStart="@dimen/context_menu_padding_margin_large" android:layout_marginLeft="@dimen/context_menu_padding_margin_large" + android:duplicateParentState="true" tools:srcCompat="@drawable/ic_action_appearance" tools:tint="@color/icon_color_secondary_light" /> diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java index 625396e5e3..b216913466 100644 --- a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java +++ b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java @@ -360,10 +360,10 @@ public class MapActivityActions implements DialogProvider { } public void addActionsToAdapter(final double latitude, - final double longitude, - final ContextMenuAdapter adapter, - Object selectedObj, - boolean configureMenu) { + final double longitude, + final ContextMenuAdapter adapter, + Object selectedObj, + boolean configureMenu) { ItemBuilder itemBuilder = new ItemBuilder(); adapter.addItem(itemBuilder @@ -543,17 +543,17 @@ public class MapActivityActions implements DialogProvider { } public void enterRoutePlanningModeGivenGpx(GPXFile gpxFile, LatLon from, PointDescription fromName, - boolean useIntermediatePointsByDefault, boolean showMenu) { + boolean useIntermediatePointsByDefault, boolean showMenu) { enterRoutePlanningModeGivenGpx(gpxFile, from, fromName, useIntermediatePointsByDefault, showMenu, MapRouteInfoMenu.DEFAULT_MENU_STATE); } public void enterRoutePlanningModeGivenGpx(GPXFile gpxFile, LatLon from, PointDescription fromName, - boolean useIntermediatePointsByDefault, boolean showMenu, int menuState) { + boolean useIntermediatePointsByDefault, boolean showMenu, int menuState) { enterRoutePlanningModeGivenGpx(gpxFile, null, from, fromName, useIntermediatePointsByDefault, showMenu, menuState); } public void enterRoutePlanningModeGivenGpx(GPXFile gpxFile, ApplicationMode appMode, LatLon from, PointDescription fromName, - boolean useIntermediatePointsByDefault, boolean showMenu, int menuState) { + boolean useIntermediatePointsByDefault, boolean showMenu, int menuState) { settings.USE_INTERMEDIATE_POINTS_NAVIGATION.set(useIntermediatePointsByDefault); OsmandApplication app = mapActivity.getMyApplication(); TargetPointsHelper targets = app.getTargetPointsHelper(); @@ -843,7 +843,8 @@ public class MapActivityActions implements DialogProvider { } }).createItem()); - boolean isTripRecordingPluginOn = OsmandPlugin.getEnabledPlugin(OsmandMonitoringPlugin.class) != null; + final OsmandMonitoringPlugin monitoringPlugin = OsmandPlugin.getEnabledPlugin(OsmandMonitoringPlugin.class); + boolean isTripRecordingPluginOn = monitoringPlugin != null; if (isTripRecordingPluginOn) { optionsMenuHelper.addItem(new ItemBuilder().setTitleId(R.string.map_widget_monitoring, mapActivity) .setId(DRAWER_TRIP_RECORDING_ID) @@ -853,7 +854,13 @@ public class MapActivityActions implements DialogProvider { public boolean onContextMenuClick(ArrayAdapter adapter, int itemId, int pos, boolean isChecked, int[] viewCoordinates) { app.logEvent("trip_recording_open"); MapActivity.clearPrevActivityIntent(); - TripRecordingBottomSheet.showInstance(mapActivity.getSupportFragmentManager()); + if (monitoringPlugin.isHasDataToSave() || monitoringPlugin.isWasTrackMonitored()) { + TripRecordingActiveBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), + monitoringPlugin.getCurrentTrack(), monitoringPlugin.isWasTrackMonitored(), + monitoringPlugin.isHasDataToSave(), monitoringPlugin.isSearchingGPS()); + } else { + TripRecordingBottomSheet.showInstance(mapActivity.getSupportFragmentManager()); + } return true; } }).createItem()); @@ -1107,7 +1114,7 @@ public class MapActivityActions implements DialogProvider { } private String getProfileDescription(OsmandApplication app, ApplicationMode mode, - Map profilesObjects, String defaultDescription) { + Map profilesObjects, String defaultDescription) { String description = defaultDescription; String routingProfileKey = mode.getRoutingProfile(); diff --git a/OsmAnd/src/net/osmand/plus/monitoring/ClearRecordedDataBottomSheetFragment.java b/OsmAnd/src/net/osmand/plus/monitoring/ClearRecordedDataBottomSheetFragment.java index 971bfd01e0..0bdced7bc5 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/ClearRecordedDataBottomSheetFragment.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/ClearRecordedDataBottomSheetFragment.java @@ -102,26 +102,18 @@ public class ClearRecordedDataBottomSheetFragment extends MenuBottomSheetDialogF @Override public void onResume() { super.onResume(); - // Replace later with tTripRecordingActiveBottomSheet.hide() Fragment target = getTargetFragment(); if (target instanceof TripRecordingActiveBottomSheet) { - Dialog dialog = ((TripRecordingActiveBottomSheet) target).getDialog(); - if (dialog != null) { - dialog.hide(); - } + ((TripRecordingActiveBottomSheet) target).hide(); } } @Override public void onPause() { super.onPause(); - // Replace later with tTripRecordingActiveBottomSheet.show() Fragment target = getTargetFragment(); if (target instanceof TripRecordingActiveBottomSheet) { - Dialog dialog = ((TripRecordingActiveBottomSheet) target).getDialog(); - if (dialog != null) { - dialog.show(); - } + ((TripRecordingActiveBottomSheet) target).show(); } } diff --git a/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java b/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java index 65538733b0..eaa54a948a 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java @@ -28,6 +28,8 @@ import com.google.android.material.slider.Slider; import net.osmand.AndroidUtils; import net.osmand.Location; import net.osmand.ValueHolder; +import net.osmand.plus.GpxSelectionHelper; +import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile; import net.osmand.plus.NavigationService; import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmAndLocationProvider; @@ -318,8 +320,34 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { } } + public SelectedGpxFile getCurrentTrack() { + return app.getSavingTrackHelper().getCurrentTrack(); + } + + public boolean isWasTrackMonitored() { + return settings.SAVE_GLOBAL_TRACK_TO_GPX.get(); + } + + public boolean isHasDataToSave() { + return app.getSavingTrackHelper().hasDataToSave(); + } + + public boolean isSearchingGPS() { + OsmAndLocationProvider locationProvider = app.getLocationProvider(); + Location lastKnownLocation = locationProvider.getLastKnownLocation(); + return lastKnownLocation == null; + } + public void controlDialog(final Activity activity, final boolean showTrackSelection) { - final boolean wasTrackMonitored = settings.SAVE_GLOBAL_TRACK_TO_GPX.get(); + if (isHasDataToSave() || isWasTrackMonitored()) { + FragmentActivity fragmentActivity = (FragmentActivity) activity; + TripRecordingActiveBottomSheet.showInstance(fragmentActivity.getSupportFragmentManager(), + getCurrentTrack(), isWasTrackMonitored(), isHasDataToSave(), isSearchingGPS()); + } else { + FragmentActivity fragmentActivity = (FragmentActivity) activity; + TripRecordingBottomSheet.showInstance(fragmentActivity.getSupportFragmentManager()); + } + /*final boolean wasTrackMonitored = settings.SAVE_GLOBAL_TRACK_TO_GPX.get(); final boolean nightMode; if (activity instanceof MapActivity) { nightMode = app.getDaynightHelper().isNightModeForMapControls(); @@ -328,8 +356,6 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { } AlertDialog.Builder bld = new AlertDialog.Builder(UiUtilities.getThemedContext(activity, nightMode)); final TIntArrayList items = new TIntArrayList(); - FragmentActivity fragmentActivity = (FragmentActivity) activity; - TripRecordingActiveBottomSheet.showInstance(fragmentActivity.getSupportFragmentManager()); if (wasTrackMonitored) { items.add(R.string.gpx_monitoring_stop); items.add(R.string.gpx_start_new_segment); @@ -419,7 +445,7 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { } }); // bld.show(); - } + }*/ } public void saveCurrentTrack() { diff --git a/OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java b/OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java index b7bf829457..5172bfc1bf 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java @@ -128,26 +128,18 @@ public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragm @Override public void onResume() { super.onResume(); - // Replace later with tTripRecordingActiveBottomSheet.hide() Fragment target = getTargetFragment(); if (target instanceof TripRecordingActiveBottomSheet) { - Dialog dialog = ((TripRecordingActiveBottomSheet) target).getDialog(); - if (dialog != null) { - dialog.hide(); - } + ((TripRecordingActiveBottomSheet) target).hide(); } } @Override public void onPause() { super.onPause(); - // Replace later with tTripRecordingActiveBottomSheet.show() Fragment target = getTargetFragment(); if (target instanceof TripRecordingActiveBottomSheet) { - Dialog dialog = ((TripRecordingActiveBottomSheet) target).getDialog(); - if (dialog != null) { - dialog.show(); - } + ((TripRecordingActiveBottomSheet) target).show(); } } diff --git a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java index 23bf24e287..775bbac87c 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java @@ -29,7 +29,6 @@ import androidx.appcompat.content.res.AppCompatResources; import androidx.appcompat.widget.AppCompatImageView; import androidx.appcompat.widget.SwitchCompat; import androidx.core.content.ContextCompat; -import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.recyclerview.widget.RecyclerView; @@ -37,8 +36,9 @@ import androidx.recyclerview.widget.RecyclerView; import com.google.android.material.snackbar.Snackbar; import net.osmand.AndroidUtils; -import net.osmand.GPXUtilities; +import net.osmand.GPXUtilities.GPXFile; import net.osmand.Location; +import net.osmand.PlatformUtil; import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile; import net.osmand.plus.OsmAndLocationProvider; import net.osmand.plus.OsmandApplication; @@ -46,6 +46,7 @@ import net.osmand.plus.R; import net.osmand.plus.UiUtilities; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.SavingTrackHelper; +import net.osmand.plus.activities.SavingTrackHelper.SaveGpxResult; import net.osmand.plus.base.MenuBottomSheetDialogFragment; import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription; import net.osmand.plus.helpers.AndroidUiHelper; @@ -53,15 +54,18 @@ import net.osmand.plus.helpers.FontCache; import net.osmand.plus.myplaces.SaveCurrentTrackTask; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.track.GpxBlockStatisticsBuilder; -import net.osmand.plus.track.SaveGpxAsyncTask; +import net.osmand.plus.track.SaveGpxAsyncTask.SaveGpxListener; import net.osmand.plus.track.TrackAppearanceFragment; import net.osmand.plus.widgets.TextViewEx; import net.osmand.util.Algorithms; +import org.apache.commons.logging.Log; + import java.lang.ref.WeakReference; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.Locale; import java.util.TimeZone; import static net.osmand.plus.UiUtilities.CompoundButtonType.PROFILE_DEPENDENT; @@ -69,57 +73,28 @@ import static net.osmand.plus.UiUtilities.CompoundButtonType.PROFILE_DEPENDENT; public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragment { public static final String TAG = TripRecordingActiveBottomSheet.class.getSimpleName(); + private static final Log log = PlatformUtil.getLog(TripRecordingActiveBottomSheet.class); private OsmandApplication app; private OsmandSettings settings; + private SavingTrackHelper helper; private SelectedGpxFile selectedGpxFile; - private GpxBlockStatisticsBuilder blockStatisticsBuilder; private boolean wasTrackMonitored = false; private boolean hasDataToSave = false; private boolean searchingGPS = false; private View statusContainer; + private View buttonSave; + private GpxBlockStatisticsBuilder blockStatisticsBuilder; private final Handler handler = new Handler(); private Runnable updatingGPS; + private Runnable updatingTimeTrackSaved; + private SaveGpxListener saveGpxListener; - SaveGpxAsyncTask.SaveGpxListener saveGpxListener = new SaveGpxAsyncTask.SaveGpxListener() { - - @Override - public void gpxSavingStarted() { - - } - - @Override - public void gpxSavingFinished(Exception errorMessage) { - String gpxFileName = Algorithms.getFileWithoutDirs(app.getSavingTrackHelper().getCurrentTrack().getGpxFile().path); - final MapActivity mapActivity = getMapActivity(); - final Context context = getContext(); - SavingTrackHelper helper = app.getSavingTrackHelper(); - final SavingTrackHelper.SaveGpxResult result = helper.saveDataToGpx(app.getAppCustomization().getTracksDir()); - if (mapActivity != null && context != null) { - Snackbar snackbar = Snackbar.make(mapActivity.getLayout(), - getString(R.string.shared_string_file_is_saved, gpxFileName), - Snackbar.LENGTH_LONG) - .setAction(R.string.shared_string_undo, new View.OnClickListener() { - @Override - public void onClick(View view) { - final WeakReference mapActivityRef = new WeakReference<>(mapActivity); - final FragmentActivity fragmentActivity = mapActivityRef.get(); - SaveGPXBottomSheetFragment.showInstance(fragmentActivity.getSupportFragmentManager(), result.getFilenames()); - } - }); - View view = snackbar.getView(); - FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) view.getLayoutParams(); - params.gravity = Gravity.TOP; - AndroidUtils.setMargins(params, 0, AndroidUtils.getStatusBarHeight(context), 0, 0); - view.setLayoutParams(params); - UiUtilities.setupSnackbar(snackbar, nightMode); - snackbar.show(); - } - } - - }; + private GPXFile getGPXFile() { + return selectedGpxFile.getGpxFile(); + } public void setSelectedGpxFile(SelectedGpxFile selectedGpxFile) { this.selectedGpxFile = selectedGpxFile; @@ -153,57 +128,30 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen public void createMenuItems(Bundle savedInstanceState) { app = requiredMyApplication(); settings = app.getSettings(); + helper = app.getSavingTrackHelper(); LayoutInflater inflater = UiUtilities.getInflater(getContext(), nightMode); final FragmentManager fragmentManager = getFragmentManager(); - final Fragment targetFragment = getTargetFragment(); View itemView = inflater.inflate(R.layout.trip_recording_active_fragment, null, false); items.add(new BottomSheetItemWithDescription.Builder() .setCustomView(itemView) .create()); - long timeTrackSaved = app.getSavingTrackHelper().getLastTimeUpdated(); - SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy HH:mm:ss:SSS Z"); - sdf.setTimeZone(TimeZone.getTimeZone("GMT")); - Date resultDate = new Date(timeTrackSaved); - String sdfFormatted = sdf.format(resultDate); - CharSequence formattedTimeTrackSaved = null; - try { - long time = sdf.parse(sdfFormatted).getTime(); - long now = System.currentTimeMillis(); - formattedTimeTrackSaved = - DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS); - } catch (ParseException e) { - e.printStackTrace(); - } - View buttonClear = itemView.findViewById(R.id.button_clear); View buttonStart = itemView.findViewById(R.id.button_start); - View buttonSave = itemView.findViewById(R.id.button_save); + buttonSave = itemView.findViewById(R.id.button_save); final View buttonPause = itemView.findViewById(R.id.button_pause); View buttonStop = itemView.findViewById(R.id.button_stop); createItem(buttonClear, ItemType.CLEAR_DATA, hasDataToSave, null); createItem(buttonStart, ItemType.START_SEGMENT, wasTrackMonitored, null); - createItem(buttonSave, ItemType.SAVE, hasDataToSave, (String) formattedTimeTrackSaved); +// createItem(buttonSave, ItemType.SAVE, hasDataToSave, getTimeTrackSaved()); createItem(buttonPause, wasTrackMonitored ? ItemType.PAUSE : ItemType.RESUME, true, null); createItem(buttonStop, ItemType.STOP, true, null); statusContainer = itemView.findViewById(R.id.status_container); updateStatus(); - // todo example, need to check - buttonPause.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - boolean wasTrackMonitored = !settings.SAVE_GLOBAL_TRACK_TO_GPX.get(); - createItem(buttonPause, wasTrackMonitored ? ItemType.PAUSE : ItemType.RESUME, true, null); - TripRecordingActiveBottomSheet.this.wasTrackMonitored = wasTrackMonitored; - settings.SAVE_GLOBAL_TRACK_TO_GPX.set(wasTrackMonitored); - updateStatus(); - } - }); - RecyclerView statBlocks = itemView.findViewById(R.id.block_statistics); blockStatisticsBuilder = new GpxBlockStatisticsBuilder(app, selectedGpxFile, null); blockStatisticsBuilder.setBlocksView(statBlocks); @@ -265,11 +213,49 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen } }); + buttonClear.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (fragmentManager != null && hasDataToSave) { + ClearRecordedDataBottomSheetFragment.showInstance(fragmentManager, TripRecordingActiveBottomSheet.this); + } + } + }); + + buttonStart.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (wasTrackMonitored) { + + } + } + }); + + setSaveListener(); buttonSave.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - final GPXUtilities.GPXFile gpxFile = app.getSavingTrackHelper().getCurrentTrack().getGpxFile(); - new SaveCurrentTrackTask(app, gpxFile, saveGpxListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + if (hasDataToSave) { + final GPXFile gpxFile = getGPXFile(); + new SaveCurrentTrackTask(app, gpxFile, saveGpxListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + } + }); + + // todo example, need to check + buttonPause.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + boolean wasTrackMonitored = !settings.SAVE_GLOBAL_TRACK_TO_GPX.get(); + createItem(buttonPause, wasTrackMonitored ? ItemType.PAUSE : ItemType.RESUME, true, null); + if (!wasTrackMonitored) { + blockStatisticsBuilder.stopUpdatingStatBlocks(); + } else { + blockStatisticsBuilder.runUpdatingStatBlocks(); + } + TripRecordingActiveBottomSheet.this.wasTrackMonitored = wasTrackMonitored; + settings.SAVE_GLOBAL_TRACK_TO_GPX.set(wasTrackMonitored); + updateStatus(); } }); @@ -277,16 +263,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen @Override public void onClick(View v) { if (fragmentManager != null) { - StopTrackRecordingBottomFragment.showInstance(fragmentManager, targetFragment); - } - } - }); - - buttonClear.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (fragmentManager != null) { - ClearRecordedDataBottomSheetFragment.showInstance(fragmentManager, targetFragment); + StopTrackRecordingBottomFragment.showInstance(fragmentManager, TripRecordingActiveBottomSheet.this); } } }); @@ -314,7 +291,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen type.setTintedIcon(icon, app, enabled, false, nightMode); } - TextView title = view.findViewById(R.id.title); + TextView title = view.findViewById(R.id.button_text); if (title != null) { title.setText(type.getTitleId()); type.setTextColor(title, app, enabled, false, nightMode); @@ -333,11 +310,29 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen } } + private String getTimeTrackSaved() { + long timeTrackSaved = helper.getLastTimeUpdated(); + SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy HH:mm:ss:SSS Z", Locale.getDefault()); + sdf.setTimeZone(TimeZone.getTimeZone("GMT")); + Date resultDate = new Date(timeTrackSaved); + String sdfFormatted = sdf.format(resultDate); + CharSequence formattedTimeTrackSaved = null; + try { + long time = sdf.parse(sdfFormatted).getTime(); + long now = System.currentTimeMillis(); + formattedTimeTrackSaved = DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS); + } catch (ParseException e) { + log.error(e); + } + return String.valueOf(formattedTimeTrackSaved); + } + @Override public void onResume() { super.onResume(); blockStatisticsBuilder.runUpdatingStatBlocks(); runUpdatingGPS(); + runUpdatingTimeTrackSaved(); } @Override @@ -345,6 +340,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen super.onPause(); blockStatisticsBuilder.stopUpdatingStatBlocks(); stopUpdatingGPS(); + stopUpdatingTimeTrackSaved(); } public void stopUpdatingGPS() { @@ -366,6 +362,61 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen handler.post(updatingGPS); } + public void stopUpdatingTimeTrackSaved() { + handler.removeCallbacks(updatingTimeTrackSaved); + } + + public void runUpdatingTimeTrackSaved() { + updatingTimeTrackSaved = new Runnable() { + @Override + public void run() { + String time = getTimeTrackSaved(); + createItem(buttonSave, ItemType.SAVE, hasDataToSave, !Algorithms.isEmpty(time) ? time : null); + handler.postDelayed(this, 60000); + } + }; + handler.post(updatingTimeTrackSaved); + } + + private void setSaveListener() { + if (saveGpxListener == null) { + saveGpxListener = new SaveGpxListener() { + + @Override + public void gpxSavingStarted() { + } + + @Override + public void gpxSavingFinished(Exception errorMessage) { + String gpxFileName = Algorithms.getFileWithoutDirs(getGPXFile().path); + final MapActivity mapActivity = getMapActivity(); + final Context context = getContext(); + final SaveGpxResult result = helper.saveDataToGpx(app.getAppCustomization().getTracksDir()); + if (mapActivity != null && context != null) { + Snackbar snackbar = Snackbar.make(mapActivity.getLayout(), + getString(R.string.shared_string_file_is_saved, gpxFileName), + Snackbar.LENGTH_LONG) + .setAction(R.string.shared_string_undo, new View.OnClickListener() { + @Override + public void onClick(View view) { + final WeakReference mapActivityRef = new WeakReference<>(mapActivity); + final FragmentActivity fragmentActivity = mapActivityRef.get(); + SaveGPXBottomSheetFragment.showInstance(fragmentActivity.getSupportFragmentManager(), result.getFilenames()); + } + }); + View view = snackbar.getView(); + FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) view.getLayoutParams(); + params.gravity = Gravity.TOP; + AndroidUtils.setMargins(params, 0, AndroidUtils.getStatusBarHeight(context), 0, 0); + view.setLayoutParams(params); + UiUtilities.setupSnackbar(snackbar, nightMode); + snackbar.show(); + } + } + }; + } + } + @Nullable public MapActivity getMapActivity() { Activity activity = getActivity(); @@ -375,6 +426,13 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen return null; } + public void show() { + Dialog dialog = getDialog(); + if (dialog != null) { + dialog.show(); + } + } + public void hide() { Dialog dialog = getDialog(); if (dialog != null) { @@ -443,7 +501,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen if (tv != null) { tv.setTextColor(ContextCompat.getColor(context, enabled ? pressed ? getPressedColorId(nightMode) - : equals(ItemType.CLEAR_DATA) ? R.color.color_osm_edit_delete + : this == ItemType.CLEAR_DATA ? R.color.color_osm_edit_delete : getActiveTextColorId(nightMode) : getSecondaryTextColorId(nightMode))); } } @@ -452,10 +510,15 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen if (iv != null) { int iconColor = ContextCompat.getColor(context, enabled ? pressed ? getPressedColorId(nightMode) - : equals(ItemType.CLEAR_DATA) ? R.color.color_osm_edit_delete + : this == ItemType.CLEAR_DATA ? R.color.color_osm_edit_delete : getActiveIconColorId(nightMode) : getSecondaryIconColorId(nightMode)); Drawable icon = UiUtilities.createTintedDrawable(context, iconId, iconColor); iv.setImageDrawable(icon); + if (this == ItemType.STOP) { + int stopSize = iv.getResources().getDimensionPixelSize(R.dimen.bottom_sheet_icon_margin_large); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(stopSize, stopSize); + iv.setLayoutParams(params); + } } } diff --git a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingBottomSheet.java b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingBottomSheet.java index 178e662176..6653b6f5c3 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingBottomSheet.java @@ -28,6 +28,7 @@ import net.osmand.AndroidUtils; import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile; import net.osmand.plus.NavigationService; import net.osmand.plus.OsmandApplication; +import net.osmand.plus.OsmandPlugin; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; import net.osmand.plus.UiUtilities.DialogButtonType; @@ -246,12 +247,12 @@ public class TripRecordingBottomSheet extends MenuBottomSheetDialogFragment { } @Override - protected int getRightButtonHeight(){ + protected int getRightButtonHeight() { return getResources().getDimensionPixelSize(R.dimen.bottom_sheet_cancel_button_height); } @Override - protected int getDismissButtonHeight(){ + protected int getDismissButtonHeight() { return getResources().getDimensionPixelSize(R.dimen.bottom_sheet_cancel_button_height); } @@ -280,6 +281,9 @@ public class TripRecordingBottomSheet extends MenuBottomSheetDialogFragment { app.getSavingTrackHelper().startNewSegment(); settings.SAVE_GLOBAL_TRACK_TO_GPX.set(true); app.startNavigationService(NavigationService.USED_BY_GPX); + OsmandMonitoringPlugin plugin = OsmandPlugin.getEnabledPlugin(OsmandMonitoringPlugin.class); + TripRecordingActiveBottomSheet.showInstance(getMapActivity().getSupportFragmentManager(), + plugin.getCurrentTrack(), plugin.isWasTrackMonitored(), plugin.isHasDataToSave(), plugin.isSearchingGPS()); dismiss(); } diff --git a/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java b/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java index a7b23e18ec..3421a46a10 100644 --- a/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java +++ b/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java @@ -89,6 +89,7 @@ public class GpxBlockStatisticsBuilder { if (bsAdapter != null) { initItems(); bsAdapter.setItems(items); + AndroidUiHelper.updateVisibility(blocksView, !Algorithms.isEmpty(items)); } int interval = app.getSettings().SAVE_GLOBAL_TRACK_INTERVAL.get(); handler.postDelayed(this, Math.max(1000, interval)); @@ -272,7 +273,7 @@ public class GpxBlockStatisticsBuilder { public void setItems(List statBlocks) { this.statBlocks.clear(); this.statBlocks.addAll(statBlocks); - notifyItemRangeChanged(0, getItemCount()); + notifyDataSetChanged(); } } diff --git a/OsmAnd/src/net/osmand/plus/track/TrackAppearanceFragment.java b/OsmAnd/src/net/osmand/plus/track/TrackAppearanceFragment.java index 522103ac02..0ad5475337 100644 --- a/OsmAnd/src/net/osmand/plus/track/TrackAppearanceFragment.java +++ b/OsmAnd/src/net/osmand/plus/track/TrackAppearanceFragment.java @@ -44,6 +44,7 @@ import net.osmand.plus.dialogs.GpxAppearanceAdapter; import net.osmand.plus.dialogs.GpxAppearanceAdapter.AppearanceListItem; import net.osmand.plus.dialogs.GpxAppearanceAdapter.GpxAppearanceAdapterType; import net.osmand.plus.helpers.AndroidUiHelper; +import net.osmand.plus.monitoring.TripRecordingActiveBottomSheet; import net.osmand.plus.monitoring.TripRecordingBottomSheet; import net.osmand.plus.routepreparationmenu.cards.BaseCard; import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener; @@ -383,6 +384,8 @@ public class TrackAppearanceFragment extends ContextMenuScrollFragment implement Fragment target = getTargetFragment(); if (target instanceof TripRecordingBottomSheet) { ((TripRecordingBottomSheet) target).show(); + } else if (target instanceof TripRecordingActiveBottomSheet) { + ((TripRecordingActiveBottomSheet) target).show(); } } From ddce9bf9555cb6377385f41fe18635b56f728fc6 Mon Sep 17 00:00:00 2001 From: androiddevkotlin <64539346+androiddevkotlin@users.noreply.github.com> Date: Tue, 9 Feb 2021 10:05:01 +0200 Subject: [PATCH 12/45] Rename snackbar button --- .../osmand/plus/monitoring/TripRecordingActiveBottomSheet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java index 775bbac87c..bcc7fa7cf0 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java @@ -396,7 +396,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen Snackbar snackbar = Snackbar.make(mapActivity.getLayout(), getString(R.string.shared_string_file_is_saved, gpxFileName), Snackbar.LENGTH_LONG) - .setAction(R.string.shared_string_undo, new View.OnClickListener() { + .setAction(R.string.shared_string_rename, new View.OnClickListener() { @Override public void onClick(View view) { final WeakReference mapActivityRef = new WeakReference<>(mapActivity); From e226eab08b56250506b7622f507430a15ebace92 Mon Sep 17 00:00:00 2001 From: androiddevkotlin <64539346+androiddevkotlin@users.noreply.github.com> Date: Tue, 9 Feb 2021 15:36:37 +0200 Subject: [PATCH 13/45] First segment recalculation --- .../plus/activities/MapActivityActions.java | 5 ++ .../FollowTrackFragment.java | 4 +- .../osmand/plus/routing/RouteProvider.java | 74 ++++++++++++++----- 3 files changed, 64 insertions(+), 19 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java index 258ed7be38..19d9d93ba3 100644 --- a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java +++ b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java @@ -515,6 +515,10 @@ public class MapActivityActions implements DialogProvider { } public void setGPXRouteParams(GPXFile result) { + setGPXRouteParams(result, -1); + } + + public void setGPXRouteParams(GPXFile result, int selectedSegment) { if (result == null) { mapActivity.getRoutingHelper().setGpxParams(null); settings.FOLLOW_THE_GPX_ROUTE.set(null); @@ -522,6 +526,7 @@ public class MapActivityActions implements DialogProvider { GPXRouteParamsBuilder params = new GPXRouteParamsBuilder(result, settings); params.setCalculateOsmAndRouteParts(settings.GPX_ROUTE_CALC_OSMAND_PARTS.get()); params.setCalculateOsmAndRoute(settings.GPX_ROUTE_CALC.get()); + params.setSelectedSegment(selectedSegment); List ps = params.getPoints(settings.getContext()); mapActivity.getRoutingHelper().setGpxParams(params); settings.FOLLOW_THE_GPX_ROUTE.set(result.path); diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/FollowTrackFragment.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/FollowTrackFragment.java index b4bd04037e..f9cab5f518 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/FollowTrackFragment.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/FollowTrackFragment.java @@ -502,6 +502,8 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca updateSelectionMode(false); } else { TrackSelectSegmentBottomSheet.showInstance(fragmentManager, selectedGpxFile); + selectTrackToFollow(selectedGpxFile.getGpxFile()); + updateSelectionMode(true); } } else { CallbackWithObject callback = new CallbackWithObject() { @@ -530,7 +532,7 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca app.initVoiceCommandPlayer(mapActivity, mode, true, null, false, false, true); } } - mapActivity.getMapActions().setGPXRouteParams(gpxFile); + mapActivity.getMapActions().setGPXRouteParams(gpxFile, 1); app.getTargetPointsHelper().updateRouteAndRefresh(true); app.getRoutingHelper().onSettingsChanged(true); } diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java index 96bb1b19dc..3b4515136b 100644 --- a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java +++ b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java @@ -20,15 +20,15 @@ import net.osmand.data.LatLon; import net.osmand.data.LocationPoint; import net.osmand.data.WptLocationPoint; import net.osmand.plus.OsmandApplication; -import net.osmand.plus.onlinerouting.OnlineRoutingHelper; -import net.osmand.plus.onlinerouting.OnlineRoutingResponse; -import net.osmand.plus.settings.backend.OsmandSettings; -import net.osmand.plus.settings.backend.CommonPreference; import net.osmand.plus.R; import net.osmand.plus.TargetPointsHelper; import net.osmand.plus.TargetPointsHelper.TargetPoint; +import net.osmand.plus.onlinerouting.OnlineRoutingHelper; +import net.osmand.plus.onlinerouting.OnlineRoutingResponse; import net.osmand.plus.render.NativeOsmandLibrary; import net.osmand.plus.settings.backend.ApplicationMode; +import net.osmand.plus.settings.backend.CommonPreference; +import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.router.GeneralRouter; import net.osmand.router.GeneralRouter.RoutingParameter; import net.osmand.router.GeneralRouter.RoutingParameterType; @@ -161,6 +161,7 @@ public class RouteProvider { private boolean leftSide; private boolean passWholeRoute; private boolean calculateOsmAndRouteParts; + private int selectedSegment = -1; public GPXRouteParamsBuilder(GPXFile file, OsmandSettings settings) { leftSide = settings.DRIVING_REGION.get().leftHandDriving; @@ -191,6 +192,14 @@ public class RouteProvider { this.calculateOsmAndRoute = calculateOsmAndRoute; } + public int getSelectedSegment() { + return selectedSegment; + } + + public void setSelectedSegment(int selectedSegment) { + this.selectedSegment = selectedSegment; + } + public void setPassWholeRoute(boolean passWholeRoute) { this.passWholeRoute = passWholeRoute; } @@ -235,6 +244,7 @@ public class RouteProvider { boolean calculateOsmAndRouteParts; boolean useIntermediatePointsRTE; private List wpt; + int selectedSegment = -1; boolean addMissingTurns = true; @@ -271,6 +281,7 @@ public class RouteProvider { passWholeRoute = builder.passWholeRoute; calculateOsmAndRouteParts = builder.calculateOsmAndRouteParts; useIntermediatePointsRTE = builder.isUseIntermediatePointsRTE(); + selectedSegment = builder.getSelectedSegment(); builder.calculateOsmAndRoute = false; // Disabled temporary builder.calculateOsmAndRoute; if (!file.isPointsEmpty()) { wpt = new ArrayList(file.getPoints().size()); @@ -279,7 +290,7 @@ public class RouteProvider { } } if (OSMAND_ROUTER_V2.equals(file.author)) { - route = parseOsmAndGPXRoute(points, file); + route = parseOsmAndGPXRoute(points, file, selectedSegment); routePoints = file.getRoutePoints(); if (reverse) { Collections.reverse(points); @@ -287,7 +298,7 @@ public class RouteProvider { } addMissingTurns = route != null && route.isEmpty(); } else if (file.isCloudmadeRouteFile() || OSMAND_ROUTER.equals(file.author)) { - directions = parseOsmAndGPXRoute(points, file, OSMAND_ROUTER.equals(file.author), builder.leftSide, 10); + directions = parseOsmAndGPXRoute(points, file, OSMAND_ROUTER.equals(file.author), builder.leftSide, 10, selectedSegment); if (OSMAND_ROUTER.equals(file.author) && file.hasRtePt()) { // For files generated by OSMAND_ROUTER use directions contained unaltered addMissingTurns = false; @@ -303,7 +314,14 @@ public class RouteProvider { if (!useIntermediatePointsRTE) { for (Track tr : file.tracks) { if (!tr.generalTrack) { - for (TrkSegment tkSeg : tr.segments) { + if (selectedSegment == -1) { + for (TrkSegment tkSeg : tr.segments) { + for (WptPt pt : tkSeg.points) { + points.add(createLocation(pt)); + } + } + } else if (tr.segments.size() > selectedSegment) { + TrkSegment tkSeg = tr.segments.get(selectedSegment); for (WptPt pt : tkSeg.points) { points.add(createLocation(pt)); } @@ -998,20 +1016,33 @@ public class RouteProvider { return new RouteCalculationResult("Empty result"); } - private static List parseOsmAndGPXRoute(List points, GPXFile gpxFile) { + private static List parseOsmAndGPXRoute(List points, GPXFile gpxFile, int selectedSegment) { for (Track tr : gpxFile.tracks) { - for (TrkSegment ts : tr.segments) { - for (WptPt p : ts.points) { - points.add(createLocation(p)); + if (selectedSegment == -1) { + for (TrkSegment ts : tr.segments) { + for (WptPt p : ts.points) { + points.add(createLocation(p)); + } + } + } else if (tr.segments.size() > selectedSegment) { + TrkSegment ts = tr.segments.get(selectedSegment); + for (WptPt pt : ts.points) { + points.add(createLocation(pt)); } } } - RouteImporter routeImporter = new RouteImporter(gpxFile); - return routeImporter.importRoute(); + List segments = gpxFile.getNonEmptyTrkSegments(true); + if (selectedSegment>=0&&segments.size() > selectedSegment) { + RouteImporter routeImporter = new RouteImporter(segments.get(selectedSegment)); + return routeImporter.importRoute(); + } else { + RouteImporter routeImporter = new RouteImporter(gpxFile); + return routeImporter.importRoute(); + } } private static List parseOsmAndGPXRoute(List points, GPXFile gpxFile, boolean osmandRouter, - boolean leftSide, float defSpeed) { + boolean leftSide, float defSpeed, int selectedSegment) { List directions = null; if (!osmandRouter) { for (WptPt pt : gpxFile.getPoints()) { @@ -1019,9 +1050,16 @@ public class RouteProvider { } } else { for (Track tr : gpxFile.tracks) { - for (TrkSegment ts : tr.segments) { - for (WptPt p : ts.points) { - points.add(createLocation(p)); + if (selectedSegment == -1) { + for (TrkSegment ts : tr.segments) { + for (WptPt p : ts.points) { + points.add(createLocation(p)); + } + } + } else if (tr.segments.size() > selectedSegment) { + TrkSegment ts = tr.segments.get(selectedSegment); + for (WptPt pt : ts.points) { + points.add(createLocation(pt)); } } } @@ -1307,7 +1345,7 @@ public class RouteProvider { GPXFile gpxFile = GPXUtilities.loadGPXFile(gpxStream); - dir = parseOsmAndGPXRoute(res, gpxFile, true, params.leftSide, params.mode.getDefaultSpeed()); + dir = parseOsmAndGPXRoute(res, gpxFile, true, params.leftSide, params.mode.getDefaultSpeed(), -1); if (dir != null) { addMissingTurns = false; From c36d007b5c169051a9e7e3329c7ab8bc6c31a596 Mon Sep 17 00:00:00 2001 From: Skalii Date: Wed, 10 Feb 2021 16:04:25 +0200 Subject: [PATCH 14/45] fix ability to click on statistics blocks; add functionality of the button "start new segment"; add snackbar with file rename to "save and stop recording" button; some fixes; --- .../StopTrackRecordingBottomFragment.java | 22 ++++- .../TripRecordingActiveBottomSheet.java | 92 +++++++++---------- .../plus/track/GpxBlockStatisticsBuilder.java | 10 +- 3 files changed, 72 insertions(+), 52 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java b/OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java index 5172bfc1bf..fd28bd7431 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java @@ -1,12 +1,13 @@ package net.osmand.plus.monitoring; -import android.app.Dialog; import android.content.Context; +import android.os.AsyncTask; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.widget.LinearLayout; +import net.osmand.GPXUtilities.GPXFile; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandPlugin; import net.osmand.plus.R; @@ -15,7 +16,9 @@ import net.osmand.plus.UiUtilities.DialogButtonType; import net.osmand.plus.base.MenuBottomSheetDialogFragment; import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem; import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription; +import net.osmand.plus.myplaces.SaveCurrentTrackTask; import net.osmand.plus.settings.backend.OsmandSettings; +import net.osmand.plus.track.SaveGpxAsyncTask.SaveGpxListener; import net.osmand.plus.widgets.TextViewEx; import androidx.annotation.DimenRes; @@ -33,6 +36,16 @@ public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragm private OsmandApplication app; private OsmandSettings settings; private OsmandMonitoringPlugin plugin; + private GPXFile gpxFile; + private SaveGpxListener saveGpxListener; + + public void setGpxFile(GPXFile gpxFile) { + this.gpxFile = gpxFile; + } + + public void setSaveGpxListener(SaveGpxListener saveGpxListener) { + this.saveGpxListener = saveGpxListener; + } @Override public void createMenuItems(Bundle savedInstanceState) { @@ -118,7 +131,8 @@ public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragm app.getSavingTrackHelper().clearRecordedData(true); } else if (tag == ButtonType.SAVE_AND_STOP) { if (plugin != null && settings.SAVE_GLOBAL_TRACK_TO_GPX.get()) { - plugin.saveCurrentTrack(); + new SaveCurrentTrackTask(app, gpxFile, saveGpxListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + plugin.stopRecording(); app.getNotificationHelper().refreshNotifications(); } } @@ -169,9 +183,11 @@ public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragm return true; } - public static void showInstance(@NonNull FragmentManager fragmentManager, @NonNull Fragment target) { + public static void showInstance(GPXFile gpxFile, SaveGpxListener saveGpxListener, @NonNull FragmentManager fragmentManager, @NonNull Fragment target) { if (!fragmentManager.isStateSaved()) { StopTrackRecordingBottomFragment fragment = new StopTrackRecordingBottomFragment(); + fragment.setGpxFile(gpxFile); + fragment.setSaveGpxListener(saveGpxListener); fragment.setTargetFragment(target, 0); fragment.show(fragmentManager, TAG); } diff --git a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java index bcc7fa7cf0..7c0f10a10f 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java @@ -90,7 +90,6 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen private final Handler handler = new Handler(); private Runnable updatingGPS; private Runnable updatingTimeTrackSaved; - private SaveGpxListener saveGpxListener; private GPXFile getGPXFile() { return selectedGpxFile.getGpxFile(); @@ -145,7 +144,6 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen createItem(buttonClear, ItemType.CLEAR_DATA, hasDataToSave, null); createItem(buttonStart, ItemType.START_SEGMENT, wasTrackMonitored, null); -// createItem(buttonSave, ItemType.SAVE, hasDataToSave, getTimeTrackSaved()); createItem(buttonPause, wasTrackMonitored ? ItemType.PAUSE : ItemType.RESUME, true, null); createItem(buttonStop, ItemType.STOP, true, null); @@ -153,8 +151,9 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen updateStatus(); RecyclerView statBlocks = itemView.findViewById(R.id.block_statistics); - blockStatisticsBuilder = new GpxBlockStatisticsBuilder(app, selectedGpxFile, null); + blockStatisticsBuilder = new GpxBlockStatisticsBuilder(app, selectedGpxFile); blockStatisticsBuilder.setBlocksView(statBlocks); + blockStatisticsBuilder.setBlocksClickable(false); blockStatisticsBuilder.initStatBlocks(null, ContextCompat.getColor(app, getActiveTextColorId(nightMode)), nightMode); LinearLayout showTrackOnMapView = itemView.findViewById(R.id.show_track_on_map); @@ -226,18 +225,17 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen @Override public void onClick(View v) { if (wasTrackMonitored) { - + helper.startNewSegment(); } } }); - setSaveListener(); buttonSave.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (hasDataToSave) { final GPXFile gpxFile = getGPXFile(); - new SaveCurrentTrackTask(app, gpxFile, saveGpxListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + new SaveCurrentTrackTask(app, gpxFile, createSaveListener()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } } }); @@ -263,7 +261,8 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen @Override public void onClick(View v) { if (fragmentManager != null) { - StopTrackRecordingBottomFragment.showInstance(fragmentManager, TripRecordingActiveBottomSheet.this); + final GPXFile gpxFile = getGPXFile(); + StopTrackRecordingBottomFragment.showInstance(gpxFile, createSaveListener(), fragmentManager, TripRecordingActiveBottomSheet.this); } } }); @@ -307,6 +306,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen AndroidUiHelper.updateVisibility(desc, isShowDesc); UiUtilities.setMargins(title, 0, marginDesc, 0, marginDesc); desc.setText(description); + type.setTextColor(desc, app, false, false, nightMode); } } @@ -378,43 +378,41 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen handler.post(updatingTimeTrackSaved); } - private void setSaveListener() { - if (saveGpxListener == null) { - saveGpxListener = new SaveGpxListener() { + private SaveGpxListener createSaveListener() { + return new SaveGpxListener() { - @Override - public void gpxSavingStarted() { - } + @Override + public void gpxSavingStarted() { + } - @Override - public void gpxSavingFinished(Exception errorMessage) { - String gpxFileName = Algorithms.getFileWithoutDirs(getGPXFile().path); - final MapActivity mapActivity = getMapActivity(); - final Context context = getContext(); - final SaveGpxResult result = helper.saveDataToGpx(app.getAppCustomization().getTracksDir()); - if (mapActivity != null && context != null) { - Snackbar snackbar = Snackbar.make(mapActivity.getLayout(), - getString(R.string.shared_string_file_is_saved, gpxFileName), - Snackbar.LENGTH_LONG) - .setAction(R.string.shared_string_rename, new View.OnClickListener() { - @Override - public void onClick(View view) { - final WeakReference mapActivityRef = new WeakReference<>(mapActivity); - final FragmentActivity fragmentActivity = mapActivityRef.get(); - SaveGPXBottomSheetFragment.showInstance(fragmentActivity.getSupportFragmentManager(), result.getFilenames()); - } - }); - View view = snackbar.getView(); - FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) view.getLayoutParams(); - params.gravity = Gravity.TOP; - AndroidUtils.setMargins(params, 0, AndroidUtils.getStatusBarHeight(context), 0, 0); - view.setLayoutParams(params); - UiUtilities.setupSnackbar(snackbar, nightMode); - snackbar.show(); - } + @Override + public void gpxSavingFinished(Exception errorMessage) { + String gpxFileName = Algorithms.getFileWithoutDirs(getGPXFile().path); + final MapActivity mapActivity = getMapActivity(); + final Context context = getContext(); + final SaveGpxResult result = helper.saveDataToGpx(app.getAppCustomization().getTracksDir()); + if (mapActivity != null && context != null) { + Snackbar snackbar = Snackbar.make(mapActivity.getLayout(), + getString(R.string.shared_string_file_is_saved, gpxFileName), + Snackbar.LENGTH_LONG) + .setAction(R.string.shared_string_rename, new View.OnClickListener() { + @Override + public void onClick(View view) { + final WeakReference mapActivityRef = new WeakReference<>(mapActivity); + final FragmentActivity fragmentActivity = mapActivityRef.get(); + SaveGPXBottomSheetFragment.showInstance(fragmentActivity.getSupportFragmentManager(), result.getFilenames()); + } + }); + View view = snackbar.getView(); + FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) view.getLayoutParams(); + params.gravity = Gravity.TOP; + AndroidUtils.setMargins(params, 0, AndroidUtils.getStatusBarHeight(context), 0, 0); + view.setLayoutParams(params); + UiUtilities.setupSnackbar(snackbar, nightMode); + snackbar.show(); } - }; - } + } + }; } @Nullable @@ -508,12 +506,12 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen public void setTintedIcon(AppCompatImageView iv, Context context, boolean enabled, boolean pressed, boolean nightMode) { if (iv != null) { - int iconColor = ContextCompat.getColor(context, - enabled ? pressed ? getPressedColorId(nightMode) - : this == ItemType.CLEAR_DATA ? R.color.color_osm_edit_delete - : getActiveIconColorId(nightMode) : getSecondaryIconColorId(nightMode)); - Drawable icon = UiUtilities.createTintedDrawable(context, iconId, iconColor); - iv.setImageDrawable(icon); + Drawable icon = AppCompatResources.getDrawable(context, iconId); + int iconColor = enabled ? pressed ? getPressedColorId(nightMode) + : this == ItemType.CLEAR_DATA ? R.color.color_osm_edit_delete + : getActiveIconColorId(nightMode) : getSecondaryIconColorId(nightMode); + Drawable tintedIcon = UiUtilities.tintDrawable(icon, ContextCompat.getColor(context, iconColor)); + iv.setImageDrawable(tintedIcon); if (this == ItemType.STOP) { int stopSize = iv.getResources().getDimensionPixelSize(R.dimen.bottom_sheet_icon_margin_large); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(stopSize, stopSize); diff --git a/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java b/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java index 0e005b0d8c..3c06eb8882 100644 --- a/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java +++ b/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java @@ -11,6 +11,7 @@ import androidx.annotation.ColorInt; import androidx.annotation.ColorRes; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatImageView; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -41,6 +42,7 @@ public class GpxBlockStatisticsBuilder { private BlockStatisticsAdapter adapter; private final List items = new ArrayList<>(); + private boolean blocksClickable = true; private final Handler handler = new Handler(); private Runnable updatingItems; @@ -51,6 +53,10 @@ public class GpxBlockStatisticsBuilder { this.selectedGpxFile = selectedGpxFile; } + public void setBlocksClickable(boolean blocksClickable) { + this.blocksClickable = blocksClickable; + } + public void setBlocksView(RecyclerView blocksView) { this.blocksView = blocksView; } @@ -63,7 +69,7 @@ public class GpxBlockStatisticsBuilder { return selectedGpxFile.getGpxFile(); } - public void initStatBlocks(SegmentActionsListener actionsListener, @ColorInt int activeColor, boolean nightMode) { + public void initStatBlocks(@Nullable SegmentActionsListener actionsListener, @ColorInt int activeColor, boolean nightMode) { initItems(); boolean isNotEmpty = !Algorithms.isEmpty(items); AndroidUiHelper.updateVisibility(blocksView, isNotEmpty); @@ -237,7 +243,7 @@ public class GpxBlockStatisticsBuilder { @Override public void onClick(View v) { GPXTrackAnalysis analysis = displayItem != null ? displayItem.analysis : null; - if (analysis != null) { + if (blocksClickable && analysis != null && actionsListener != null) { ArrayList list = new ArrayList<>(); if (analysis.hasElevationData || analysis.isSpeedSpecified() || analysis.hasSpeedData) { if (item.firstType != null) { From 6adbcd5ff6e21f3c5ca1b5a3057e144221f6c6ad Mon Sep 17 00:00:00 2001 From: Skalii Date: Wed, 10 Feb 2021 17:21:01 +0200 Subject: [PATCH 15/45] fix another way to show the bottom sheet with renaming and opening current track after clicking "Save and stop recording"; fix showing correct track save time; fix now after clicking the "Stop.." buttons, the track recording fragment does not open --- .../plus/activities/SavingTrackHelper.java | 2 + .../StopTrackRecordingBottomFragment.java | 35 +++++++--------- .../TripRecordingActiveBottomSheet.java | 41 ++++++++----------- .../plus/myplaces/SaveCurrentTrackTask.java | 1 + 4 files changed, 34 insertions(+), 45 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/activities/SavingTrackHelper.java b/OsmAnd/src/net/osmand/plus/activities/SavingTrackHelper.java index e173a49ad1..a5c5c74100 100644 --- a/OsmAnd/src/net/osmand/plus/activities/SavingTrackHelper.java +++ b/OsmAnd/src/net/osmand/plus/activities/SavingTrackHelper.java @@ -78,6 +78,7 @@ public class SavingTrackHelper extends SQLiteOpenHelper { private SelectedGpxFile currentTrack; private int points; private int trkPoints = 0; + public long time; public SavingTrackHelper(OsmandApplication ctx) { super(ctx, DATABASE_NAME, null, DATABASE_VERSION); @@ -255,6 +256,7 @@ public class SavingTrackHelper extends SQLiteOpenHelper { GPXTrackAnalysis analysis = gpx.getAnalysis(fout.lastModified()); GpxDataItem item = new GpxDataItem(fout, analysis); ctx.getGpxDbHelper().add(item); + time = fout.lastModified(); } } } diff --git a/OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java b/OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java index fd28bd7431..3d648f432b 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java @@ -1,24 +1,21 @@ package net.osmand.plus.monitoring; import android.content.Context; -import android.os.AsyncTask; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.widget.LinearLayout; -import net.osmand.GPXUtilities.GPXFile; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandPlugin; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; import net.osmand.plus.UiUtilities.DialogButtonType; +import net.osmand.plus.activities.MapActivity; import net.osmand.plus.base.MenuBottomSheetDialogFragment; import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem; import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription; -import net.osmand.plus.myplaces.SaveCurrentTrackTask; import net.osmand.plus.settings.backend.OsmandSettings; -import net.osmand.plus.track.SaveGpxAsyncTask.SaveGpxListener; import net.osmand.plus.widgets.TextViewEx; import androidx.annotation.DimenRes; @@ -34,17 +31,13 @@ public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragm public static final String TAG = StopTrackRecordingBottomFragment.class.getSimpleName(); private OsmandApplication app; + private MapActivity mapActivity; private OsmandSettings settings; private OsmandMonitoringPlugin plugin; - private GPXFile gpxFile; - private SaveGpxListener saveGpxListener; + private ButtonType tag = ButtonType.CANCEL; - public void setGpxFile(GPXFile gpxFile) { - this.gpxFile = gpxFile; - } - - public void setSaveGpxListener(SaveGpxListener saveGpxListener) { - this.saveGpxListener = saveGpxListener; + public void setMapActivity(MapActivity mapActivity) { + this.mapActivity = mapActivity; } @Override @@ -122,7 +115,7 @@ public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragm return; } - ButtonType tag = (ButtonType) o; + tag = (ButtonType) o; if (tag == ButtonType.STOP_AND_DISCARD) { if (plugin != null && settings.SAVE_GLOBAL_TRACK_TO_GPX.get()) { plugin.stopRecording(); @@ -131,8 +124,7 @@ public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragm app.getSavingTrackHelper().clearRecordedData(true); } else if (tag == ButtonType.SAVE_AND_STOP) { if (plugin != null && settings.SAVE_GLOBAL_TRACK_TO_GPX.get()) { - new SaveCurrentTrackTask(app, gpxFile, saveGpxListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - plugin.stopRecording(); + plugin.saveCurrentTrack(null, mapActivity); app.getNotificationHelper().refreshNotifications(); } } @@ -151,9 +143,11 @@ public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragm @Override public void onPause() { super.onPause(); - Fragment target = getTargetFragment(); - if (target instanceof TripRecordingActiveBottomSheet) { - ((TripRecordingActiveBottomSheet) target).show(); + if (tag == ButtonType.CANCEL) { + Fragment target = getTargetFragment(); + if (target instanceof TripRecordingActiveBottomSheet) { + ((TripRecordingActiveBottomSheet) target).show(); + } } } @@ -183,11 +177,10 @@ public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragm return true; } - public static void showInstance(GPXFile gpxFile, SaveGpxListener saveGpxListener, @NonNull FragmentManager fragmentManager, @NonNull Fragment target) { + public static void showInstance(MapActivity mapActivity, @NonNull FragmentManager fragmentManager, @NonNull Fragment target) { if (!fragmentManager.isStateSaved()) { StopTrackRecordingBottomFragment fragment = new StopTrackRecordingBottomFragment(); - fragment.setGpxFile(gpxFile); - fragment.setSaveGpxListener(saveGpxListener); + fragment.setMapActivity(mapActivity); fragment.setTargetFragment(target, 0); fragment.show(fragmentManager, TAG); } diff --git a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java index 7c0f10a10f..f72f736997 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java @@ -62,11 +62,6 @@ import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; import java.lang.ref.WeakReference; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; import static net.osmand.plus.UiUtilities.CompoundButtonType.PROFILE_DEPENDENT; @@ -261,8 +256,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen @Override public void onClick(View v) { if (fragmentManager != null) { - final GPXFile gpxFile = getGPXFile(); - StopTrackRecordingBottomFragment.showInstance(gpxFile, createSaveListener(), fragmentManager, TripRecordingActiveBottomSheet.this); + StopTrackRecordingBottomFragment.showInstance(getMapActivity(), fragmentManager, TripRecordingActiveBottomSheet.this); } } }); @@ -311,20 +305,14 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen } private String getTimeTrackSaved() { - long timeTrackSaved = helper.getLastTimeUpdated(); - SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy HH:mm:ss:SSS Z", Locale.getDefault()); - sdf.setTimeZone(TimeZone.getTimeZone("GMT")); - Date resultDate = new Date(timeTrackSaved); - String sdfFormatted = sdf.format(resultDate); - CharSequence formattedTimeTrackSaved = null; - try { - long time = sdf.parse(sdfFormatted).getTime(); + if (helper.time != 0) { + long timeTrackSaved = helper.time; long now = System.currentTimeMillis(); - formattedTimeTrackSaved = DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS); - } catch (ParseException e) { - log.error(e); + CharSequence time = DateUtils.getRelativeTimeSpanString(timeTrackSaved, now, DateUtils.MINUTE_IN_MILLIS); + return String.valueOf(time); + } else { + return null; } - return String.valueOf(formattedTimeTrackSaved); } @Override @@ -406,7 +394,8 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen View view = snackbar.getView(); FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) view.getLayoutParams(); params.gravity = Gravity.TOP; - AndroidUtils.setMargins(params, 0, AndroidUtils.getStatusBarHeight(context), 0, 0); + final int dp16 = AndroidUtils.dpToPx(mapActivity, 16f); + AndroidUtils.setMargins(params, 0, AndroidUtils.getStatusBarHeight(context) + dp16, 0, 0); view.setLayoutParams(params); UiUtilities.setupSnackbar(snackbar, nightMode); snackbar.show(); @@ -438,26 +427,30 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen } } - private static void setItemBackgroundActive(LinearLayout view, Context context, boolean nightMode) { + private static void setItemBackgroundActive(LinearLayout view, Context context, + boolean nightMode) { Drawable background = AppCompatResources.getDrawable(context, nightMode ? R.drawable.btn_background_active_dark : R.drawable.btn_background_active_light); view.setBackgroundDrawable(background); } - private static void setItemBackgroundInactive(LinearLayout view, Context context, boolean nightMode) { + private static void setItemBackgroundInactive(LinearLayout view, Context context, + boolean nightMode) { Drawable background = AppCompatResources.getDrawable(context, nightMode ? R.drawable.btn_background_inactive_dark : R.drawable.btn_background_inactive_light); view.setBackgroundDrawable(background); } - private static void setShowOnMapBackgroundActive(LinearLayout view, Context context, boolean checked, boolean nightMode) { + private static void setShowOnMapBackgroundActive(LinearLayout view, Context context, + boolean checked, boolean nightMode) { Drawable background = AppCompatResources.getDrawable(context, nightMode ? checked ? R.drawable.btn_background_active_dark : R.drawable.btn_background_stroked_active_dark : checked ? R.drawable.btn_background_active_light : R.drawable.btn_background_stroked_active_light); view.setBackgroundDrawable(background); } - private static void setShowOnMapBackgroundInactive(LinearLayout view, Context context, boolean checked, boolean nightMode) { + private static void setShowOnMapBackgroundInactive(LinearLayout view, Context context, + boolean checked, boolean nightMode) { Drawable background = AppCompatResources.getDrawable(context, nightMode ? checked ? R.drawable.btn_background_inactive_dark : R.drawable.btn_background_stroked_inactive_dark : checked ? R.drawable.btn_background_inactive_light : R.drawable.btn_background_stroked_inactive_light); diff --git a/OsmAnd/src/net/osmand/plus/myplaces/SaveCurrentTrackTask.java b/OsmAnd/src/net/osmand/plus/myplaces/SaveCurrentTrackTask.java index 84959d17f7..843d7b7ea1 100644 --- a/OsmAnd/src/net/osmand/plus/myplaces/SaveCurrentTrackTask.java +++ b/OsmAnd/src/net/osmand/plus/myplaces/SaveCurrentTrackTask.java @@ -52,6 +52,7 @@ public class SaveCurrentTrackTask extends AsyncTask { for (final String f : files.keySet()) { File fout = new File(dir, f + IndexConstants.GPX_FILE_EXT); GPXUtilities.writeGpxFile(fout, gpx); + app.getSavingTrackHelper().time = fout.lastModified(); } return shouldClearPath; } From b7497338b3702ef37163f224577f90ab262aec70 Mon Sep 17 00:00:00 2001 From: Skalii Date: Wed, 10 Feb 2021 18:05:58 +0200 Subject: [PATCH 16/45] fix updating block statistics and time track saved after clicking "Save" button --- .../TripRecordingActiveBottomSheet.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java index f72f736997..24e2bb4843 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java @@ -230,7 +230,15 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen public void onClick(View v) { if (hasDataToSave) { final GPXFile gpxFile = getGPXFile(); - new SaveCurrentTrackTask(app, gpxFile, createSaveListener()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + new SaveCurrentTrackTask(app, gpxFile, createSaveListener(new Runnable() { + @Override + public void run() { + blockStatisticsBuilder.stopUpdatingStatBlocks(); + blockStatisticsBuilder.runUpdatingStatBlocks(); + stopUpdatingTimeTrackSaved(); + runUpdatingTimeTrackSaved(); + } + })).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } } }); @@ -366,7 +374,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen handler.post(updatingTimeTrackSaved); } - private SaveGpxListener createSaveListener() { + private SaveGpxListener createSaveListener(@Nullable final Runnable callback) { return new SaveGpxListener() { @Override @@ -399,6 +407,9 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen view.setLayoutParams(params); UiUtilities.setupSnackbar(snackbar, nightMode); snackbar.show(); + if (callback != null) { + callback.run(); + } } } }; From 26083c53a35903b5fa43b2847bf4705607f64562 Mon Sep 17 00:00:00 2001 From: Skalii Date: Wed, 10 Feb 2021 19:22:29 +0200 Subject: [PATCH 17/45] small code cleanup; --- .../plus/activities/MapActivityActions.java | 7 +-- .../monitoring/OsmandMonitoringPlugin.java | 40 ++++++----------- .../TripRecordingActiveBottomSheet.java | 45 +++++++------------ .../monitoring/TripRecordingBottomSheet.java | 9 ++-- 4 files changed, 35 insertions(+), 66 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java index b216913466..7bfcdd754b 100644 --- a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java +++ b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java @@ -22,7 +22,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.core.content.ContextCompat; -import androidx.fragment.app.FragmentActivity; import net.osmand.AndroidUtils; import net.osmand.GPXUtilities; @@ -854,10 +853,8 @@ public class MapActivityActions implements DialogProvider { public boolean onContextMenuClick(ArrayAdapter adapter, int itemId, int pos, boolean isChecked, int[] viewCoordinates) { app.logEvent("trip_recording_open"); MapActivity.clearPrevActivityIntent(); - if (monitoringPlugin.isHasDataToSave() || monitoringPlugin.isWasTrackMonitored()) { - TripRecordingActiveBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), - monitoringPlugin.getCurrentTrack(), monitoringPlugin.isWasTrackMonitored(), - monitoringPlugin.isHasDataToSave(), monitoringPlugin.isSearchingGPS()); + if (monitoringPlugin.hasDataToSave() || monitoringPlugin.wasTrackMonitored()) { + TripRecordingActiveBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), monitoringPlugin.getCurrentTrack()); } else { TripRecordingBottomSheet.showInstance(mapActivity.getSupportFragmentManager()); } diff --git a/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java b/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java index eaa54a948a..df7390af7b 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java @@ -1,9 +1,7 @@ package net.osmand.plus.monitoring; -import android.Manifest; import android.app.Activity; import android.content.Context; -import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; @@ -19,7 +17,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.AppCompatCheckBox; -import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.fragment.app.FragmentActivity; @@ -28,11 +25,9 @@ import com.google.android.material.slider.Slider; import net.osmand.AndroidUtils; import net.osmand.Location; import net.osmand.ValueHolder; -import net.osmand.plus.GpxSelectionHelper; import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile; import net.osmand.plus.NavigationService; import net.osmand.plus.OsmAndFormatter; -import net.osmand.plus.OsmAndLocationProvider; import net.osmand.plus.OsmAndTaskManager.OsmAndTaskRunnable; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandPlugin; @@ -45,7 +40,6 @@ import net.osmand.plus.dashboard.tools.DashFragmentData; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.settings.fragments.BaseSettingsFragment.SettingsScreenType; -import net.osmand.plus.track.TrackDisplayHelper; import net.osmand.plus.views.OsmandMapLayer.DrawSettings; import net.osmand.plus.views.OsmandMapTileView; import net.osmand.plus.views.layers.MapInfoLayer; @@ -55,8 +49,6 @@ import net.osmand.util.Algorithms; import java.lang.ref.WeakReference; import java.util.List; -import gnu.trove.list.array.TIntArrayList; - import static net.osmand.plus.UiUtilities.CompoundButtonType.PROFILE_DEPENDENT; public class OsmandMonitoringPlugin extends OsmandPlugin { @@ -165,9 +157,9 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { } } - public static final int[] SECONDS = new int[] {0, 1, 2, 3, 5, 10, 15, 20, 30, 60, 90}; - public static final int[] MINUTES = new int[] {2, 3, 5}; - public static final int[] MAX_INTERVAL_TO_SEND_MINUTES = new int[] {1, 2, 5, 10, 15, 20, 30, 60, 90, 2 * 60, 3 * 60, 4 * 60, 6 * 60, 12 * 60, 24 * 60}; + public static final int[] SECONDS = new int[]{0, 1, 2, 3, 5, 10, 15, 20, 30, 60, 90}; + public static final int[] MINUTES = new int[]{2, 3, 5}; + public static final int[] MAX_INTERVAL_TO_SEND_MINUTES = new int[]{1, 2, 5, 10, 15, 20, 30, 60, 90, 2 * 60, 3 * 60, 4 * 60, 6 * 60, 12 * 60, 24 * 60}; @Override public SettingsScreenType getSettingsScreenType() { @@ -185,9 +177,10 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { private TextInfoWidget createMonitoringControl(final MapActivity map) { monitoringControl = new TextInfoWidget(map) { long lastUpdateTime; + @Override public boolean updateInfo(DrawSettings drawSettings) { - if(isSaving){ + if (isSaving) { setText(map.getString(R.string.shared_string_save), ""); setIcons(R.drawable.widget_monitoring_rec_big_day, R.drawable.widget_monitoring_rec_big_night); return true; @@ -215,7 +208,7 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { } final boolean liveMonitoringEnabled = liveMonitoringHelper.isLiveMonitoringEnabled(); - if(globalRecord) { + if (globalRecord) { //indicates global recording (+background recording) if (liveMonitoringEnabled) { dn = R.drawable.widget_live_monitoring_rec_big_night; @@ -324,25 +317,18 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { return app.getSavingTrackHelper().getCurrentTrack(); } - public boolean isWasTrackMonitored() { + public boolean wasTrackMonitored() { return settings.SAVE_GLOBAL_TRACK_TO_GPX.get(); } - public boolean isHasDataToSave() { + public boolean hasDataToSave() { return app.getSavingTrackHelper().hasDataToSave(); } - public boolean isSearchingGPS() { - OsmAndLocationProvider locationProvider = app.getLocationProvider(); - Location lastKnownLocation = locationProvider.getLastKnownLocation(); - return lastKnownLocation == null; - } - public void controlDialog(final Activity activity, final boolean showTrackSelection) { - if (isHasDataToSave() || isWasTrackMonitored()) { + if (hasDataToSave() || wasTrackMonitored()) { FragmentActivity fragmentActivity = (FragmentActivity) activity; - TripRecordingActiveBottomSheet.showInstance(fragmentActivity.getSupportFragmentManager(), - getCurrentTrack(), isWasTrackMonitored(), isHasDataToSave(), isSearchingGPS()); + TripRecordingActiveBottomSheet.showInstance(fragmentActivity.getSupportFragmentManager(), getCurrentTrack()); } else { FragmentActivity fragmentActivity = (FragmentActivity) activity; TripRecordingBottomSheet.showInstance(fragmentActivity.getSupportFragmentManager()); @@ -507,7 +493,7 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { } } - public void stopRecording(){ + public void stopRecording() { settings.SAVE_GLOBAL_TRACK_TO_GPX.set(false); if (app.getNavigationService() != null) { app.getNavigationService().stopIfNeeded(app, NavigationService.USED_BY_GPX); @@ -596,11 +582,11 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) { String s; int progress = (int) value; - if(progress == 0) { + if (progress == 0) { s = uiCtx.getString(R.string.int_continuosly); v.value = 0; } else { - if(progress < secondsLength) { + if (progress < secondsLength) { s = seconds[progress] + " " + uiCtx.getString(R.string.int_seconds); v.value = seconds[progress] * 1000; } else { diff --git a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java index 24e2bb4843..7b05345608 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java @@ -37,10 +37,8 @@ import com.google.android.material.snackbar.Snackbar; import net.osmand.AndroidUtils; import net.osmand.GPXUtilities.GPXFile; -import net.osmand.Location; import net.osmand.PlatformUtil; import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile; -import net.osmand.plus.OsmAndLocationProvider; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; @@ -74,9 +72,6 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen private OsmandSettings settings; private SavingTrackHelper helper; private SelectedGpxFile selectedGpxFile; - private boolean wasTrackMonitored = false; - private boolean hasDataToSave = false; - private boolean searchingGPS = false; private View statusContainer; private View buttonSave; @@ -94,26 +89,22 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen this.selectedGpxFile = selectedGpxFile; } - public void setWasTrackMonitored(boolean wasTrackMonitored) { - this.wasTrackMonitored = wasTrackMonitored; + public boolean hasDataToSave() { + return app.getSavingTrackHelper().hasDataToSave(); } - public void setHasDataToSave(boolean hasDataToSave) { - this.hasDataToSave = hasDataToSave; + public boolean searchingGPS() { + return app.getLocationProvider().getLastKnownLocation() == null; } - public void setSearchingGPS(boolean searchingGPS) { - this.searchingGPS = searchingGPS; + public boolean wasTrackMonitored() { + return settings != null && settings.SAVE_GLOBAL_TRACK_TO_GPX.get(); } - public static void showInstance(@NonNull FragmentManager fragmentManager, SelectedGpxFile selectedGpxFile, - boolean wasTrackMonitored, boolean hasDataToSave, boolean searchingGPS) { + public static void showInstance(@NonNull FragmentManager fragmentManager, SelectedGpxFile selectedGpxFile) { if (!fragmentManager.isStateSaved()) { TripRecordingActiveBottomSheet fragment = new TripRecordingActiveBottomSheet(); fragment.setSelectedGpxFile(selectedGpxFile); - fragment.setWasTrackMonitored(wasTrackMonitored); - fragment.setHasDataToSave(hasDataToSave); - fragment.setSearchingGPS(searchingGPS); fragment.show(fragmentManager, TAG); } } @@ -137,9 +128,9 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen final View buttonPause = itemView.findViewById(R.id.button_pause); View buttonStop = itemView.findViewById(R.id.button_stop); - createItem(buttonClear, ItemType.CLEAR_DATA, hasDataToSave, null); - createItem(buttonStart, ItemType.START_SEGMENT, wasTrackMonitored, null); - createItem(buttonPause, wasTrackMonitored ? ItemType.PAUSE : ItemType.RESUME, true, null); + createItem(buttonClear, ItemType.CLEAR_DATA, hasDataToSave(), null); + createItem(buttonStart, ItemType.START_SEGMENT, wasTrackMonitored(), null); + createItem(buttonPause, wasTrackMonitored() ? ItemType.PAUSE : ItemType.RESUME, true, null); createItem(buttonStop, ItemType.STOP, true, null); statusContainer = itemView.findViewById(R.id.status_container); @@ -210,7 +201,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen buttonClear.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - if (fragmentManager != null && hasDataToSave) { + if (fragmentManager != null && hasDataToSave()) { ClearRecordedDataBottomSheetFragment.showInstance(fragmentManager, TripRecordingActiveBottomSheet.this); } } @@ -219,7 +210,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen buttonStart.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - if (wasTrackMonitored) { + if (wasTrackMonitored()) { helper.startNewSegment(); } } @@ -228,7 +219,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen buttonSave.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - if (hasDataToSave) { + if (hasDataToSave()) { final GPXFile gpxFile = getGPXFile(); new SaveCurrentTrackTask(app, gpxFile, createSaveListener(new Runnable() { @Override @@ -247,14 +238,13 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen buttonPause.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - boolean wasTrackMonitored = !settings.SAVE_GLOBAL_TRACK_TO_GPX.get(); + boolean wasTrackMonitored = !wasTrackMonitored(); createItem(buttonPause, wasTrackMonitored ? ItemType.PAUSE : ItemType.RESUME, true, null); if (!wasTrackMonitored) { blockStatisticsBuilder.stopUpdatingStatBlocks(); } else { blockStatisticsBuilder.runUpdatingStatBlocks(); } - TripRecordingActiveBottomSheet.this.wasTrackMonitored = wasTrackMonitored; settings.SAVE_GLOBAL_TRACK_TO_GPX.set(wasTrackMonitored); updateStatus(); } @@ -273,7 +263,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen private void updateStatus() { TextView statusTitle = statusContainer.findViewById(R.id.text_status); AppCompatImageView statusIcon = statusContainer.findViewById(R.id.icon_status); - ItemType status = searchingGPS ? ItemType.SEARCHING_GPS : !wasTrackMonitored ? ItemType.ON_PAUSE : ItemType.RECORDING; + ItemType status = searchingGPS() ? ItemType.SEARCHING_GPS : !wasTrackMonitored() ? ItemType.ON_PAUSE : ItemType.RECORDING; statusTitle.setText(status.getTitleId()); int colorText = status.equals(ItemType.SEARCHING_GPS) ? getSecondaryTextColorId(nightMode) : getOsmandIconColorId(nightMode); statusTitle.setTextColor(ContextCompat.getColor(app, colorText)); @@ -348,9 +338,6 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen @Override public void run() { int interval = app.getSettings().SAVE_GLOBAL_TRACK_INTERVAL.get(); - OsmAndLocationProvider locationProvider = app.getLocationProvider(); - Location lastKnownLocation = locationProvider.getLastKnownLocation(); - searchingGPS = lastKnownLocation == null; updateStatus(); handler.postDelayed(this, Math.max(1000, interval)); } @@ -367,7 +354,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen @Override public void run() { String time = getTimeTrackSaved(); - createItem(buttonSave, ItemType.SAVE, hasDataToSave, !Algorithms.isEmpty(time) ? time : null); + createItem(buttonSave, ItemType.SAVE, hasDataToSave(), !Algorithms.isEmpty(time) ? time : null); handler.postDelayed(this, 60000); } }; diff --git a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingBottomSheet.java b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingBottomSheet.java index 6653b6f5c3..bd7f98d45f 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingBottomSheet.java @@ -28,11 +28,11 @@ import net.osmand.AndroidUtils; import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile; import net.osmand.plus.NavigationService; import net.osmand.plus.OsmandApplication; -import net.osmand.plus.OsmandPlugin; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; import net.osmand.plus.UiUtilities.DialogButtonType; import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.activities.SavingTrackHelper; import net.osmand.plus.base.MenuBottomSheetDialogFragment; import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription; import net.osmand.plus.helpers.AndroidUiHelper; @@ -278,12 +278,11 @@ public class TripRecordingBottomSheet extends MenuBottomSheetDialogFragment { @Override protected void onRightBottomButtonClick() { - app.getSavingTrackHelper().startNewSegment(); + SavingTrackHelper helper = app.getSavingTrackHelper(); + helper.startNewSegment(); settings.SAVE_GLOBAL_TRACK_TO_GPX.set(true); app.startNavigationService(NavigationService.USED_BY_GPX); - OsmandMonitoringPlugin plugin = OsmandPlugin.getEnabledPlugin(OsmandMonitoringPlugin.class); - TripRecordingActiveBottomSheet.showInstance(getMapActivity().getSupportFragmentManager(), - plugin.getCurrentTrack(), plugin.isWasTrackMonitored(), plugin.isHasDataToSave(), plugin.isSearchingGPS()); + TripRecordingActiveBottomSheet.showInstance(getMapActivity().getSupportFragmentManager(), helper.getCurrentTrack()); dismiss(); } From 567c8f2a5bacf9a7b3ee184a81a29fc8b42811d4 Mon Sep 17 00:00:00 2001 From: Skalii Date: Thu, 11 Feb 2021 01:09:30 +0200 Subject: [PATCH 18/45] fix statistics blocks are immediately displayed after the start of recording; fix height of the "show on map" block when increasing the font size --- .../layout/trip_recording_active_fragment.xml | 2 +- .../TripRecordingActiveBottomSheet.java | 30 +++++++++---------- .../plus/track/GpxBlockStatisticsBuilder.java | 17 +++++------ 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/OsmAnd/res/layout/trip_recording_active_fragment.xml b/OsmAnd/res/layout/trip_recording_active_fragment.xml index df687a1bc5..630b68a5fd 100644 --- a/OsmAnd/res/layout/trip_recording_active_fragment.xml +++ b/OsmAnd/res/layout/trip_recording_active_fragment.xml @@ -77,7 +77,7 @@ android:id="@+id/show_track_on_map" layout="@layout/bottom_sheet_with_switch_divider_and_additional_button" android:layout_width="match_parent" - android:layout_height="@dimen/context_menu_buttons_bottom_height" + android:layout_height="wrap_content" android:layout_marginStart="@dimen/content_padding" android:layout_marginLeft="@dimen/content_padding" android:layout_marginTop="@dimen/content_padding_half" diff --git a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java index 7b05345608..3dd1b69b7e 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java @@ -142,10 +142,11 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen blockStatisticsBuilder.setBlocksClickable(false); blockStatisticsBuilder.initStatBlocks(null, ContextCompat.getColor(app, getActiveTextColorId(nightMode)), nightMode); - LinearLayout showTrackOnMapView = itemView.findViewById(R.id.show_track_on_map); - final LinearLayout basicItemBody = showTrackOnMapView.findViewById(R.id.basic_item_body); + LinearLayout showTrackContainer = itemView.findViewById(R.id.show_track_on_map); + showTrackContainer.setMinimumHeight(app.getResources().getDimensionPixelSize(R.dimen.bottom_sheet_list_item_height)); - TextView showTrackTitle = basicItemBody.findViewById(R.id.title); + final LinearLayout buttonShow = showTrackContainer.findViewById(R.id.basic_item_body); + TextView showTrackTitle = buttonShow.findViewById(R.id.title); showTrackTitle.setText(ItemType.SHOW_TRACK.getTitleId()); showTrackTitle.setTextColor(ContextCompat.getColor(app, getActiveIconColorId(nightMode))); showTrackTitle.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimensionPixelSize(R.dimen.default_desc_text_size)); @@ -155,24 +156,24 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen float letterSpacing = AndroidUtils.getFloatValueFromRes(app, R.dimen.description_letter_spacing); showTrackTitle.setLetterSpacing(letterSpacing); } - final SwitchCompat showTrackOnMapButton = basicItemBody.findViewById(R.id.switch_button); + final SwitchCompat showTrackOnMapButton = buttonShow.findViewById(R.id.switch_button); showTrackOnMapButton.setChecked(app.getSelectedGpxHelper().getSelectedCurrentRecordingTrack() != null); UiUtilities.setupCompoundButton(showTrackOnMapButton, nightMode, PROFILE_DEPENDENT); - final LinearLayout additionalButton = showTrackOnMapView.findViewById(R.id.additional_button); - View divider = additionalButton.getChildAt(0); + final LinearLayout buttonAppearance = showTrackContainer.findViewById(R.id.additional_button); + View divider = buttonAppearance.getChildAt(0); AndroidUiHelper.setVisibility(View.GONE, divider); int marginS = app.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_small); - UiUtilities.setMargins(additionalButton, marginS, 0, 0, 0); + UiUtilities.setMargins(buttonAppearance, marginS, 0, 0, 0); String width = settings.CURRENT_TRACK_WIDTH.get(); boolean showArrows = settings.CURRENT_TRACK_SHOW_ARROWS.get(); int color = settings.CURRENT_TRACK_COLOR.get(); Drawable appearanceDrawable = TrackAppearanceFragment.getTrackIcon(app, width, showArrows, color); - AppCompatImageView appearanceIcon = additionalButton.findViewById(R.id.icon_after_divider); + AppCompatImageView appearanceIcon = buttonAppearance.findViewById(R.id.icon_after_divider); int marginTrackIconH = app.getResources().getDimensionPixelSize(R.dimen.content_padding_small); UiUtilities.setMargins(appearanceIcon, marginTrackIconH, 0, marginTrackIconH, 0); appearanceIcon.setImageDrawable(appearanceDrawable); - additionalButton.setOnClickListener(new View.OnClickListener() { + buttonAppearance.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (showTrackOnMapButton.isChecked()) { @@ -185,16 +186,16 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen } } }); - createItem(additionalButton, ItemType.APPEARANCE, showTrackOnMapButton.isChecked(), null); - setShowOnMapBackgroundInactive(basicItemBody, app, showTrackOnMapButton.isChecked(), nightMode); - basicItemBody.setOnClickListener(new View.OnClickListener() { + createItem(buttonAppearance, ItemType.APPEARANCE, showTrackOnMapButton.isChecked(), null); + setShowOnMapBackgroundInactive(buttonShow, app, showTrackOnMapButton.isChecked(), nightMode); + buttonShow.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { boolean checked = !showTrackOnMapButton.isChecked(); showTrackOnMapButton.setChecked(checked); app.getSelectedGpxHelper().selectGpxFile(app.getSavingTrackHelper().getCurrentGpx(), checked, false); - setShowOnMapBackgroundInactive(basicItemBody, app, checked, nightMode); - createItem(additionalButton, ItemType.APPEARANCE, checked, null); + setShowOnMapBackgroundInactive(buttonShow, app, checked, nightMode); + createItem(buttonAppearance, ItemType.APPEARANCE, checked, null); } }); @@ -234,7 +235,6 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen } }); - // todo example, need to check buttonPause.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java b/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java index 3c06eb8882..51ee200d26 100644 --- a/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java +++ b/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java @@ -71,14 +71,11 @@ public class GpxBlockStatisticsBuilder { public void initStatBlocks(@Nullable SegmentActionsListener actionsListener, @ColorInt int activeColor, boolean nightMode) { initItems(); - boolean isNotEmpty = !Algorithms.isEmpty(items); - AndroidUiHelper.updateVisibility(blocksView, isNotEmpty); - if (isNotEmpty) { - adapter = new BlockStatisticsAdapter(getDisplayItem(getGPXFile()), actionsListener, activeColor, nightMode); - adapter.setItems(items); - blocksView.setLayoutManager(new LinearLayoutManager(app, LinearLayoutManager.HORIZONTAL, false)); - blocksView.setAdapter(adapter); - } + adapter = new BlockStatisticsAdapter(getDisplayItem(getGPXFile()), actionsListener, activeColor, nightMode); + adapter.setItems(items); + blocksView.setLayoutManager(new LinearLayoutManager(app, LinearLayoutManager.HORIZONTAL, false)); + blocksView.setAdapter(adapter); + AndroidUiHelper.updateVisibility(blocksView, !Algorithms.isEmpty(items)); } public void stopUpdatingStatBlocks() { @@ -90,11 +87,11 @@ public class GpxBlockStatisticsBuilder { updatingItems = new Runnable() { @Override public void run() { + initItems(); if (adapter != null) { - initItems(); adapter.setItems(items); - AndroidUiHelper.updateVisibility(blocksView, !Algorithms.isEmpty(items)); } + AndroidUiHelper.updateVisibility(blocksView, !Algorithms.isEmpty(items)); int interval = app.getSettings().SAVE_GLOBAL_TRACK_INTERVAL.get(); handler.postDelayed(this, Math.max(1000, interval)); } From 77c4b12259efb5b00779376b6346ecca8afb45ec Mon Sep 17 00:00:00 2001 From: Skalii Date: Thu, 11 Feb 2021 04:08:11 +0200 Subject: [PATCH 19/45] some fixes; --- .../layout/trip_recording_active_fragment.xml | 2 +- .../TripRecordingActiveBottomSheet.java | 22 ++++++++++--------- .../plus/track/GpxBlockStatisticsBuilder.java | 10 ++++----- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/OsmAnd/res/layout/trip_recording_active_fragment.xml b/OsmAnd/res/layout/trip_recording_active_fragment.xml index 630b68a5fd..9bb2e62b29 100644 --- a/OsmAnd/res/layout/trip_recording_active_fragment.xml +++ b/OsmAnd/res/layout/trip_recording_active_fragment.xml @@ -103,7 +103,7 @@ android:layout_marginBottom="@dimen/content_padding" /> 0 ? GpxUiHelper.makeGpxDisplayItem(app, gpxFile) : null; } private GPXFile getGPXFile() { @@ -101,12 +102,9 @@ public class GpxBlockStatisticsBuilder { public void initItems() { GPXFile gpxFile = getGPXFile(); - GpxDisplayItem gpxDisplayItem = null; + GpxDisplayItem gpxDisplayItem = getDisplayItem(gpxFile); GPXTrackAnalysis analysis = null; boolean withoutGaps = true; - if (gpxFile.tracks.size() > 0) { - gpxDisplayItem = getDisplayItem(gpxFile); - } if (gpxDisplayItem != null) { analysis = gpxDisplayItem.analysis; withoutGaps = !selectedGpxFile.isJoinSegments() && gpxDisplayItem.isGeneralTrack(); From 2cc2196cd68db79f18e84a62b22c8b06f244f671 Mon Sep 17 00:00:00 2001 From: androiddevkotlin <64539346+androiddevkotlin@users.noreply.github.com> Date: Thu, 11 Feb 2021 17:20:06 +0200 Subject: [PATCH 20/45] Whole track --- .../layout/bottom_sheet_select_segment.xml | 23 +++---- OsmAnd/res/values/ids.xml | 2 + .../helpers/TrackSelectSegmentAdapter.java | 13 +--- .../track/TrackSelectSegmentBottomSheet.java | 63 ++++++++++++++----- 4 files changed, 59 insertions(+), 42 deletions(-) diff --git a/OsmAnd/res/layout/bottom_sheet_select_segment.xml b/OsmAnd/res/layout/bottom_sheet_select_segment.xml index 427d0d93a8..51aa2b97ac 100644 --- a/OsmAnd/res/layout/bottom_sheet_select_segment.xml +++ b/OsmAnd/res/layout/bottom_sheet_select_segment.xml @@ -16,7 +16,7 @@ android:paddingTop="@dimen/measurement_tool_menu_title_padding_top" android:paddingEnd="@dimen/content_padding" android:paddingRight="@dimen/content_padding" - android:paddingBottom="@dimen/content_padding_small"> + android:paddingBottom="@dimen/measurement_tool_button_padding_top"> - + + + + + + \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/helpers/TrackSelectSegmentAdapter.java b/OsmAnd/src/net/osmand/plus/helpers/TrackSelectSegmentAdapter.java index 0ca79ab891..0747cc8afc 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/TrackSelectSegmentAdapter.java +++ b/OsmAnd/src/net/osmand/plus/helpers/TrackSelectSegmentAdapter.java @@ -12,13 +12,10 @@ import androidx.recyclerview.widget.RecyclerView; import net.osmand.GPXUtilities.TrkSegment; import net.osmand.GPXUtilities.WptPt; -import net.osmand.plus.GPXDatabase; -import net.osmand.plus.GpxSelectionHelper; import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; -import net.osmand.plus.measurementtool.MeasurementEditingContext; import net.osmand.util.MapUtils; import java.util.List; @@ -27,9 +24,8 @@ public class TrackSelectSegmentAdapter extends RecyclerView.Adapter segments; + private GpxTrackAdapter.OnItemClickListener onItemClickListener; public TrackSelectSegmentAdapter(Context ctx, List segments) { app = (OsmandApplication) ctx.getApplicationContext(); @@ -62,7 +58,6 @@ public class TrackSelectSegmentAdapter extends RecyclerView.Adapter segments = file.getPointsToDisplay(); + final List segments = selectedFile.getPointsToDisplay(); adapterSegments = new TrackSelectSegmentAdapter(requireContext(), segments); adapterSegments.setAdapterListener(new GpxTrackAdapter.OnItemClickListener() { @Override public void onItemClick(int position) { - selectSegmentToFollow(segments.get(position), file); + //select segment dismiss(); } }); recyclerView.setAdapter(adapterSegments); + gpxTrackContainer.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + selectSegmentToFollow(gpxFile); + dismiss(); + } + }); + } - private void selectSegmentToFollow(TrkSegment segment, GpxSelectionHelper.SelectedGpxFile file) { - MapActivity mapActivity = (MapActivity) getActivity(); + private void selectSegmentToFollow(GPXUtilities.GPXFile gpxFile) { if (mapActivity != null) { - TargetPointsHelper targetPointsHelper = mapActivity.getMyApplication().getTargetPointsHelper(); - RoutingHelper routingHelper = mapActivity.getMyApplication().getRoutingHelper(); - List points = segment.points; + this.gpxFile = gpxFile; + TargetPointsHelper targetPointsHelper = app.getTargetPointsHelper(); + RoutingHelper routingHelper = app.getRoutingHelper(); + List points = gpxFile.getRoutePoints(); if (!points.isEmpty()) { ApplicationMode mode = ApplicationMode.valueOfStringKey(points.get(0).getProfileType(), null); if (mode != null) { routingHelper.setAppMode(mode); - mapActivity.getMyApplication().initVoiceCommandPlayer(mapActivity, mode, true, null, false, false, true); + app.initVoiceCommandPlayer(mapActivity, mode, true, null, false, false, true); } } - mapActivity.getMapActions().setGPXRouteParams(file.getGpxFile()); + mapActivity.getMapActions().setGPXRouteParams(gpxFile); targetPointsHelper.updateRouteAndRefresh(true); routingHelper.onSettingsChanged(true); } From 7890afe5829367d85831902884f20e4ba497f497 Mon Sep 17 00:00:00 2001 From: androiddevkotlin <64539346+androiddevkotlin@users.noreply.github.com> Date: Thu, 11 Feb 2021 20:42:27 +0200 Subject: [PATCH 21/45] Review fix --- .../layout/bottom_sheet_select_segment.xml | 1 - OsmAnd/res/layout/gpx_track_item.xml | 1 + .../helpers/TrackSelectSegmentAdapter.java | 6 ---- .../FollowTrackFragment.java | 12 ++++---- .../track/TrackSelectSegmentBottomSheet.java | 28 +++++++++++-------- 5 files changed, 23 insertions(+), 25 deletions(-) diff --git a/OsmAnd/res/layout/bottom_sheet_select_segment.xml b/OsmAnd/res/layout/bottom_sheet_select_segment.xml index 51aa2b97ac..5a17fe2107 100644 --- a/OsmAnd/res/layout/bottom_sheet_select_segment.xml +++ b/OsmAnd/res/layout/bottom_sheet_select_segment.xml @@ -4,7 +4,6 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" - android:minHeight="@dimen/bottom_sheet_selected_item_title_height" android:orientation="vertical"> 1; + if (GPXFile != null && fragmentManager != null) { + boolean isTrackContainsMultiSegment = GPXFile.getNonEmptySegmentsCount() > 1; if (!isTrackContainsMultiSegment) { - selectTrackToFollow(selectedGpxFile.getGpxFile()); + selectTrackToFollow(GPXFile); updateSelectionMode(false); } else { - TrackSelectSegmentBottomSheet.showInstance(fragmentManager, selectedGpxFile); - selectTrackToFollow(selectedGpxFile.getGpxFile()); - updateSelectionMode(true); + TrackSelectSegmentBottomSheet.showInstance(fragmentManager, GPXFile); } } else { CallbackWithObject callback = new CallbackWithObject() { diff --git a/OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java b/OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java index 0ff986d4ad..bb5bc98760 100644 --- a/OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java @@ -8,15 +8,16 @@ import android.text.SpannableString; import android.text.style.ForegroundColorSpan; import android.view.LayoutInflater; import android.view.View; -import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.appcompat.widget.AppCompatImageView; 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.TrkSegment; import net.osmand.plus.GpxSelectionHelper; @@ -27,7 +28,7 @@ import net.osmand.plus.TargetPointsHelper; import net.osmand.plus.UiUtilities; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.base.MenuBottomSheetDialogFragment; -import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription; +import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem; import net.osmand.plus.helpers.FontCache; import net.osmand.plus.helpers.GpxTrackAdapter; import net.osmand.plus.helpers.TrackSelectSegmentAdapter; @@ -47,10 +48,11 @@ public class TrackSelectSegmentBottomSheet extends MenuBottomSheetDialogFragment private GPXUtilities.GPXFile gpxFile; private OsmandApplication app; - public static void showInstance(@NonNull FragmentManager fragmentManager, @NonNull GpxSelectionHelper.SelectedGpxFile selectedFile) { + public static void showInstance(@NonNull FragmentManager fragmentManager, @NonNull GPXUtilities.GPXFile gpxFile) { if (!fragmentManager.isStateSaved()) { TrackSelectSegmentBottomSheet fragment = new TrackSelectSegmentBottomSheet(); - fragment.selectedFile = selectedFile; + fragment.setRetainInstance(true); + fragment.gpxFile = gpxFile; fragment.show(fragmentManager, TAG); } } @@ -68,7 +70,6 @@ public class TrackSelectSegmentBottomSheet extends MenuBottomSheetDialogFragment } mapActivity = (MapActivity) getActivity(); - gpxFile = selectedFile.getGpxFile(); String titleGpxTrack = Algorithms.getFileWithoutDirs(gpxFile.path); Typeface typeface = FontCache.getRobotoMedium(app); String selectSegmentDescription = getString(R.string.select_segments_description, titleGpxTrack); @@ -79,23 +80,28 @@ public class TrackSelectSegmentBottomSheet extends MenuBottomSheetDialogFragment gpxTrackName.setSpan(new CustomTypefaceSpan(typeface), startIndex, endIndex, 0); gpxTrackName.setSpan(new ForegroundColorSpan(descriptionColor), startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - items.add(new BottomSheetItemWithDescription.Builder() - .setDescription(gpxTrackName) + items.add(new BaseBottomSheetItem.Builder() .setCustomView(itemView) .create()); LinearLayout gpxTrackContainer = itemView.findViewById(R.id.gpx_track_container); GPXUtilities.GPXTrackAnalysis analysis = gpxFile.getAnalysis(0); - ImageView icon = gpxTrackContainer.findViewById(R.id.icon); - icon.setId(R.id.icon1); + AppCompatImageView icon = gpxTrackContainer.findViewById(R.id.icon); + int sidePadding = AndroidUtils.dpToPx(mapActivity, 16f); + TextView name = gpxTrackContainer.findViewById(R.id.name); + TextView description = itemView.findViewById(R.id.description); TextView distance = gpxTrackContainer.findViewById(R.id.distance); TextView pointsCount = gpxTrackContainer.findViewById(R.id.points_count); TextView time = gpxTrackContainer.findViewById(R.id.time); - + LinearLayout container = gpxTrackContainer.findViewById(R.id.container); + LinearLayout containerNameAndReadSection = gpxTrackContainer.findViewById(R.id.name_and_read_section_container); + container.setPadding(sidePadding, 0, 0, 0); + containerNameAndReadSection.setPadding(sidePadding, 0, 0, 0); icon.setImageDrawable(app.getUIUtilities().getThemedIcon(R.drawable.ic_action_polygom_dark)); name.setText(titleGpxTrack); + description.setText(gpxTrackName); distance.setText(OsmAndFormatter.getFormattedDistance(analysis.totalDistance, app)); pointsCount.setText(String.valueOf(analysis.wptPoints)); time.setText(analysis.isTimeSpecified() ? Algorithms.formatDuration((int) (analysis.timeSpan / 1000), app.accessibilityEnabled()) : ""); @@ -103,7 +109,7 @@ public class TrackSelectSegmentBottomSheet extends MenuBottomSheetDialogFragment final RecyclerView recyclerView = itemView.findViewById(R.id.gpx_segment_list); recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); recyclerView.setNestedScrollingEnabled(false); - final List segments = selectedFile.getPointsToDisplay(); + final List segments = gpxFile.getNonEmptyTrkSegments(true); adapterSegments = new TrackSelectSegmentAdapter(requireContext(), segments); adapterSegments.setAdapterListener(new GpxTrackAdapter.OnItemClickListener() { @Override From 3d92a46df6d6a48fdc121ed417af7c0196811142 Mon Sep 17 00:00:00 2001 From: androiddevkotlin <64539346+androiddevkotlin@users.noreply.github.com> Date: Thu, 11 Feb 2021 23:25:54 +0200 Subject: [PATCH 22/45] NPE fix, styling text --- .../layout/bottom_sheet_select_segment.xml | 6 +++-- OsmAnd/res/values/ids.xml | 2 -- OsmAnd/res/values/sizes.xml | 3 +++ .../FollowTrackFragment.java | 26 ++++++++++++------- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/OsmAnd/res/layout/bottom_sheet_select_segment.xml b/OsmAnd/res/layout/bottom_sheet_select_segment.xml index 5a17fe2107..ddfa37f927 100644 --- a/OsmAnd/res/layout/bottom_sheet_select_segment.xml +++ b/OsmAnd/res/layout/bottom_sheet_select_segment.xml @@ -25,7 +25,7 @@ android:ellipsize="end" android:gravity="center_vertical" android:letterSpacing="@dimen/text_button_letter_spacing" - android:lineSpacingExtra="@dimen/line_spacing_extra_description" + android:lineSpacingExtra="@dimen/titleLineSpacingExtra" android:maxLines="1" android:text="@string/select_segments" android:textColor="?android:textColorPrimary" @@ -37,10 +37,12 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/list_header_settings_top_margin" + android:letterSpacing="@dimen/description_letter_spacing" android:lineSpacingMultiplier="@dimen/bottom_sheet_text_spacing_multiplier" + android:lineSpacingExtra="@dimen/descriptionLineSpacingExtra" android:text="@string/select_segments_description" android:textColor="?android:textColorSecondary" - android:textSize="@dimen/default_list_text_size" + android:textSize="@dimen/default_desc_text_size" osmand:typeface="@string/font_roboto_regular" /> diff --git a/OsmAnd/res/values/ids.xml b/OsmAnd/res/values/ids.xml index 244ac99d5d..19a023ee8a 100644 --- a/OsmAnd/res/values/ids.xml +++ b/OsmAnd/res/values/ids.xml @@ -16,7 +16,5 @@ - - \ No newline at end of file diff --git a/OsmAnd/res/values/sizes.xml b/OsmAnd/res/values/sizes.xml index a086849297..107bb45da7 100644 --- a/OsmAnd/res/values/sizes.xml +++ b/OsmAnd/res/values/sizes.xml @@ -413,4 +413,7 @@ 32dp 24dp + + 5sp + 3sp \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/FollowTrackFragment.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/FollowTrackFragment.java index d1e6120fc4..68c07bcb30 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/FollowTrackFragment.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/FollowTrackFragment.java @@ -493,22 +493,28 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca if (mapActivity != null && index < card.getGpxInfoList().size()) { GPXInfo gpxInfo = card.getGpxInfoList().get(index); String fileName = gpxInfo.getFileName(); - GPXFile GPXFile = app.getSelectedGpxHelper().getSelectedFileByName(fileName).getGpxFile(); - FragmentManager fragmentManager = getFragmentManager(); - if (GPXFile != null && fragmentManager != null) { - boolean isTrackContainsMultiSegment = GPXFile.getNonEmptySegmentsCount() > 1; - if (!isTrackContainsMultiSegment) { - selectTrackToFollow(GPXFile); - updateSelectionMode(false); + SelectedGpxFile selectedGpxFile = app.getSelectedGpxHelper().getSelectedFileByName(fileName); + if (selectedGpxFile != null) { + GPXFile gpxFile = selectedGpxFile.getGpxFile(); + if (gpxFile.getNonEmptySegmentsCount() > 1) { + TrackSelectSegmentBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), gpxFile); } else { - TrackSelectSegmentBottomSheet.showInstance(fragmentManager, GPXFile); + updateSelectionMode(false); + selectTrackToFollow(gpxFile); } } else { CallbackWithObject callback = new CallbackWithObject() { @Override public boolean processResult(GPXFile[] result) { - selectTrackToFollow(result[0]); - updateSelectionMode(false); + MapActivity mapActivity = getMapActivity(); + if (mapActivity != null) { + if (result[0].getNonEmptySegmentsCount() > 1) { + TrackSelectSegmentBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), result[0]); + } else { + updateSelectionMode(false); + selectTrackToFollow(result[0]); + } + } return true; } }; From 51c8222447b201c7f595009f254793052bb44546 Mon Sep 17 00:00:00 2001 From: androiddevkotlin <64539346+androiddevkotlin@users.noreply.github.com> Date: Fri, 12 Feb 2021 12:14:03 +0200 Subject: [PATCH 23/45] Minor UI fixes --- .../osmand/plus/helpers/TrackSelectSegmentAdapter.java | 6 +++++- .../osmand/plus/track/TrackSelectSegmentBottomSheet.java | 9 +++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/helpers/TrackSelectSegmentAdapter.java b/OsmAnd/src/net/osmand/plus/helpers/TrackSelectSegmentAdapter.java index f417801625..96ceefed24 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/TrackSelectSegmentAdapter.java +++ b/OsmAnd/src/net/osmand/plus/helpers/TrackSelectSegmentAdapter.java @@ -56,7 +56,11 @@ public class TrackSelectSegmentAdapter extends RecyclerView.Adapter Date: Fri, 12 Feb 2021 15:08:56 +0200 Subject: [PATCH 24/45] fix "Currently recording track" showing with same name; add update statistics blocks in "Overview" if the current recording track is open; --- .../plus/track/GpxBlockStatisticsBuilder.java | 41 +++++++++++-------- .../net/osmand/plus/track/OverviewCard.java | 4 ++ .../osmand/plus/track/TrackMenuFragment.java | 17 +++++++- 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java b/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java index 0e005b0d8c..0c1b77a1fa 100644 --- a/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java +++ b/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java @@ -11,6 +11,7 @@ import androidx.annotation.ColorInt; import androidx.annotation.ColorRes; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatImageView; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -41,6 +42,7 @@ public class GpxBlockStatisticsBuilder { private BlockStatisticsAdapter adapter; private final List items = new ArrayList<>(); + private boolean blocksClickable = true; private final Handler handler = new Handler(); private Runnable updatingItems; @@ -51,28 +53,34 @@ public class GpxBlockStatisticsBuilder { this.selectedGpxFile = selectedGpxFile; } + public boolean isUpdateRunning() { + return updateRunning; + } + + public void setBlocksClickable(boolean blocksClickable) { + this.blocksClickable = blocksClickable; + } + public void setBlocksView(RecyclerView blocksView) { this.blocksView = blocksView; } - private GpxDisplayItem getDisplayItem(GPXFile gpxFile) { - return GpxUiHelper.makeGpxDisplayItem(app, gpxFile); + @Nullable + public GpxDisplayItem getDisplayItem(GPXFile gpxFile) { + return gpxFile.tracks.size() > 0 ? GpxUiHelper.makeGpxDisplayItem(app, gpxFile) : null; } private GPXFile getGPXFile() { return selectedGpxFile.getGpxFile(); } - public void initStatBlocks(SegmentActionsListener actionsListener, @ColorInt int activeColor, boolean nightMode) { + public void initStatBlocks(@Nullable SegmentActionsListener actionsListener, @ColorInt int activeColor, boolean nightMode) { initItems(); - boolean isNotEmpty = !Algorithms.isEmpty(items); - AndroidUiHelper.updateVisibility(blocksView, isNotEmpty); - if (isNotEmpty) { - adapter = new BlockStatisticsAdapter(getDisplayItem(getGPXFile()), actionsListener, activeColor, nightMode); - adapter.setItems(items); - blocksView.setLayoutManager(new LinearLayoutManager(app, LinearLayoutManager.HORIZONTAL, false)); - blocksView.setAdapter(adapter); - } + adapter = new BlockStatisticsAdapter(getDisplayItem(getGPXFile()), actionsListener, activeColor, nightMode); + adapter.setItems(items); + blocksView.setLayoutManager(new LinearLayoutManager(app, LinearLayoutManager.HORIZONTAL, false)); + blocksView.setAdapter(adapter); + AndroidUiHelper.updateVisibility(blocksView, !Algorithms.isEmpty(items)); } public void stopUpdatingStatBlocks() { @@ -84,11 +92,11 @@ public class GpxBlockStatisticsBuilder { updatingItems = new Runnable() { @Override public void run() { + initItems(); if (adapter != null) { - initItems(); adapter.setItems(items); - AndroidUiHelper.updateVisibility(blocksView, !Algorithms.isEmpty(items)); } + AndroidUiHelper.updateVisibility(blocksView, !Algorithms.isEmpty(items)); int interval = app.getSettings().SAVE_GLOBAL_TRACK_INTERVAL.get(); handler.postDelayed(this, Math.max(1000, interval)); } @@ -98,12 +106,9 @@ public class GpxBlockStatisticsBuilder { public void initItems() { GPXFile gpxFile = getGPXFile(); - GpxDisplayItem gpxDisplayItem = null; + GpxDisplayItem gpxDisplayItem = getDisplayItem(gpxFile); GPXTrackAnalysis analysis = null; boolean withoutGaps = true; - if (gpxFile.tracks.size() > 0) { - gpxDisplayItem = getDisplayItem(gpxFile); - } if (gpxDisplayItem != null) { analysis = gpxDisplayItem.analysis; withoutGaps = !selectedGpxFile.isJoinSegments() && gpxDisplayItem.isGeneralTrack(); @@ -237,7 +242,7 @@ public class GpxBlockStatisticsBuilder { @Override public void onClick(View v) { GPXTrackAnalysis analysis = displayItem != null ? displayItem.analysis : null; - if (analysis != null) { + if (blocksClickable && analysis != null && actionsListener != null) { ArrayList list = new ArrayList<>(); if (analysis.hasElevationData || analysis.isSpeedSpecified() || analysis.hasSpeedData) { if (item.firstType != null) { diff --git a/OsmAnd/src/net/osmand/plus/track/OverviewCard.java b/OsmAnd/src/net/osmand/plus/track/OverviewCard.java index bb56b43f89..25fa38e04e 100644 --- a/OsmAnd/src/net/osmand/plus/track/OverviewCard.java +++ b/OsmAnd/src/net/osmand/plus/track/OverviewCard.java @@ -43,6 +43,10 @@ public class OverviewCard extends BaseCard { private final SelectedGpxFile selectedGpxFile; private final GpxBlockStatisticsBuilder blockStatisticsBuilder; + public GpxBlockStatisticsBuilder getBlockStatisticsBuilder() { + return blockStatisticsBuilder; + } + public OverviewCard(@NonNull MapActivity mapActivity, @NonNull SegmentActionsListener actionsListener, SelectedGpxFile selectedGpxFile) { super(mapActivity); this.actionsListener = actionsListener; diff --git a/OsmAnd/src/net/osmand/plus/track/TrackMenuFragment.java b/OsmAnd/src/net/osmand/plus/track/TrackMenuFragment.java index ff2ec67140..7aa8eebbce 100644 --- a/OsmAnd/src/net/osmand/plus/track/TrackMenuFragment.java +++ b/OsmAnd/src/net/osmand/plus/track/TrackMenuFragment.java @@ -231,7 +231,8 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card } displayHelper.setGpx(selectedGpxFile.getGpxFile()); String fileName = Algorithms.getFileWithoutDirs(getGpx().path); - gpxTitle = GpxUiHelper.getGpxTitle(fileName); + gpxTitle = !isCurrentRecordingTrack() ? GpxUiHelper.getGpxTitle(fileName) + : app.getResources().getString(R.string.shared_string_currently_recording_track); toolbarHeightPx = getResources().getDimensionPixelSize(R.dimen.dashboard_map_toolbar); FragmentActivity activity = requireMyActivity(); @@ -330,8 +331,13 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card overviewCard.setListener(this); headerContainer.addView(overviewCard.build(getMapActivity())); } + GpxBlockStatisticsBuilder blocksBuilder = overviewCard.getBlockStatisticsBuilder(); + if (isCurrentRecordingTrack() && !blocksBuilder.isUpdateRunning()) { + blocksBuilder.runUpdatingStatBlocks(); + } } else { if (overviewCard != null && overviewCard.getView() != null) { + overviewCard.getBlockStatisticsBuilder().stopUpdatingStatBlocks(); headerContainer.removeView(overviewCard.getView()); } boolean isOptions = menuType == TrackMenuType.OPTIONS; @@ -544,6 +550,10 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card } updateControlsVisibility(true); startLocationUpdate(); + GpxBlockStatisticsBuilder blockStats = overviewCard.getBlockStatisticsBuilder(); + if (menuType == TrackMenuType.OVERVIEW && isCurrentRecordingTrack() && !blockStats.isUpdateRunning()) { + blockStats.runUpdatingStatBlocks(); + } } @Override @@ -555,6 +565,7 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card } updateControlsVisibility(false); stopLocationUpdate(); + overviewCard.getBlockStatisticsBuilder().stopUpdatingStatBlocks(); } @Override @@ -1120,6 +1131,10 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } + private boolean isCurrentRecordingTrack() { + return app.getSavingTrackHelper().getCurrentTrack() == selectedGpxFile; + } + private void hide() { try { MapActivity mapActivity = getMapActivity(); From 357ab00ed60df90daa8f61db5dbf5e271840aa91 Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Fri, 12 Feb 2021 21:38:28 +0200 Subject: [PATCH 25/45] Download all button implementation --- .../java/net/osmand/map/OsmandRegions.java | 39 ++ .../main/java/net/osmand/map/WorldRegion.java | 29 ++ OsmAnd/res/values/strings.xml | 2 + .../download/AbstractDownloadActivity.java | 2 +- .../osmand/plus/download/CustomIndexItem.java | 3 +- .../plus/download/DownloadActivity.java | 1 - .../plus/download/DownloadActivityType.java | 27 +- .../plus/download/DownloadIndexesThread.java | 10 + .../osmand/plus/download/DownloadItem.java | 76 ++++ .../plus/download/DownloadResourceGroup.java | 80 ++-- .../plus/download/DownloadResources.java | 158 ++++++-- .../download/DownloadValidationManager.java | 2 +- .../net/osmand/plus/download/IndexItem.java | 85 ++-- .../plus/download/MultipleIndexItem.java | 122 ++++++ .../ui/DownloadResourceGroupAdapter.java | 6 +- .../plus/download/ui/ItemViewHolder.java | 367 ++++++++++++------ .../download/ui/UpdatesIndexFragment.java | 3 +- 17 files changed, 763 insertions(+), 249 deletions(-) create mode 100644 OsmAnd/src/net/osmand/plus/download/DownloadItem.java create mode 100644 OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java diff --git a/OsmAnd-java/src/main/java/net/osmand/map/OsmandRegions.java b/OsmAnd-java/src/main/java/net/osmand/map/OsmandRegions.java index 033beb3789..eba0d94b2b 100644 --- a/OsmAnd-java/src/main/java/net/osmand/map/OsmandRegions.java +++ b/OsmAnd-java/src/main/java/net/osmand/map/OsmandRegions.java @@ -10,6 +10,7 @@ import net.osmand.binary.BinaryMapIndexReader.TagValuePair; import net.osmand.data.LatLon; import net.osmand.data.QuadRect; import net.osmand.data.QuadTree; +import net.osmand.map.WorldRegion.RegionBoundingBox; import net.osmand.util.Algorithms; import net.osmand.util.MapAlgorithms; import net.osmand.util.MapUtils; @@ -436,6 +437,7 @@ public class OsmandRegions { cx /= object.getPointsLength(); cy /= object.getPointsLength(); rd.regionCenter = new LatLon(MapUtils.get31LatitudeY((int) cy), MapUtils.get31LongitudeX((int) cx)); + rd.boundingBox = findBoundingBox(object); } rd.regionParentFullName = mapIndexFields.get(mapIndexFields.parentFullName, object); @@ -461,6 +463,43 @@ public class OsmandRegions { return rd; } + private RegionBoundingBox findBoundingBox(BinaryMapDataObject object) { + if (object.getPointsLength() == 0) { + return new RegionBoundingBox(0, 0, 0, 0); + } + + double currentX = object.getPoint31XTile(0); + double currentY = object.getPoint31YTile(0); + double minX = currentX; + double maxX = currentX; + double minY = currentY; + double maxY = currentY; + + if (object.getPointsLength() > 1) { + for (int i = 1; i < object.getPointsLength(); i++) { + currentX = object.getPoint31XTile(i); + currentY = object.getPoint31YTile(i); + if (currentX > maxX) { + maxX = currentX; + } else if (currentX < minX) { + minX = currentX; + } + if (currentY > maxY) { + maxY = currentY; + } else if (currentY < minY) { + minY = currentY; + } + } + } + + minX = MapUtils.get31LongitudeX((int) minX); + maxX = MapUtils.get31LongitudeX((int) maxX); + double revertedMinY = MapUtils.get31LatitudeY((int) maxY); + double revertedMaxY = MapUtils.get31LatitudeY((int) minY); + + return new RegionBoundingBox(minX, maxX, revertedMinY, revertedMaxY); + } + private String getSearchIndex(BinaryMapDataObject object) { MapIndex mi = object.getMapIndex(); TIntObjectIterator it = object.getObjectNames().iterator(); diff --git a/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java b/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java index 38fbc40c3d..e95efb4f5b 100644 --- a/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java +++ b/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java @@ -40,6 +40,7 @@ public class WorldRegion implements Serializable { protected String regionDownloadName; protected boolean regionMapDownload; protected LatLon regionCenter; + protected RegionBoundingBox boundingBox; public static class RegionParams { protected String regionLeftHandDriving; @@ -182,4 +183,32 @@ public class WorldRegion implements Serializable { } return res; } + + public static boolean isFirstRegionInsideTheSecond(WorldRegion first, + WorldRegion second) { + RegionBoundingBox bbox1 = first.boundingBox; + RegionBoundingBox bbox2 = second.boundingBox; + if ((bbox1.minX > bbox2.minX) && (bbox1.maxX < bbox2.maxX)) { + if ((bbox1.minY > bbox2.minY) && (bbox1.maxY < bbox2.maxY)) { + return true; + } + } + return false; + } + + public static class RegionBoundingBox { + + double minX; + double maxX; + double minY; + double maxY; + + public RegionBoundingBox(double minX, double maxX, double minY, double maxY) { + this.minX = minX; + this.maxX = maxX; + this.minY = minY; + this.maxY = maxY; + } + + } } \ No newline at end of file diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 8b1a73aa95..71c3591ade 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -12,6 +12,8 @@ --> + Delete %1$d files? + All regions Car Motorbike Off-road diff --git a/OsmAnd/src/net/osmand/plus/download/AbstractDownloadActivity.java b/OsmAnd/src/net/osmand/plus/download/AbstractDownloadActivity.java index 9bcb0ebb6c..93b887ea1c 100644 --- a/OsmAnd/src/net/osmand/plus/download/AbstractDownloadActivity.java +++ b/OsmAnd/src/net/osmand/plus/download/AbstractDownloadActivity.java @@ -17,7 +17,7 @@ public class AbstractDownloadActivity extends ActionBarProgressActivity { downloadValidationManager.startDownload(this, indexItem); } - public void makeSureUserCancelDownload(IndexItem item) { + public void makeSureUserCancelDownload(DownloadItem item) { downloadValidationManager.makeSureUserCancelDownload(this, item); } } diff --git a/OsmAnd/src/net/osmand/plus/download/CustomIndexItem.java b/OsmAnd/src/net/osmand/plus/download/CustomIndexItem.java index 16067b7c04..885e28fdf6 100644 --- a/OsmAnd/src/net/osmand/plus/download/CustomIndexItem.java +++ b/OsmAnd/src/net/osmand/plus/download/CustomIndexItem.java @@ -56,7 +56,8 @@ public class CustomIndexItem extends IndexItem { } @Override - public File getTargetFile(OsmandApplication ctx) { + @NonNull + public File getTargetFile(@NonNull OsmandApplication ctx) { String basename = getTranslatedBasename(); if (!Algorithms.isEmpty(subfolder)) { basename = subfolder + "/" + basename; diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadActivity.java b/OsmAnd/src/net/osmand/plus/download/DownloadActivity.java index d076f329f0..bc92fc050f 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadActivity.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadActivity.java @@ -1,7 +1,6 @@ package net.osmand.plus.download; import android.Manifest; -import android.annotation.SuppressLint; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java b/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java index 298e3fc287..b78617d426 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.net.URLEncoder; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Locale; @@ -113,6 +114,10 @@ public class DownloadActivityType { public static DownloadActivityType getIndexType(String tagName) { return byTag.get(tagName); } + + public static Collection values() { + return byTag.values(); + } protected static String addVersionToExt(String ext, int version) { return "_" + version + ext; @@ -318,7 +323,7 @@ public class DownloadActivityType { } } - public String getVisibleDescription(IndexItem indexItem, Context ctx) { + public String getVisibleDescription(DownloadItem downloadItem, Context ctx) { if (this == SRTM_COUNTRY_FILE) { return ctx.getString(R.string.download_srtm_maps); } else if (this == WIKIPEDIA_FILE) { @@ -337,20 +342,20 @@ public class DownloadActivityType { return ""; } - public String getVisibleName(IndexItem indexItem, Context ctx, OsmandRegions osmandRegions, boolean includingParent) { + public String getVisibleName(DownloadItem downloadItem, Context ctx, OsmandRegions osmandRegions, boolean includingParent) { if (this == VOICE_FILE) { - String fileName = indexItem.fileName; + String fileName = downloadItem.getFileName(); if (fileName.endsWith(IndexConstants.VOICE_INDEX_EXT_ZIP)) { - return FileNameTranslationHelper.getVoiceName(ctx, getBasename(indexItem)); + return FileNameTranslationHelper.getVoiceName(ctx, getBasename(downloadItem)); } else if (fileName.endsWith(IndexConstants.TTSVOICE_INDEX_EXT_JS)) { - return FileNameTranslationHelper.getVoiceName(ctx, getBasename(indexItem)); + return FileNameTranslationHelper.getVoiceName(ctx, getBasename(downloadItem)); } - return getBasename(indexItem); + return getBasename(downloadItem); } if (this == FONT_FILE) { - return FileNameTranslationHelper.getFontName(ctx, getBasename(indexItem)); + return FileNameTranslationHelper.getFontName(ctx, getBasename(downloadItem)); } - final String basename = getBasename(indexItem); + final String basename = getBasename(downloadItem); if (basename.endsWith(FileNameTranslationHelper.WIKI_NAME)) { return FileNameTranslationHelper.getWikiName(ctx, basename); } @@ -442,8 +447,8 @@ public class DownloadActivityType { } - public String getBasename(IndexItem indexItem) { - String fileName = indexItem.fileName; + public String getBasename(DownloadItem downloadItem) { + String fileName = downloadItem.getFileName(); if (fileName.endsWith(IndexConstants.EXTRA_ZIP_EXT)) { return fileName.substring(0, fileName.length() - IndexConstants.EXTRA_ZIP_EXT.length()); } @@ -458,7 +463,7 @@ public class DownloadActivityType { if (fileName.endsWith(IndexConstants.SQLITE_EXT)) { return fileName.substring(0, fileName.length() - IndexConstants.SQLITE_EXT.length()); } - if (indexItem.getType() == WIKIVOYAGE_FILE && + if (downloadItem.getType() == WIKIVOYAGE_FILE && fileName.endsWith(IndexConstants.BINARY_WIKIVOYAGE_MAP_INDEX_EXT)) { return fileName.substring(0, fileName.length() - IndexConstants.BINARY_WIKIVOYAGE_MAP_INDEX_EXT.length()); } diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java b/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java index 9d47f57762..20ac836139 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java @@ -239,6 +239,16 @@ public class DownloadIndexesThread { } } + public void cancelDownload(DownloadItem item) { + if (item instanceof MultipleIndexItem) { + MultipleIndexItem multipleIndexItem = (MultipleIndexItem) item; + cancelDownload(multipleIndexItem.getAllIndexes()); + } else if (item instanceof IndexItem) { + IndexItem indexItem = (IndexItem) item; + cancelDownload(indexItem); + } + } + public void cancelDownload(IndexItem item) { app.logMapDownloadEvent("cancel", item); if (currentDownloadingItem == item) { diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadItem.java b/OsmAnd/src/net/osmand/plus/download/DownloadItem.java new file mode 100644 index 0000000000..f0a566cea6 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/download/DownloadItem.java @@ -0,0 +1,76 @@ +package net.osmand.plus.download; + +import android.content.Context; + +import androidx.annotation.NonNull; + +import net.osmand.map.OsmandRegions; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; + +import java.io.File; +import java.util.List; +import java.util.Locale; + +public abstract class DownloadItem { + + protected DownloadActivityType type; + protected DownloadResourceGroup relatedGroup; + + public DownloadItem(DownloadActivityType type) { + this.type = type; + } + + public DownloadActivityType getType() { + return type; + } + + public void setRelatedGroup(DownloadResourceGroup relatedGroup) { + this.relatedGroup = relatedGroup; + } + + public DownloadResourceGroup getRelatedGroup() { + return relatedGroup; + } + + @NonNull + public String getSizeDescription(Context ctx) { + String pattern = ctx.getString(R.string.ltr_or_rtl_combine_via_space); + String size = String.format(Locale.US, "%.2f", getSizeToDownloadInMb()); + return String.format(pattern, size, "MB"); + } + + public String getVisibleName(Context ctx, OsmandRegions osmandRegions) { + return type.getVisibleName(this, ctx, osmandRegions, true); + } + + public String getVisibleName(Context ctx, OsmandRegions osmandRegions, boolean includingParent) { + return type.getVisibleName(this, ctx, osmandRegions, includingParent); + } + + public String getVisibleDescription(OsmandApplication clctx) { + return type.getVisibleDescription(this, clctx); + } + + public String getBasename() { + return type.getBasename(this); + } + + protected abstract double getSizeToDownloadInMb(); + + public abstract double getArchiveSizeMB(); + + public abstract boolean isDownloaded(); + + public abstract boolean isOutdated(); + + public abstract boolean hasActualDataToDownload(); + + public abstract boolean isDownloading(DownloadIndexesThread thread); + + public abstract String getFileName(); + + @NonNull + public abstract List getDownloadedFiles(OsmandApplication app); + +} diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java b/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java index 416e20bc94..dc4e697cb4 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java @@ -8,6 +8,7 @@ import net.osmand.map.OsmandRegions; import net.osmand.map.WorldRegion; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; +import net.osmand.util.Algorithms; import java.util.ArrayList; import java.util.Collections; @@ -20,8 +21,8 @@ public class DownloadResourceGroup { private final DownloadResourceGroupType type; private final DownloadResourceGroup parentGroup; - // ASSERT: individualResources are not empty if and only if groups are empty - private final List individualResources; + // ASSERT: individualDisplayItems are not empty if and only if groups are empty + private final List individualDownloadItems; private final List groups; protected final String id; @@ -107,10 +108,10 @@ public class DownloadResourceGroup { public DownloadResourceGroup(DownloadResourceGroup parentGroup, DownloadResourceGroupType type, String id) { boolean flat = type.containsIndexItem(); if (flat) { - this.individualResources = new ArrayList(); + this.individualDownloadItems = new ArrayList(); this.groups = null; } else { - this.individualResources = null; + this.individualDownloadItems = null; this.groups = new ArrayList(); } this.id = id; @@ -173,7 +174,7 @@ public class DownloadResourceGroup { DownloadResourceGroup regionMaps = getSubGroupById(DownloadResourceGroupType.REGION_MAPS.getDefaultId()); if(regionMaps != null && regionMaps.size() == 1 && parentGroup != null && parentGroup.getParentGroup() != null && isEmpty(getSubGroupById(DownloadResourceGroupType.SUBREGIONS.getDefaultId()))) { - IndexItem item = regionMaps.individualResources.get(0); + IndexItem item = regionMaps.getIndividualResources().get(0); DownloadResourceGroup screenParent = parentGroup.getParentGroup(); if(item.getType() == DownloadActivityType.HILLSHADE_FILE) { DownloadResourceGroup hillshades = @@ -183,7 +184,7 @@ public class DownloadResourceGroup { screenParent.addGroup(hillshades); } hillshades.addItem(item); - regionMaps.individualResources.remove(0); + regionMaps.individualDownloadItems.remove(0); } else if (item.getType() == DownloadActivityType.SRTM_COUNTRY_FILE) { DownloadResourceGroup hillshades = screenParent .getSubGroupById(DownloadResourceGroupType.SRTM_HEADER.getDefaultId()); @@ -192,7 +193,7 @@ public class DownloadResourceGroup { screenParent.addGroup(hillshades); } hillshades.addItem(item); - regionMaps.individualResources.remove(0); + regionMaps.individualDownloadItems.remove(0); } } @@ -221,35 +222,38 @@ public class DownloadResourceGroup { } } groups.add(g); - if (g.individualResources != null) { - final net.osmand.Collator collator = OsmAndCollator.primaryCollator(); - final OsmandApplication app = getRoot().app; - final OsmandRegions osmandRegions = app.getRegions(); - Collections.sort(g.individualResources, new Comparator() { - @Override - public int compare(IndexItem lhs, IndexItem rhs) { - int lli = lhs.getType().getOrderIndex(); - int rri = rhs.getType().getOrderIndex(); - if(lli < rri) { - return -1; - } else if(lli > rri) { - return 1; - } + sortDownloadItems(g.individualDownloadItems); + } - return collator.compare(lhs.getVisibleName(app.getApplicationContext(), osmandRegions), - rhs.getVisibleName(app.getApplicationContext(), osmandRegions)); + protected void sortDownloadItems(List items) { + if (Algorithms.isEmpty(items)) return; + final net.osmand.Collator collator = OsmAndCollator.primaryCollator(); + final OsmandApplication app = getRoot().app; + final OsmandRegions osmandRegions = app.getRegions(); + Collections.sort(items, new Comparator() { + @Override + public int compare(DownloadItem firstItem, DownloadItem secondItem) { + int firstOrder = firstItem.getType().getOrderIndex(); + int secondOrder = secondItem.getType().getOrderIndex(); + if(firstOrder < secondOrder) { + return -1; + } else if(firstOrder > secondOrder) { + return 1; } - }); - } + String firstName = firstItem.getVisibleName(app, osmandRegions); + String secondName = secondItem.getVisibleName(app, osmandRegions); + return collator.compare(firstName, secondName); + } + }); } - public void addItem(IndexItem i) { + public void addItem(DownloadItem i) { i.setRelatedGroup(this); - individualResources.add(i); + individualDownloadItems.add(i); } public boolean isEmpty() { - return isEmpty(individualResources) && isEmpty(groups); + return isEmpty(individualDownloadItems) && isEmpty(groups); } private boolean isEmpty(List l) { @@ -265,7 +269,7 @@ public class DownloadResourceGroup { } public int size() { - return groups != null ? groups.size() : individualResources.size(); + return groups != null ? groups.size() : individualDownloadItems.size(); } public DownloadResourceGroup getGroupByIndex(int ind) { @@ -275,9 +279,9 @@ public class DownloadResourceGroup { return null; } - public IndexItem getItemByIndex(int ind) { - if (individualResources != null && ind >= 0 && ind < individualResources.size()) { - return individualResources.get(ind); + public DownloadItem getItemByIndex(int ind) { + if (individualDownloadItems != null && ind >= 0 && ind < individualDownloadItems.size()) { + return individualDownloadItems.get(ind); } return null; } @@ -306,8 +310,20 @@ public class DownloadResourceGroup { } public List getIndividualResources() { + List individualResources = new ArrayList<>(); + if (individualDownloadItems != null) { + for (DownloadItem item : individualDownloadItems) { + if (item instanceof IndexItem) { + individualResources.add((IndexItem) item); + } + } + } return individualResources; } + + public List getIndividualDownloadItems() { + return individualDownloadItems; + } public WorldRegion getRegion() { return region; diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadResources.java b/OsmAnd/src/net/osmand/plus/download/DownloadResources.java index 56d137a696..a3aa20c79f 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadResources.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadResources.java @@ -25,10 +25,14 @@ import java.io.InputStream; import java.text.DateFormat; import java.text.ParseException; import java.util.ArrayList; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; + +import static net.osmand.plus.download.DownloadResourceGroup.DownloadResourceGroupType.REGION_MAPS; public class DownloadResources extends DownloadResourceGroup { private static final String TAG = DownloadResources.class.getSimpleName(); @@ -40,7 +44,7 @@ public class DownloadResources extends DownloadResourceGroup { private Map indexFileNames = new LinkedHashMap<>(); private Map indexActivatedFileNames = new LinkedHashMap<>(); private List rawResources; - private Map > groupByRegion; + private Map> groupByRegion; private List itemsToUpdate = new ArrayList<>(); public static final String WORLD_SEAMARKS_KEY = "world_seamarks"; public static final String WORLD_SEAMARKS_NAME = "World_seamarks"; @@ -55,7 +59,7 @@ public class DownloadResources extends DownloadResourceGroup { this.region = app.getRegions().getWorldRegion(); this.app = app; } - + public List getItemsToUpdate() { return itemsToUpdate; } @@ -260,7 +264,7 @@ public class DownloadResources extends DownloadResourceGroup { } private Map listWithAlternatives(final java.text.DateFormat dateFormat, File file, - final String ext, final Map files) { + final String ext, final Map files) { if (file.isDirectory()) { file.list(new FilenameFilter() { @Override @@ -292,7 +296,7 @@ public class DownloadResources extends DownloadResourceGroup { } return file; } - + private void prepareFilesToUpdate() { List filtered = rawResources; if (filtered != null) { @@ -307,7 +311,7 @@ public class DownloadResources extends DownloadResourceGroup { } } } - + protected boolean prepareData(List resources) { this.rawResources = resources; @@ -332,18 +336,18 @@ public class DownloadResources extends DownloadResourceGroup { DownloadResourceGroup nauticalMapsGroup = new DownloadResourceGroup(this, DownloadResourceGroupType.NAUTICAL_MAPS_GROUP); DownloadResourceGroup nauticalMapsScreen = new DownloadResourceGroup(nauticalMapsGroup, DownloadResourceGroupType.NAUTICAL_MAPS); DownloadResourceGroup nauticalMaps = new DownloadResourceGroup(nauticalMapsGroup, DownloadResourceGroupType.NAUTICAL_MAPS_HEADER); - + DownloadResourceGroup wikivoyageMapsGroup = new DownloadResourceGroup(this, DownloadResourceGroupType.TRAVEL_GROUP); DownloadResourceGroup wikivoyageMapsScreen = new DownloadResourceGroup(wikivoyageMapsGroup, DownloadResourceGroupType.WIKIVOYAGE_MAPS); DownloadResourceGroup wikivoyageMaps = new DownloadResourceGroup(wikivoyageMapsGroup, DownloadResourceGroupType.WIKIVOYAGE_HEADER); - Map > groupByRegion = new LinkedHashMap>(); + Map> groupByRegion = new LinkedHashMap<>(); OsmandRegions regs = app.getRegions(); for (IndexItem ii : resources) { if (ii.getType() == DownloadActivityType.VOICE_FILE) { - if (ii.getFileName().endsWith(IndexConstants.TTSVOICE_INDEX_EXT_JS)){ + if (ii.getFileName().endsWith(IndexConstants.TTSVOICE_INDEX_EXT_JS)) { voiceTTS.addItem(ii); - } else if (ii.getFileName().endsWith(IndexConstants.VOICE_INDEX_EXT_ZIP)){ + } else if (ii.getFileName().endsWith(IndexConstants.VOICE_INDEX_EXT_ZIP)) { voiceRec.addItem(ii); } continue; @@ -377,7 +381,7 @@ public class DownloadResources extends DownloadResourceGroup { groupByRegion.get(wg).add(ii); } else { if (ii.getFileName().startsWith("World_")) { - if (ii.getFileName().toLowerCase().startsWith(WORLD_SEAMARKS_KEY) || + if (ii.getFileName().toLowerCase().startsWith(WORLD_SEAMARKS_KEY) || ii.getFileName().toLowerCase().startsWith(WORLD_SEAMARKS_OLD_KEY)) { nauticalMaps.addItem(ii); } else { @@ -402,22 +406,22 @@ public class DownloadResources extends DownloadResourceGroup { LinkedList parent = new LinkedList(); DownloadResourceGroup worldSubregions = new DownloadResourceGroup(this, DownloadResourceGroupType.SUBREGIONS); addGroup(worldSubregions); - for(WorldRegion rg : region.getSubregions()) { + for (WorldRegion rg : region.getSubregions()) { queue.add(rg); parent.add(worldSubregions); } - while(!queue.isEmpty()) { + while (!queue.isEmpty()) { WorldRegion reg = queue.pollFirst(); DownloadResourceGroup parentGroup = parent.pollFirst(); List subregions = reg.getSubregions(); DownloadResourceGroup mainGrp = new DownloadResourceGroup(parentGroup, DownloadResourceGroupType.REGION, reg.getRegionId()); mainGrp.region = reg; parentGroup.addGroup(mainGrp); - + List list = groupByRegion.get(reg); - if(list != null) { - DownloadResourceGroup flatFiles = new DownloadResourceGroup(mainGrp, DownloadResourceGroupType.REGION_MAPS); - for(IndexItem ii : list) { + if (list != null) { + DownloadResourceGroup flatFiles = new DownloadResourceGroup(mainGrp, REGION_MAPS); + for (IndexItem ii : list) { flatFiles.addItem(ii); } mainGrp.addGroup(flatFiles); @@ -425,10 +429,10 @@ public class DownloadResources extends DownloadResourceGroup { DownloadResourceGroup subRegions = new DownloadResourceGroup(mainGrp, DownloadResourceGroupType.SUBREGIONS); mainGrp.addGroup(subRegions); // add to processing queue - for(WorldRegion rg : subregions) { + for (WorldRegion rg : subregions) { queue.add(rg); parent.add(subRegions); - } + } } // Possible improvements // 1. if there is no subregions no need to create resource group REGIONS_MAPS - objection raise diversity and there is no value @@ -455,8 +459,8 @@ public class DownloadResources extends DownloadResourceGroup { } otherGroup.addGroup(voiceScreenTTS); otherGroup.addGroup(voiceScreenRec); - - + + if (fonts.getIndividualResources() != null) { otherGroup.addGroup(fontScreen); } @@ -465,9 +469,87 @@ public class DownloadResources extends DownloadResourceGroup { createHillshadeSRTMGroups(); trimEmptyGroups(); updateLoadedFiles(); + collectMultipleIndexesItems(region); return true; } + private void collectMultipleIndexesItems(@NonNull WorldRegion region) { + List subRegions = region.getSubregions(); + if (Algorithms.isEmpty(subRegions)) return; + + DownloadResourceGroup group = getRegionMapsGroup(region); + if (group != null) { + boolean listModified = false; + List indexesList = group.getIndividualResources(); + for (DownloadActivityType type : DownloadActivityType.values()) { + if (!doesListContainIndexWithType(indexesList, type)) { + List indexesFromSubRegions = collectIndexesOfType(subRegions, type); + if (indexesFromSubRegions != null) { + group.addItem(new MultipleIndexItem(region, indexesFromSubRegions, type)); + listModified = true; + } + } + } + if (listModified) { + sortDownloadItems(group.getIndividualDownloadItems()); + } + } + for (WorldRegion subRegion : subRegions) { + collectMultipleIndexesItems(subRegion); + } + } + + private DownloadResourceGroup getRegionMapsGroup(WorldRegion region) { + DownloadResourceGroup group = getRegionGroup(region); + if (group != null) { + return group.getSubGroupById(REGION_MAPS.getDefaultId()); + } + return null; + } + + @Nullable + private List collectIndexesOfType(@NonNull List regions, + @NonNull DownloadActivityType type) { + Map collectedIndexes = new LinkedHashMap<>(); + for (WorldRegion region : regions) { + List regionIndexes = getIndexItems(region); + boolean found = false; + if (regionIndexes != null) { + for (IndexItem index : regionIndexes) { + if (index.getType() == type) { + found = true; + collectedIndexes.put(region, index); + break; + } + } + } + if (!found) return null; + } + return removeDuplicates(collectedIndexes); + } + + private List removeDuplicates(Map collectedIndexes) { + List regions = new ArrayList<>(collectedIndexes.keySet()); + // collect duplicates + Set duplicates = new HashSet<>(); + for (int i = 0; i < regions.size() - 1; i++) { + WorldRegion firstRegion = regions.get(i); + for (int j = i + 1; j < regions.size(); j++) { + WorldRegion secondRegion = regions.get(j); + if (WorldRegion.isFirstRegionInsideTheSecond(firstRegion, secondRegion)) { + duplicates.add(firstRegion); + } else if (WorldRegion.isFirstRegionInsideTheSecond(secondRegion, firstRegion)) { + duplicates.add(secondRegion); + } + } + } + // remove duplicates + for (WorldRegion key : duplicates) { + collectedIndexes.remove(key); + } + return new ArrayList<>(collectedIndexes.values()); + } + private void buildRegionsGroups(WorldRegion region, DownloadResourceGroup group) { LinkedList queue = new LinkedList(); LinkedList parent = new LinkedList(); @@ -485,7 +567,7 @@ public class DownloadResources extends DownloadResourceGroup { CustomRegion customRegion = (CustomRegion) reg; List indexItems = customRegion.loadIndexItems(); if (!Algorithms.isEmpty(indexItems)) { - DownloadResourceGroup flatFiles = new DownloadResourceGroup(mainGrp, DownloadResourceGroupType.REGION_MAPS); + DownloadResourceGroup flatFiles = new DownloadResourceGroup(mainGrp, REGION_MAPS); for (IndexItem ii : indexItems) { flatFiles.addItem(ii); } @@ -557,7 +639,11 @@ public class DownloadResources extends DownloadResourceGroup { return res; } - public static List findIndexItemsAt(OsmandApplication app, List names, DownloadActivityType type, boolean includeDownloaded, int limit) { + public static List findIndexItemsAt(OsmandApplication app, + List names, + DownloadActivityType type, + boolean includeDownloaded, + int limit) { List res = new ArrayList<>(); OsmandRegions regions = app.getRegions(); DownloadIndexesThread downloadThread = app.getDownloadThread(); @@ -573,8 +659,12 @@ public class DownloadResources extends DownloadResourceGroup { return res; } - private static boolean isIndexItemDownloaded(DownloadIndexesThread downloadThread, DownloadActivityType type, WorldRegion downloadRegion, List res) { - List otherIndexItems = new ArrayList<>(downloadThread.getIndexes().getIndexItems(downloadRegion)); + private static boolean isIndexItemDownloaded(DownloadIndexesThread downloadThread, + DownloadActivityType type, + WorldRegion downloadRegion, + List res) { + List otherIndexItems = + new ArrayList<>(downloadThread.getIndexes().getIndexItems(downloadRegion)); for (IndexItem indexItem : otherIndexItems) { if (indexItem.getType() == type && indexItem.isDownloaded()) { return true; @@ -584,8 +674,24 @@ public class DownloadResources extends DownloadResourceGroup { && isIndexItemDownloaded(downloadThread, type, downloadRegion.getSuperregion(), res); } - private static boolean addIndexItem(DownloadIndexesThread downloadThread, DownloadActivityType type, WorldRegion downloadRegion, List res) { - List otherIndexItems = new ArrayList<>(downloadThread.getIndexes().getIndexItems(downloadRegion)); + private boolean doesListContainIndexWithType(List indexItems, + DownloadActivityType type) { + if (indexItems != null) { + for (IndexItem indexItem : indexItems) { + if (indexItem.getType() == type) { + return true; + } + } + } + return false; + } + + private static boolean addIndexItem(DownloadIndexesThread downloadThread, + DownloadActivityType type, + WorldRegion downloadRegion, + List res) { + List otherIndexItems = + new ArrayList<>(downloadThread.getIndexes().getIndexItems(downloadRegion)); for (IndexItem indexItem : otherIndexItems) { if (indexItem.getType() == type && !res.contains(indexItem)) { diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadValidationManager.java b/OsmAnd/src/net/osmand/plus/download/DownloadValidationManager.java index 8e03b2c1e5..6b12fb6713 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadValidationManager.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadValidationManager.java @@ -192,7 +192,7 @@ public class DownloadValidationManager { } - public void makeSureUserCancelDownload(FragmentActivity ctx, final IndexItem item) { + public void makeSureUserCancelDownload(FragmentActivity ctx, final DownloadItem item) { AlertDialog.Builder bld = new AlertDialog.Builder(ctx); bld.setTitle(ctx.getString(R.string.shared_string_cancel)); bld.setMessage(R.string.confirm_interrupt_download); diff --git a/OsmAnd/src/net/osmand/plus/download/IndexItem.java b/OsmAnd/src/net/osmand/plus/download/IndexItem.java index 650ab0679b..a746d4aa90 100644 --- a/OsmAnd/src/net/osmand/plus/download/IndexItem.java +++ b/OsmAnd/src/net/osmand/plus/download/IndexItem.java @@ -1,12 +1,9 @@ package net.osmand.plus.download; -import android.content.Context; - import androidx.annotation.NonNull; import net.osmand.IndexConstants; import net.osmand.PlatformUtil; -import net.osmand.map.OsmandRegions; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.helpers.FileNameTranslationHelper; @@ -16,9 +13,11 @@ import org.apache.commons.logging.Log; import java.io.File; import java.io.IOException; import java.text.DateFormat; +import java.util.ArrayList; import java.util.Date; +import java.util.List; -public class IndexItem implements Comparable { +public class IndexItem extends DownloadItem implements Comparable { private static final Log log = PlatformUtil.getLog(IndexItem.class); String description; @@ -27,43 +26,44 @@ public class IndexItem implements Comparable { long timestamp; long contentSize; long containerSize; - DownloadActivityType type; boolean extra; // Update information boolean outdated; boolean downloaded; long localTimestamp; - DownloadResourceGroup relatedGroup; - - public IndexItem(String fileName, String description, long timestamp, String size, long contentSize, - long containerSize, @NonNull DownloadActivityType tp) { + public IndexItem(String fileName, + String description, + long timestamp, + String size, + long contentSize, + long containerSize, + @NonNull DownloadActivityType type) { + super(type); this.fileName = fileName; this.description = description; this.timestamp = timestamp; this.size = size; this.contentSize = contentSize; this.containerSize = containerSize; - this.type = tp; - } - - public DownloadActivityType getType() { - return type; - } - - public void setRelatedGroup(DownloadResourceGroup relatedGroup) { - this.relatedGroup = relatedGroup; - } - - public DownloadResourceGroup getRelatedGroup() { - return relatedGroup; } + @Override public String getFileName() { return fileName; } + @NonNull + @Override + public List getDownloadedFiles(OsmandApplication app) { + File targetFile = getTargetFile(app); + List result = new ArrayList<>(); + if (targetFile.exists()) { + result.add(targetFile); + } + return result; + } public String getDescription() { return description; @@ -89,10 +89,14 @@ public class IndexItem implements Comparable { return ((double)containerSize) / (1 << 20); } - public String getSizeDescription(Context ctx) { - return ctx.getString(R.string.ltr_or_rtl_combine_via_space, size, "MB"); + @Override + protected double getSizeToDownloadInMb() { + try { + return Double.parseDouble(size); + } catch (Exception e) { + return 0; + } } - public DownloadEntry createDownloadEntry(OsmandApplication ctx) { String fileName = this.fileName; @@ -132,11 +136,8 @@ public class IndexItem implements Comparable { return type.getTargetFileName(this); } - public String getBasename() { - return type.getBasename(this); - } - - public File getTargetFile(OsmandApplication ctx) { + @NonNull + public File getTargetFile(@NonNull OsmandApplication ctx) { String basename = getTranslatedBasename(); return new File(type.getDownloadFolder(ctx, this), basename + type.getUnzipExtension(ctx, this)); } @@ -190,7 +191,7 @@ public class IndexItem implements Comparable { && getType() != DownloadActivityType.HILLSHADE_FILE && getType() != DownloadActivityType.SLOPE_FILE; } - + public void setOutdated(boolean outdated) { this.outdated = outdated; } @@ -198,7 +199,12 @@ public class IndexItem implements Comparable { public void setDownloaded(boolean downloaded) { this.downloaded = downloaded; } - + + @Override + public boolean hasActualDataToDownload() { + return !isDownloaded() || isOutdated(); + } + public void setLocalTimestamp(long localTimestamp) { this.localTimestamp = localTimestamp; } @@ -211,20 +217,11 @@ public class IndexItem implements Comparable { return downloaded; } - public String getVisibleName(Context ctx, OsmandRegions osmandRegions) { - return type.getVisibleName(this, ctx, osmandRegions, true); + @Override + public boolean isDownloading(DownloadIndexesThread thread) { + return thread.isDownloading(this); } - public String getVisibleName(Context ctx, OsmandRegions osmandRegions, boolean includingParent) { - return type.getVisibleName(this, ctx, osmandRegions, includingParent); - } - - public String getVisibleDescription(OsmandApplication clctx) { - return type.getVisibleDescription(this, clctx); - } - - - public String getDate(java.text.DateFormat format) { return format.format(new Date(timestamp)); } diff --git a/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java b/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java new file mode 100644 index 0000000000..e28d606653 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java @@ -0,0 +1,122 @@ +package net.osmand.plus.download; + +import androidx.annotation.NonNull; + +import net.osmand.map.WorldRegion; +import net.osmand.plus.OsmandApplication; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class MultipleIndexItem extends DownloadItem { + + private final List items; + + public MultipleIndexItem(@NonNull WorldRegion region, + @NonNull List items, + @NonNull DownloadActivityType type) { + super(type); + this.items = items; + } + + public List getAllIndexes() { + return items; + } + + @Override + public boolean isOutdated() { + for (IndexItem item : items) { + if (item.isOutdated()) { + return true; + } + } + return false; + } + + @Override + public boolean isDownloaded() { + for (IndexItem item : items) { + if (item.isDownloaded()) { + return true; + } + } + return false; + } + + @Override + public boolean isDownloading(DownloadIndexesThread thread) { + for (IndexItem item : items) { + if (thread.isDownloading(item)) { + return true; + } + } + return false; + } + + @Override + public String getFileName() { + // The file name is used in many places. + // But in the case of a Multiple Indexes element it's not use in most cases. + // File is not created for Multiple Indexes element, + // and all file names are available in internal IndexItem elements. + + // The only one place where a filename may be needed + // is to generate the base and display names. + // Since these names are generated based on the filename. + // But now we don't need a name for display, + // because on all screens where we now use multiple elements item, + // for display used a type name instead of a file name. + + // Later, if you need a file name, + // you can try to create it based on the WorldRegion + // and file name of one of the internal IndexItem elements. + return ""; + } + + @NonNull + @Override + public List getDownloadedFiles(OsmandApplication app) { + List result = new ArrayList<>(); + for (IndexItem item : items) { + result.addAll(item.getDownloadedFiles(app)); + } + return result; + } + + public List getIndexesToDownload() { + List indexesToDownload = new ArrayList<>(); + for (IndexItem item : items) { + if (item.hasActualDataToDownload()) { + indexesToDownload.add(item); + } + } + return indexesToDownload; + } + + @Override + public boolean hasActualDataToDownload() { + return getIndexesToDownload().size() > 0; + } + + @Override + public double getSizeToDownloadInMb() { + double totalSizeMb = 0.0d; + for (IndexItem item : items) { + if (item.hasActualDataToDownload()) { + totalSizeMb += Double.parseDouble(item.size); + } + } + return totalSizeMb; + } + + @Override + public double getArchiveSizeMB() { + double result = 0.0d; + for (IndexItem item : items) { + result += item.getArchiveSizeMB(); + } + return result; + } + +} diff --git a/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupAdapter.java b/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupAdapter.java index a212dd5e31..d2e281bbfc 100644 --- a/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupAdapter.java +++ b/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupAdapter.java @@ -10,9 +10,9 @@ import android.widget.TextView; import net.osmand.plus.R; import net.osmand.plus.activities.OsmandBaseExpandableListAdapter; import net.osmand.plus.download.CustomIndexItem; +import net.osmand.plus.download.DownloadItem; import net.osmand.plus.download.DownloadActivity; import net.osmand.plus.download.DownloadResourceGroup; -import net.osmand.plus.download.IndexItem; import java.util.ArrayList; import java.util.List; @@ -52,9 +52,9 @@ public class DownloadResourceGroupAdapter extends OsmandBaseExpandableListAdapte public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { final Object child = getChild(groupPosition, childPosition); - if (child instanceof IndexItem) { + if (child instanceof DownloadItem) { - IndexItem item = (IndexItem) child; + DownloadItem item = (DownloadItem) child; DownloadResourceGroup group = getGroupObj(groupPosition); ItemViewHolder viewHolder; if (convertView != null && convertView.getTag() instanceof ItemViewHolder) { diff --git a/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java b/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java index 70041a525e..7fd4172fce 100644 --- a/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java +++ b/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java @@ -17,11 +17,14 @@ import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.PopupMenu; import androidx.core.view.ViewCompat; +import net.osmand.map.OsmandRegions; import net.osmand.map.WorldRegion; +import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.Version; import net.osmand.plus.activities.LocalIndexHelper.LocalIndexType; @@ -31,11 +34,13 @@ import net.osmand.plus.activities.PluginsFragment; import net.osmand.plus.chooseplan.ChoosePlanDialogFragment; import net.osmand.plus.download.CityItem; import net.osmand.plus.download.CustomIndexItem; +import net.osmand.plus.download.DownloadItem; import net.osmand.plus.download.DownloadActivity; import net.osmand.plus.download.DownloadActivityType; import net.osmand.plus.download.DownloadResourceGroup; import net.osmand.plus.download.DownloadResources; import net.osmand.plus.download.IndexItem; +import net.osmand.plus.download.MultipleIndexItem; import net.osmand.plus.download.ui.LocalIndexesFragment.LocalIndexOperationTask; import net.osmand.plus.helpers.FileNameTranslationHelper; import net.osmand.plus.inapp.InAppPurchaseHelper; @@ -43,6 +48,8 @@ import net.osmand.util.Algorithms; import java.io.File; import java.text.DateFormat; +import java.util.ArrayList; +import java.util.List; public class ItemViewHolder { @@ -137,24 +144,24 @@ public class ItemViewHolder { depthContoursPurchased = InAppPurchaseHelper.isDepthContoursPurchased(context.getMyApplication()); } - public void bindIndexItem(final IndexItem indexItem) { - bindIndexItem(indexItem, null); + public void bindIndexItem(final DownloadItem downloadItem) { + bindIndexItem(downloadItem, null); } - public void bindIndexItem(final IndexItem indexItem, final String cityName) { + public void bindIndexItem(final DownloadItem downloadItem, final String cityName) { initAppStatusVariables(); - boolean isDownloading = context.getDownloadThread().isDownloading(indexItem); + boolean isDownloading = downloadItem.isDownloading(context.getDownloadThread()); int progress = -1; - if (context.getDownloadThread().getCurrentDownloadingItem() == indexItem) { + if (context.getDownloadThread().getCurrentDownloadingItem() == downloadItem) { progress = context.getDownloadThread().getCurrentDownloadingItemProgress(); } - boolean disabled = checkDisabledAndClickAction(indexItem); + boolean disabled = checkDisabledAndClickAction(downloadItem); /// name and left item String name; if(showTypeInName) { - name = indexItem.getType().getString(context); + name = downloadItem.getType().getString(context); } else { - name = indexItem.getVisibleName(context, context.getMyApplication().getRegions(), showParentRegionName); + name = downloadItem.getVisibleName(context, context.getMyApplication().getRegions(), showParentRegionName); } String text = (!Algorithms.isEmpty(cityName) && !cityName.equals(name) ? cityName + "\n" : "") + name; nameTextView.setText(text); @@ -164,43 +171,78 @@ public class ItemViewHolder { nameTextView.setTextColor(textColorSecondary); } int color = textColorSecondary; - if(indexItem.isDownloaded() && !isDownloading) { - int colorId = indexItem.isOutdated() ? R.color.color_distance : R.color.color_ok; + if(downloadItem.isDownloaded() && !isDownloading) { + int colorId = downloadItem.isOutdated() ? R.color.color_distance : R.color.color_ok; color = context.getResources().getColor(colorId); } - if (indexItem.isDownloaded()) { + if (downloadItem.isDownloaded()) { leftImageView.setImageDrawable(getContentIcon(context, - indexItem.getType().getIconResource(), color)); + downloadItem.getType().getIconResource(), color)); } else if (disabled) { leftImageView.setImageDrawable(getContentIcon(context, - indexItem.getType().getIconResource(), textColorSecondary)); + downloadItem.getType().getIconResource(), textColorSecondary)); } else { leftImageView.setImageDrawable(getContentIcon(context, - indexItem.getType().getIconResource())); + downloadItem.getType().getIconResource())); } descrTextView.setTextColor(textColorSecondary); if (!isDownloading) { progressBar.setVisibility(View.GONE); descrTextView.setVisibility(View.VISIBLE); - if (indexItem instanceof CustomIndexItem && (((CustomIndexItem) indexItem).getSubName(context) != null)) { - descrTextView.setText(((CustomIndexItem) indexItem).getSubName(context)); - } else if (indexItem.getType() == DownloadActivityType.DEPTH_CONTOUR_FILE && !depthContoursPurchased) { + if (downloadItem instanceof CustomIndexItem && (((CustomIndexItem) downloadItem).getSubName(context) != null)) { + descrTextView.setText(((CustomIndexItem) downloadItem).getSubName(context)); + } else if (downloadItem.getType() == DownloadActivityType.DEPTH_CONTOUR_FILE && !depthContoursPurchased) { descrTextView.setText(context.getString(R.string.depth_contour_descr)); - } else if ((indexItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE - || indexItem.getType() == DownloadActivityType.HILLSHADE_FILE - || indexItem.getType() == DownloadActivityType.SLOPE_FILE) && srtmDisabled) { + } else if ((downloadItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE + || downloadItem.getType() == DownloadActivityType.HILLSHADE_FILE + || downloadItem.getType() == DownloadActivityType.SLOPE_FILE) && srtmDisabled) { if (showTypeInName) { descrTextView.setText(""); } else { - descrTextView.setText(indexItem.getType().getString(context)); + descrTextView.setText(downloadItem.getType().getString(context)); } - } else if (showTypeInDesc) { - descrTextView.setText(indexItem.getType().getString(context) + - " • " + indexItem.getSizeDescription(context) + - " • " + (showRemoteDate ? indexItem.getRemoteDate(dateFormat) : indexItem.getLocalDate(dateFormat))); + } else if (downloadItem instanceof MultipleIndexItem) { + MultipleIndexItem item = (MultipleIndexItem) downloadItem; + String allRegionsHeader = context.getString(R.string.shared_strings_all_regions); + String regionsHeader = context.getString(R.string.regions); + String allRegionsCount = String.valueOf(item.getAllIndexes().size()); + String leftToDownloadCount = String.valueOf(item.getIndexesToDownload().size()); + String header; + String count; + if (item.hasActualDataToDownload()) { + if (!item.isDownloaded()) { + header = allRegionsHeader; + count = leftToDownloadCount; + } else { + header = regionsHeader; + count = String.format( + context.getString(R.string.ltr_or_rtl_combine_via_slash), + leftToDownloadCount, + allRegionsCount); + } + } else { + header = allRegionsHeader; + count = allRegionsCount; + } + String fullDescription = + context.getString(R.string.ltr_or_rtl_combine_via_colon, header, count); + if (item.hasActualDataToDownload()) { + fullDescription = context.getString( + R.string.ltr_or_rtl_combine_via_bold_point, fullDescription, + item.getSizeDescription(context)); + } + descrTextView.setText(fullDescription); } else { - descrTextView.setText(indexItem.getSizeDescription(context) + " • " + - (showRemoteDate ? indexItem.getRemoteDate(dateFormat) : indexItem.getLocalDate(dateFormat))); + IndexItem item = (IndexItem) downloadItem; + String pattern = context.getString(R.string.ltr_or_rtl_combine_via_bold_point); + String type = item.getType().getString(context); + String size = item.getSizeDescription(context); + String date = showRemoteDate ? item.getRemoteDate(dateFormat) : item.getLocalDate(dateFormat); + String fullDescription = String.format(pattern, size, date); + if (showTypeInDesc) { + fullDescription = String.format(pattern, type, fullDescription); + } + descrTextView.setText(fullDescription); } } else { @@ -209,18 +251,19 @@ public class ItemViewHolder { progressBar.setProgress(progress); if (showProgressInDesc) { - double mb = indexItem.getArchiveSizeMB(); + double mb = downloadItem.getArchiveSizeMB(); String v ; if (progress != -1) { v = context.getString(R.string.value_downloaded_of_max, mb * progress / 100, mb); } else { v = context.getString(R.string.file_size_in_mb, mb); } - if(showTypeInDesc && indexItem.getType() == DownloadActivityType.ROADS_FILE) { - descrTextView.setText(indexItem.getType().getString(context) + " • " + v); - } else { - descrTextView.setText(v); + String fullDescription = v; + if(showTypeInDesc && downloadItem.getType() == DownloadActivityType.ROADS_FILE) { + fullDescription = context.getString(R.string.ltr_or_rtl_combine_via_bold_point, + downloadItem.getType().getString(context), fullDescription); } + descrTextView.setText(fullDescription); descrTextView.setVisibility(View.VISIBLE); } else { descrTextView.setVisibility(View.GONE); @@ -241,44 +284,7 @@ public class ItemViewHolder { } } - protected void download(IndexItem indexItem, DownloadResourceGroup parentOptional) { - boolean handled = false; - if(parentOptional != null) { - WorldRegion region = DownloadResourceGroup.getRegion(parentOptional); - context.setDownloadItem(region, indexItem.getTargetFile(context.getMyApplication()).getAbsolutePath()); - } - if (indexItem.getType() == DownloadActivityType.ROADS_FILE && parentOptional != null) { - for (IndexItem ii : parentOptional.getIndividualResources()) { - if (ii.getType() == DownloadActivityType.NORMAL_FILE) { - if (ii.isDownloaded()) { - handled = true; - confirmDownload(indexItem); - } - break; - } - } - } - if(!handled) { - context.startDownload(indexItem); - } - } - private void confirmDownload(final IndexItem indexItem) { - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.are_you_sure); - builder.setMessage(R.string.confirm_download_roadmaps); - builder.setNegativeButton(R.string.shared_string_cancel, null).setPositiveButton( - R.string.shared_string_download, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (indexItem != null) { - context.startDownload(indexItem); - } - } - }); - builder.show(); - } - - private boolean checkDisabledAndClickAction(final IndexItem item) { + private boolean checkDisabledAndClickAction(final DownloadItem item) { RightButtonAction clickAction = getClickAction(item); boolean disabled = clickAction != RightButtonAction.DOWNLOAD; OnClickListener action = getRightButtonAction(item, clickAction); @@ -290,15 +296,15 @@ public class ItemViewHolder { } else { rightButton.setVisibility(View.GONE); rightImageButton.setVisibility(View.VISIBLE); - final boolean isDownloading = context.getDownloadThread().isDownloading(item); + final boolean isDownloading = item.isDownloading(context.getDownloadThread()); if (isDownloading) { rightImageButton.setImageDrawable(getContentIcon(context, R.drawable.ic_action_remove_dark)); rightImageButton.setContentDescription(context.getString(R.string.shared_string_cancel)); - } else if(item.isDownloaded() && !item.isOutdated()) { + } else if(!item.hasActualDataToDownload()) { rightImageButton.setImageDrawable(getContentIcon(context, R.drawable.ic_overflow_menu_white)); rightImageButton.setContentDescription(context.getString(R.string.shared_string_more)); } else { - rightImageButton.setImageDrawable(getContentIcon(context, R.drawable.ic_action_import)); + rightImageButton.setImageDrawable(getContentIcon(context, getDownloadActionIconId(item))); rightImageButton.setContentDescription(context.getString(R.string.shared_string_download)); } rightImageButton.setOnClickListener(action); @@ -307,31 +313,37 @@ public class ItemViewHolder { return disabled; } + private int getDownloadActionIconId(@NonNull DownloadItem item) { + return item instanceof MultipleIndexItem ? + R.drawable.ic_action_multi_download : + R.drawable.ic_action_import; + } + @SuppressLint("DefaultLocale") - public RightButtonAction getClickAction(final IndexItem indexItem) { + public RightButtonAction getClickAction(final DownloadItem item) { RightButtonAction clickAction = RightButtonAction.DOWNLOAD; - if (indexItem.getBasename().toLowerCase().equals(DownloadResources.WORLD_SEAMARKS_KEY) + if (item.getBasename().toLowerCase().equals(DownloadResources.WORLD_SEAMARKS_KEY) && nauticalPluginDisabled) { clickAction = RightButtonAction.ASK_FOR_SEAMARKS_PLUGIN; - } else if ((indexItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE - || indexItem.getType() == DownloadActivityType.HILLSHADE_FILE - || indexItem.getType() == DownloadActivityType.SLOPE_FILE) && srtmDisabled) { + } else if ((item.getType() == DownloadActivityType.SRTM_COUNTRY_FILE + || item.getType() == DownloadActivityType.HILLSHADE_FILE + || item.getType() == DownloadActivityType.SLOPE_FILE) && srtmDisabled) { if (srtmNeedsInstallation) { clickAction = RightButtonAction.ASK_FOR_SRTM_PLUGIN_PURCHASE; } else { clickAction = RightButtonAction.ASK_FOR_SRTM_PLUGIN_ENABLE; } - } else if (indexItem.getType() == DownloadActivityType.WIKIPEDIA_FILE + } else if (item.getType() == DownloadActivityType.WIKIPEDIA_FILE && !Version.isPaidVersion(context.getMyApplication())) { clickAction = RightButtonAction.ASK_FOR_FULL_VERSION_PURCHASE; - } else if (indexItem.getType() == DownloadActivityType.DEPTH_CONTOUR_FILE && !depthContoursPurchased) { + } else if (item.getType() == DownloadActivityType.DEPTH_CONTOUR_FILE && !depthContoursPurchased) { clickAction = RightButtonAction.ASK_FOR_DEPTH_CONTOURS_PURCHASE; } return clickAction; } - public OnClickListener getRightButtonAction(final IndexItem item, final RightButtonAction clickAction) { + public OnClickListener getRightButtonAction(final DownloadItem item, final RightButtonAction clickAction) { if (clickAction != RightButtonAction.DOWNLOAD) { return new View.OnClickListener() { @Override @@ -370,7 +382,7 @@ public class ItemViewHolder { } }; } else { - final boolean isDownloading = context.getDownloadThread().isDownloading(item); + final boolean isDownloading = item.isDownloading(context.getDownloadThread()); return new View.OnClickListener() { @Override public void onClick(View v) { @@ -380,8 +392,8 @@ public class ItemViewHolder { } else { context.makeSureUserCancelDownload(item); } - } else if(item.isDownloaded() && !item.isOutdated()){ - contextMenu(v, item, item.getRelatedGroup()); + } else if(!item.hasActualDataToDownload()){ + showContextMenu(v, item, item.getRelatedGroup()); } else { download(item, item.getRelatedGroup()); } @@ -390,52 +402,21 @@ public class ItemViewHolder { } } - protected void contextMenu(View v, final IndexItem indexItem, final DownloadResourceGroup parentOptional) { - final PopupMenu optionsMenu = new PopupMenu(context, v); + protected void showContextMenu(View v, + final DownloadItem downloadItem, + final DownloadResourceGroup parentOptional) { + OsmandApplication app = context.getMyApplication(); + PopupMenu optionsMenu = new PopupMenu(context, v); MenuItem item; - - final File fl = indexItem.getTargetFile(context.getMyApplication()); - if (fl.exists()) { - item = optionsMenu.getMenu().add(R.string.shared_string_remove).setIcon( - context.getMyApplication().getUIUtilities().getThemedIcon(R.drawable.ic_action_remove_dark)); + + final List downloadedFiles = downloadItem.getDownloadedFiles(app); + if (!Algorithms.isEmpty(downloadedFiles)) { + item = optionsMenu.getMenu().add(R.string.shared_string_remove) + .setIcon(getThemedIcon(context, R.drawable.ic_action_remove_dark)); item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { - LocalIndexType tp = LocalIndexType.MAP_DATA; - if (indexItem.getType() == DownloadActivityType.HILLSHADE_FILE) { - tp = LocalIndexType.TILES_DATA; - } else if (indexItem.getType() == DownloadActivityType.SLOPE_FILE) { - tp = LocalIndexType.TILES_DATA; - } else if (indexItem.getType() == DownloadActivityType.ROADS_FILE) { - tp = LocalIndexType.MAP_DATA; - } else if (indexItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE) { - tp = LocalIndexType.SRTM_DATA; - } else if (indexItem.getType() == DownloadActivityType.WIKIPEDIA_FILE) { - tp = LocalIndexType.MAP_DATA; - } else if (indexItem.getType() == DownloadActivityType.WIKIVOYAGE_FILE) { - tp = LocalIndexType.MAP_DATA; - } else if (indexItem.getType() == DownloadActivityType.TRAVEL_FILE) { - tp = LocalIndexType.MAP_DATA; - } else if (indexItem.getType() == DownloadActivityType.FONT_FILE) { - tp = LocalIndexType.FONT_DATA; - } else if (indexItem.getType() == DownloadActivityType.VOICE_FILE) { - tp = indexItem.getBasename().contains("tts") ? LocalIndexType.TTS_VOICE_DATA - : LocalIndexType.VOICE_DATA; - } - final LocalIndexInfo info = new LocalIndexInfo(tp, fl, false, context.getMyApplication()); - AlertDialog.Builder confirm = new AlertDialog.Builder(context); - confirm.setPositiveButton(R.string.shared_string_yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - new LocalIndexOperationTask(context, null, LocalIndexOperationTask.DELETE_OPERATION) - .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, info); - } - }); - confirm.setNegativeButton(R.string.shared_string_no, null); - String fn = FileNameTranslationHelper.getFileName(context, context.getMyApplication().getRegions(), - indexItem.getVisibleName(context, context.getMyApplication().getRegions())); - confirm.setMessage(context.getString(R.string.delete_confirmation_msg, fn)); - confirm.show(); + confirmRemove(downloadItem, downloadedFiles); return true; } }); @@ -445,14 +426,144 @@ public class ItemViewHolder { item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { - download(indexItem, parentOptional); + download(downloadItem, parentOptional); return true; } }); - + optionsMenu.show(); } + protected void download(DownloadItem item, DownloadResourceGroup parentOptional) { + boolean handled = false; + if (parentOptional != null && item instanceof IndexItem) { + IndexItem indexItem = (IndexItem) item; + WorldRegion region = DownloadResourceGroup.getRegion(parentOptional); + context.setDownloadItem(region, indexItem.getTargetFile(context.getMyApplication()).getAbsolutePath()); + } + if (item.getType() == DownloadActivityType.ROADS_FILE && parentOptional != null) { + for (IndexItem ii : parentOptional.getIndividualResources()) { + if (ii.getType() == DownloadActivityType.NORMAL_FILE) { + if (ii.isDownloaded()) { + handled = true; + confirmDownload(item); + } + break; + } + } + } + if(!handled) { + startDownload(item); + } + } + private void confirmDownload(final DownloadItem item) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.are_you_sure); + builder.setMessage(R.string.confirm_download_roadmaps); + builder.setNegativeButton(R.string.shared_string_cancel, null).setPositiveButton( + R.string.shared_string_download, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (item != null) { + startDownload(item); + } + } + }); + builder.show(); + } + + private void startDownload(DownloadItem item) { + if (item instanceof MultipleIndexItem) { + MultipleIndexItem multipleIndexItem = (MultipleIndexItem) item; + List indexes; + if (multipleIndexItem.hasActualDataToDownload()) { + // download left regions + indexes = multipleIndexItem.getIndexesToDownload(); + } else { + // download all regions again + indexes = multipleIndexItem.getAllIndexes(); + } + IndexItem[] indexesArray = new IndexItem[indexes.size()]; + context.startDownload(indexes.toArray(indexesArray)); + } else if (item instanceof IndexItem) { + IndexItem indexItem = (IndexItem) item; + context.startDownload(indexItem); + } + } + + private void confirmRemove(@NonNull final DownloadItem downloadItem, + @NonNull final List downloadedFiles) { + OsmandApplication app = context.getMyApplication(); + AlertDialog.Builder confirm = new AlertDialog.Builder(context); + + String message; + if (downloadedFiles.size() > 1) { + message = context.getString(R.string.delete_number_files_question, downloadedFiles.size()); + } else { + OsmandRegions regions = app.getRegions(); + String visibleName = downloadItem.getVisibleName(context, regions); + String fileName = FileNameTranslationHelper.getFileName(context, regions, visibleName); + message = context.getString(R.string.delete_confirmation_msg, fileName); + } + confirm.setMessage(message); + + confirm.setPositiveButton(R.string.shared_string_yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + LocalIndexType type = getLocalIndexType(downloadItem); + remove(type, downloadedFiles); + } + }); + confirm.setNegativeButton(R.string.shared_string_no, null); + + confirm.show(); + } + + private void remove(@NonNull LocalIndexType type, + @NonNull List filesToDelete) { + OsmandApplication app = context.getMyApplication(); + LocalIndexOperationTask removeTask = new LocalIndexOperationTask( + context, + null, + LocalIndexOperationTask.DELETE_OPERATION); + LocalIndexInfo[] params = new LocalIndexInfo[filesToDelete.size()]; + for (int i = 0; i < filesToDelete.size(); i++) { + File file = filesToDelete.get(i); + params[i] = new LocalIndexInfo(type, file, false, app); + } + removeTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params); + } + + @NonNull + private LocalIndexType getLocalIndexType(@NonNull DownloadItem downloadItem) { + LocalIndexType type = LocalIndexType.MAP_DATA; + if (downloadItem.getType() == DownloadActivityType.HILLSHADE_FILE) { + type = LocalIndexType.TILES_DATA; + } else if (downloadItem.getType() == DownloadActivityType.SLOPE_FILE) { + type = LocalIndexType.TILES_DATA; + } else if (downloadItem.getType() == DownloadActivityType.ROADS_FILE) { + type = LocalIndexType.MAP_DATA; + } else if (downloadItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE) { + type = LocalIndexType.SRTM_DATA; + } else if (downloadItem.getType() == DownloadActivityType.WIKIPEDIA_FILE) { + type = LocalIndexType.MAP_DATA; + } else if (downloadItem.getType() == DownloadActivityType.WIKIVOYAGE_FILE) { + type = LocalIndexType.MAP_DATA; + } else if (downloadItem.getType() == DownloadActivityType.TRAVEL_FILE) { + type = LocalIndexType.MAP_DATA; + } else if (downloadItem.getType() == DownloadActivityType.FONT_FILE) { + type = LocalIndexType.FONT_DATA; + } else if (downloadItem.getType() == DownloadActivityType.VOICE_FILE) { + type = downloadItem.getBasename().contains("tts") ? LocalIndexType.TTS_VOICE_DATA + : LocalIndexType.VOICE_DATA; + } + return type; + } + + private Drawable getThemedIcon(DownloadActivity context, int resourceId) { + return context.getMyApplication().getUIUtilities().getThemedIcon(resourceId); + } + private Drawable getContentIcon(DownloadActivity context, int resourceId) { return context.getMyApplication().getUIUtilities().getThemedIcon(resourceId); } diff --git a/OsmAnd/src/net/osmand/plus/download/ui/UpdatesIndexFragment.java b/OsmAnd/src/net/osmand/plus/download/ui/UpdatesIndexFragment.java index f7362edc76..faf39a56f7 100644 --- a/OsmAnd/src/net/osmand/plus/download/ui/UpdatesIndexFragment.java +++ b/OsmAnd/src/net/osmand/plus/download/ui/UpdatesIndexFragment.java @@ -153,7 +153,8 @@ public class UpdatesIndexFragment extends OsmAndListFragment implements Download for (IndexItem indexItem : indexItems) { downloadsSize += indexItem.getSize(); } - String updateAllText = getActivity().getString(R.string.update_all, downloadsSize >> 20); + String updateAllText = getActivity().getString( + R.string.update_all, String.valueOf(downloadsSize >> 20)); updateAllButton.setText(updateAllText); updateAllButton.setOnClickListener(new View.OnClickListener() { @Override From 63351ebf66b086c840e278c6cc24b3a544ed6b2b Mon Sep 17 00:00:00 2001 From: Skalii Date: Sat, 13 Feb 2021 05:57:28 +0200 Subject: [PATCH 26/45] fix vertical arrow alignment; fix blocks within width 60dp-120dp --- OsmAnd/res/layout/favorites_list_item.xml | 1 + OsmAnd/res/layout/gpx_overview_fragment.xml | 10 ++++++---- OsmAnd/res/layout/item_gpx_stat_block.xml | 9 +++++---- .../plus/track/GpxBlockStatisticsBuilder.java | 15 +++++++++++---- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/OsmAnd/res/layout/favorites_list_item.xml b/OsmAnd/res/layout/favorites_list_item.xml index d53497c0f5..b444aae2ac 100644 --- a/OsmAnd/res/layout/favorites_list_item.xml +++ b/OsmAnd/res/layout/favorites_list_item.xml @@ -93,6 +93,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" + android:layout_marginTop="1sp" android:contentDescription="@string/show_view_angle" osmand:srcCompat="@drawable/ic_direction_arrow" /> diff --git a/OsmAnd/res/layout/gpx_overview_fragment.xml b/OsmAnd/res/layout/gpx_overview_fragment.xml index 3b205ae60e..e613260e86 100644 --- a/OsmAnd/res/layout/gpx_overview_fragment.xml +++ b/OsmAnd/res/layout/gpx_overview_fragment.xml @@ -38,21 +38,23 @@ android:layout_height="wrap_content" android:layout_marginStart="@dimen/content_padding" android:layout_marginLeft="@dimen/content_padding" - android:gravity="center" - android:orientation="horizontal" - android:paddingTop="@dimen/dash_margin" - android:paddingBottom="@dimen/dash_margin"> + android:layout_marginTop="@dimen/dash_margin" + android:layout_marginBottom="@dimen/dash_margin" + android:orientation="horizontal"> @@ -61,8 +60,10 @@ android:layout_height="wrap_content" android:background="@null" android:ellipsize="end" + android:gravity="start|center_vertical" android:lines="1" android:maxWidth="@dimen/grid_menu_item_width" + android:minWidth="@dimen/map_route_buttons_width" android:textColor="?android:attr/textColorSecondary" android:textSize="@dimen/default_desc_text_size" tools:text="@string/distance" /> diff --git a/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java b/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java index 0c1b77a1fa..75bd8f58bb 100644 --- a/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java +++ b/OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java @@ -32,6 +32,7 @@ import net.osmand.plus.widgets.TextViewEx; import net.osmand.util.Algorithms; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public class GpxBlockStatisticsBuilder { @@ -232,12 +233,10 @@ public class GpxBlockStatisticsBuilder { public void onBindViewHolder(BlockStatisticsViewHolder holder, int position) { final StatBlock item = items.get(position); holder.valueText.setText(item.value); - holder.titleText.setText(item.title); - if (updateRunning) { - holder.titleText.setWidth(app.getResources().getDimensionPixelSize(R.dimen.map_route_buttons_width)); - } holder.valueText.setTextColor(activeColor); + holder.titleText.setText(item.title); holder.titleText.setTextColor(app.getResources().getColor(R.color.text_color_secondary_light)); + holder.titleText.setWidth(calculateWidthWithin(item.title, item.value)); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -271,6 +270,14 @@ public class GpxBlockStatisticsBuilder { } } + public int calculateWidthWithin(String... texts) { + int textSize = app.getResources().getDimensionPixelSize(R.dimen.default_desc_text_size); + int textWidth = AndroidUtils.getTextMaxWidth(textSize, Arrays.asList(texts)); + int minWidth = AndroidUtils.dpToPx(app, 60); + int maxWidth = AndroidUtils.dpToPx(app, 120); + return Math.min(maxWidth, Math.max(minWidth, textWidth)); + } + private class BlockStatisticsViewHolder extends RecyclerView.ViewHolder { private final TextViewEx valueText; From b04115aad20c3ce37fc6632b68793c8639207140 Mon Sep 17 00:00:00 2001 From: Vitaliy Date: Sun, 14 Feb 2021 16:51:24 +0200 Subject: [PATCH 27/45] Add ability to choose gpx segment for routing --- .../layout/bottom_sheet_select_segment.xml | 2 - .../plus/activities/MapActivityActions.java | 6 +- .../osmand/plus/base/FailSafeFuntions.java | 3 + .../helpers/TrackSelectSegmentAdapter.java | 33 +++---- .../FollowTrackFragment.java | 42 ++++++--- .../osmand/plus/routing/RouteProvider.java | 73 +++++++++++----- .../plus/settings/backend/OsmandSettings.java | 5 +- .../track/TrackSelectSegmentBottomSheet.java | 87 ++++++++----------- 8 files changed, 138 insertions(+), 113 deletions(-) diff --git a/OsmAnd/res/layout/bottom_sheet_select_segment.xml b/OsmAnd/res/layout/bottom_sheet_select_segment.xml index ddfa37f927..ee4dfec006 100644 --- a/OsmAnd/res/layout/bottom_sheet_select_segment.xml +++ b/OsmAnd/res/layout/bottom_sheet_select_segment.xml @@ -45,7 +45,6 @@ android:textSize="@dimen/default_desc_text_size" osmand:typeface="@string/font_roboto_regular" /> - - ps = params.getPoints(settings.getContext()); mapActivity.getRoutingHelper().setGpxParams(params); settings.FOLLOW_THE_GPX_ROUTE.set(result.path); diff --git a/OsmAnd/src/net/osmand/plus/base/FailSafeFuntions.java b/OsmAnd/src/net/osmand/plus/base/FailSafeFuntions.java index d898505b76..46708ce5ae 100644 --- a/OsmAnd/src/net/osmand/plus/base/FailSafeFuntions.java +++ b/OsmAnd/src/net/osmand/plus/base/FailSafeFuntions.java @@ -134,6 +134,9 @@ public class FailSafeFuntions { if(settings.GPX_ROUTE_CALC.get()) { gpxRoute.setCalculateOsmAndRoute(true); } + if (settings.GPX_ROUTE_SEGMENT.get() != -1) { + gpxRoute.setSelectedSegment(settings.GPX_ROUTE_SEGMENT.get()); + } } else { gpxRoute = null; } diff --git a/OsmAnd/src/net/osmand/plus/helpers/TrackSelectSegmentAdapter.java b/OsmAnd/src/net/osmand/plus/helpers/TrackSelectSegmentAdapter.java index 96ceefed24..4f621b9161 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/TrackSelectSegmentAdapter.java +++ b/OsmAnd/src/net/osmand/plus/helpers/TrackSelectSegmentAdapter.java @@ -16,16 +16,18 @@ import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; +import net.osmand.plus.helpers.TrackSelectSegmentAdapter.TrackViewHolder; import net.osmand.util.MapUtils; import java.util.List; -public class TrackSelectSegmentAdapter extends RecyclerView.Adapter { +public class TrackSelectSegmentAdapter extends RecyclerView.Adapter { + private final OsmandApplication app; private final LayoutInflater themedInflater; private final UiUtilities iconsCache; private final List segments; - private GpxTrackAdapter.OnItemClickListener onItemClickListener; + private OnItemClickListener onItemClickListener; public TrackSelectSegmentAdapter(Context ctx, List segments) { app = (OsmandApplication) ctx.getApplicationContext(); @@ -36,17 +38,17 @@ public class TrackSelectSegmentAdapter extends RecyclerView.Adapter 1; String fileName = null; File file = null; if (!Algorithms.isEmpty(gpxFile.path)) { file = new File(gpxFile.path); - if (isTrackContainsMultiSegment) { - fileName = Algorithms.getFileNameWithoutExtension(file.getName()); - } else { - fileName = Algorithms.getFileNameWithoutExtension(file.getName()); - } + fileName = Algorithms.getFileNameWithoutExtension(file.getName()); } else if (!Algorithms.isEmpty(gpxFile.tracks)) { fileName = gpxFile.tracks.get(0).name; } if (Algorithms.isEmpty(fileName)) { fileName = app.getString(R.string.shared_string_gpx_track); } + GPXRouteParamsBuilder routeParams = app.getRoutingHelper().getCurrentGPXRoute(); + if (gpxFile.getNonEmptySegmentsCount() > 1 && routeParams != null && routeParams.getSelectedSegment() != -1) { + fileName = fileName + " segment " + (routeParams.getSelectedSegment() + 1); + } sortButton.setVisibility(View.GONE); GPXInfo gpxInfo = new GPXInfo(fileName, file != null ? file.lastModified() : 0, file != null ? file.length() : 0); TrackEditCard importTrackCard = new TrackEditCard(mapActivity, gpxInfo); @@ -497,10 +498,10 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca if (selectedGpxFile != null) { GPXFile gpxFile = selectedGpxFile.getGpxFile(); if (gpxFile.getNonEmptySegmentsCount() > 1) { - TrackSelectSegmentBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), gpxFile); + TrackSelectSegmentBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), gpxFile, this); } else { - updateSelectionMode(false); selectTrackToFollow(gpxFile); + updateSelectionMode(false); } } else { CallbackWithObject callback = new CallbackWithObject() { @@ -509,10 +510,10 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca MapActivity mapActivity = getMapActivity(); if (mapActivity != null) { if (result[0].getNonEmptySegmentsCount() > 1) { - TrackSelectSegmentBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), result[0]); + TrackSelectSegmentBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), result[0], FollowTrackFragment.this); } else { - updateSelectionMode(false); selectTrackToFollow(result[0]); + updateSelectionMode(false); } } return true; @@ -536,7 +537,7 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca app.initVoiceCommandPlayer(mapActivity, mode, true, null, false, false, true); } } - mapActivity.getMapActions().setGPXRouteParams(gpxFile, 1); + mapActivity.getMapActions().setGPXRouteParams(gpxFile); app.getTargetPointsHelper().updateRouteAndRefresh(true); app.getRoutingHelper().onSettingsChanged(true); } @@ -719,7 +720,6 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca } } - @Override public void routeWasCancelled() { @@ -734,4 +734,18 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca protected String getThemeInfoProviderTag() { return TAG; } + + @Override + public void onSegmentSelect(GPXFile gpxFile, int selectedSegment) { + selectTrackToFollow(gpxFile); + if (selectedSegment != -1) { + GPXRouteParamsBuilder paramsBuilder = app.getRoutingHelper().getCurrentGPXRoute(); + if (paramsBuilder != null) { + paramsBuilder.setSelectedSegment(selectedSegment); + app.getSettings().GPX_ROUTE_SEGMENT.set(selectedSegment); + app.getRoutingHelper().onSettingsChanged(true); + } + } + updateSelectionMode(false); + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java index b3b2a11ab6..051a5218fa 100644 --- a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java +++ b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java @@ -8,7 +8,6 @@ import android.util.Base64; import net.osmand.GPXUtilities; import net.osmand.GPXUtilities.GPXFile; import net.osmand.GPXUtilities.Route; -import net.osmand.GPXUtilities.Track; import net.osmand.GPXUtilities.TrkSegment; import net.osmand.GPXUtilities.WptPt; import net.osmand.Location; @@ -20,15 +19,15 @@ import net.osmand.data.LatLon; import net.osmand.data.LocationPoint; import net.osmand.data.WptLocationPoint; import net.osmand.plus.OsmandApplication; -import net.osmand.plus.onlinerouting.OnlineRoutingHelper; -import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine.OnlineRoutingResponse; -import net.osmand.plus.settings.backend.OsmandSettings; -import net.osmand.plus.settings.backend.CommonPreference; import net.osmand.plus.R; import net.osmand.plus.TargetPointsHelper; import net.osmand.plus.TargetPointsHelper.TargetPoint; +import net.osmand.plus.onlinerouting.OnlineRoutingHelper; +import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine.OnlineRoutingResponse; import net.osmand.plus.render.NativeOsmandLibrary; import net.osmand.plus.settings.backend.ApplicationMode; +import net.osmand.plus.settings.backend.CommonPreference; +import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.router.GeneralRouter; import net.osmand.router.GeneralRouter.RoutingParameter; import net.osmand.router.GeneralRouter.RoutingParameterType; @@ -161,6 +160,7 @@ public class RouteProvider { private boolean leftSide; private boolean passWholeRoute; private boolean calculateOsmAndRouteParts; + private int selectedSegment = -1; public GPXRouteParamsBuilder(GPXFile file, OsmandSettings settings) { leftSide = settings.DRIVING_REGION.get().leftHandDriving; @@ -191,6 +191,14 @@ public class RouteProvider { this.calculateOsmAndRoute = calculateOsmAndRoute; } + public int getSelectedSegment() { + return selectedSegment; + } + + public void setSelectedSegment(int selectedSegment) { + this.selectedSegment = selectedSegment; + } + public void setPassWholeRoute(boolean passWholeRoute) { this.passWholeRoute = passWholeRoute; } @@ -278,8 +286,9 @@ public class RouteProvider { wpt.add(new WptLocationPoint(w)); } } + int selectedSegment = builder.getSelectedSegment(); if (OSMAND_ROUTER_V2.equals(file.author)) { - route = parseOsmAndGPXRoute(points, file); + route = parseOsmAndGPXRoute(points, file, selectedSegment); routePoints = file.getRoutePoints(); if (reverse) { Collections.reverse(points); @@ -287,7 +296,7 @@ public class RouteProvider { } addMissingTurns = route != null && route.isEmpty(); } else if (file.isCloudmadeRouteFile() || OSMAND_ROUTER.equals(file.author)) { - directions = parseOsmAndGPXRoute(points, file, OSMAND_ROUTER.equals(file.author), builder.leftSide, 10); + directions = parseOsmAndGPXRoute(points, file, OSMAND_ROUTER.equals(file.author), builder.leftSide, 10, selectedSegment); if (OSMAND_ROUTER.equals(file.author) && file.hasRtePt()) { // For files generated by OSMAND_ROUTER use directions contained unaltered addMissingTurns = false; @@ -301,12 +310,16 @@ public class RouteProvider { } else { // first of all check tracks if (!useIntermediatePointsRTE) { - for (Track tr : file.tracks) { - if (!tr.generalTrack) { - for (TrkSegment tkSeg : tr.segments) { - for (WptPt pt : tkSeg.points) { - points.add(createLocation(pt)); - } + List segments = file.getNonEmptyTrkSegments(false); + if (selectedSegment != -1 && segments.size() > selectedSegment) { + TrkSegment segment = segments.get(selectedSegment); + for (WptPt p : segment.points) { + points.add(createLocation(p)); + } + } else { + for (TrkSegment tkSeg : segments) { + for (WptPt p : tkSeg.points) { + points.add(createLocation(p)); } } } @@ -998,35 +1011,49 @@ public class RouteProvider { return new RouteCalculationResult("Empty result"); } - private static List parseOsmAndGPXRoute(List points, GPXFile gpxFile) { - for (Track tr : gpxFile.tracks) { - for (TrkSegment ts : tr.segments) { + private static List parseOsmAndGPXRoute(List points, GPXFile gpxFile, int selectedSegment) { + List segments = gpxFile.getNonEmptyTrkSegments(false); + if (selectedSegment != -1 && segments.size() > selectedSegment) { + TrkSegment segment = segments.get(selectedSegment); + for (WptPt p : segment.points) { + points.add(createLocation(p)); + } + RouteImporter routeImporter = new RouteImporter(segment); + return routeImporter.importRoute(); + } else { + for (TrkSegment ts : segments) { for (WptPt p : ts.points) { points.add(createLocation(p)); } } + RouteImporter routeImporter = new RouteImporter(gpxFile); + return routeImporter.importRoute(); } - RouteImporter routeImporter = new RouteImporter(gpxFile); - return routeImporter.importRoute(); } private static List parseOsmAndGPXRoute(List points, GPXFile gpxFile, boolean osmandRouter, - boolean leftSide, float defSpeed) { + boolean leftSide, float defSpeed, int selectedSegment) { List directions = null; if (!osmandRouter) { for (WptPt pt : gpxFile.getPoints()) { points.add(createLocation(pt)); } } else { - for (Track tr : gpxFile.tracks) { - for (TrkSegment ts : tr.segments) { + List segments = gpxFile.getNonEmptyTrkSegments(false); + if (selectedSegment != -1 && segments.size() > selectedSegment) { + TrkSegment segment = segments.get(selectedSegment); + for (WptPt p : segment.points) { + points.add(createLocation(p)); + } + } else { + for (TrkSegment ts : segments) { for (WptPt p : ts.points) { points.add(createLocation(p)); } } } } - float[] distanceToEnd = new float[points.size()]; + float[] distanceToEnd = new float[points.size()]; for (int i = points.size() - 2; i >= 0; i--) { distanceToEnd[i] = distanceToEnd[i + 1] + points.get(i).distanceTo(points.get(i + 1)); } @@ -1307,7 +1334,7 @@ public class RouteProvider { GPXFile gpxFile = GPXUtilities.loadGPXFile(gpxStream); - dir = parseOsmAndGPXRoute(res, gpxFile, true, params.leftSide, params.mode.getDefaultSpeed()); + dir = parseOsmAndGPXRoute(res, gpxFile, true, params.leftSide, params.mode.getDefaultSpeed(), -1); if (dir != null) { addMissingTurns = false; diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java index 45cefd2723..9652fc3bad 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java @@ -45,10 +45,8 @@ import net.osmand.plus.helpers.enums.DrivingRegion; import net.osmand.plus.helpers.enums.MetricsConstants; import net.osmand.plus.helpers.enums.SpeedConstants; import net.osmand.plus.helpers.enums.TracksSortByMode; -import net.osmand.plus.mapillary.MapillaryPlugin; import net.osmand.plus.mapmarkers.CoordinateInputFormats.Format; import net.osmand.plus.mapmarkers.MapMarkersMode; -import net.osmand.plus.openplacereviews.OpenPlaceReviewsPlugin; import net.osmand.plus.profiles.LocationIcon; import net.osmand.plus.profiles.NavigationIcon; import net.osmand.plus.profiles.ProfileIconColors; @@ -1389,6 +1387,7 @@ public class OsmandSettings { public final OsmandPreference GPX_ROUTE_CALC_OSMAND_PARTS = new BooleanPreference(this, "gpx_routing_calculate_osmand_route", true).makeGlobal().makeShared().cache(); public final OsmandPreference GPX_CALCULATE_RTEPT = new BooleanPreference(this, "gpx_routing_calculate_rtept", true).makeGlobal().makeShared().cache(); public final OsmandPreference GPX_ROUTE_CALC = new BooleanPreference(this, "calc_gpx_route", false).makeGlobal().makeShared().cache(); + public final OsmandPreference GPX_ROUTE_SEGMENT = new IntPreference(this, "gpx_route_segment", -1).makeGlobal().makeShared().cache(); public final OsmandPreference SHOW_START_FINISH_ICONS = new BooleanPreference(this, "show_start_finish_icons", true).makeGlobal().makeShared().cache(); public final OsmandPreference AVOID_TOLL_ROADS = new BooleanPreference(this, "avoid_toll_roads", false).makeProfile().cache(); @@ -2594,7 +2593,7 @@ public class OsmandSettings { public static final String VOICE_PROVIDER_NOT_USE = "VOICE_PROVIDER_NOT_USE"; - public static final String[] TTS_AVAILABLE_VOICES = new String[]{ + public static final String[] TTS_AVAILABLE_VOICES = new String[] { "de", "en", "es", "fr", "it", "ja", "nl", "pl", "pt", "ru", "zh" }; // this value string is synchronized with settings_pref.xml preference name diff --git a/OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java b/OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java index 319605dd98..b49c2eb898 100644 --- a/OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/track/TrackSelectSegmentBottomSheet.java @@ -9,31 +9,30 @@ import android.text.style.ForegroundColorSpan; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.NonNull; -import androidx.appcompat.widget.AppCompatImageView; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; 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.GPXUtilities.TrkSegment; import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; -import net.osmand.plus.TargetPointsHelper; import net.osmand.plus.UiUtilities; -import net.osmand.plus.activities.MapActivity; import net.osmand.plus.base.MenuBottomSheetDialogFragment; import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem; import net.osmand.plus.helpers.FontCache; -import net.osmand.plus.helpers.GpxTrackAdapter; import net.osmand.plus.helpers.TrackSelectSegmentAdapter; -import net.osmand.plus.routing.RoutingHelper; -import net.osmand.plus.settings.backend.ApplicationMode; +import net.osmand.plus.helpers.TrackSelectSegmentAdapter.OnItemClickListener; import net.osmand.plus.widgets.style.CustomTypefaceSpan; import net.osmand.util.Algorithms; @@ -42,33 +41,18 @@ import java.util.List; public class TrackSelectSegmentBottomSheet extends MenuBottomSheetDialogFragment { public static final String TAG = TrackSelectSegmentBottomSheet.class.getSimpleName(); - protected TrackSelectSegmentAdapter adapterSegments; - private MapActivity mapActivity; - private GPXUtilities.GPXFile gpxFile; - private OsmandApplication app; - public static void showInstance(@NonNull FragmentManager fragmentManager, @NonNull GPXUtilities.GPXFile gpxFile) { - if (!fragmentManager.isStateSaved()) { - TrackSelectSegmentBottomSheet fragment = new TrackSelectSegmentBottomSheet(); - fragment.setRetainInstance(true); - fragment.gpxFile = gpxFile; - fragment.show(fragmentManager, TAG); - } - } + private OsmandApplication app; + private GPXFile gpxFile; @Override public void createMenuItems(Bundle savedInstanceState) { + app = requiredMyApplication(); Context context = requireContext(); LayoutInflater inflater = UiUtilities.getInflater(context, nightMode); View itemView = inflater.inflate(R.layout.bottom_sheet_select_segment, null, false); - app = getMyApplication(); - if (app == null) { - return; - } - - mapActivity = (MapActivity) getActivity(); String titleGpxTrack = Algorithms.getFileWithoutDirs(gpxFile.path); Typeface typeface = FontCache.getRobotoMedium(app); String selectSegmentDescription = getString(R.string.select_segments_description, titleGpxTrack); @@ -86,9 +70,9 @@ public class TrackSelectSegmentBottomSheet extends MenuBottomSheetDialogFragment LinearLayout gpxTrackContainer = itemView.findViewById(R.id.gpx_track_container); GPXUtilities.GPXTrackAnalysis analysis = gpxFile.getAnalysis(0); - AppCompatImageView icon = gpxTrackContainer.findViewById(R.id.icon); - int sidePadding = AndroidUtils.dpToPx(mapActivity, 16f); - int bottomTopPadding = AndroidUtils.dpToPx(mapActivity, 2f); + ImageView icon = gpxTrackContainer.findViewById(R.id.icon); + int sidePadding = AndroidUtils.dpToPx(context, 16f); + int bottomTopPadding = AndroidUtils.dpToPx(context, 2f); LinearLayout readContainer = gpxTrackContainer.findViewById(R.id.read_section); readContainer.setPadding(0, bottomTopPadding, 0, bottomTopPadding); @@ -111,15 +95,19 @@ public class TrackSelectSegmentBottomSheet extends MenuBottomSheetDialogFragment time.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); time.setText(analysis.isTimeSpecified() ? Algorithms.formatDuration((int) (analysis.timeSpan / 1000), app.accessibilityEnabled()) : ""); - final RecyclerView recyclerView = itemView.findViewById(R.id.gpx_segment_list); + RecyclerView recyclerView = itemView.findViewById(R.id.gpx_segment_list); recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); recyclerView.setNestedScrollingEnabled(false); - final List segments = gpxFile.getNonEmptyTrkSegments(true); - adapterSegments = new TrackSelectSegmentAdapter(requireContext(), segments); - adapterSegments.setAdapterListener(new GpxTrackAdapter.OnItemClickListener() { + + List segments = gpxFile.getNonEmptyTrkSegments(false); + TrackSelectSegmentAdapter adapterSegments = new TrackSelectSegmentAdapter(context, segments); + adapterSegments.setAdapterListener(new OnItemClickListener() { @Override public void onItemClick(int position) { - //select segment + Fragment fragment = getTargetFragment(); + if (fragment instanceof OnSegmentSelectedListener) { + ((OnSegmentSelectedListener) fragment).onSegmentSelect(gpxFile, position); + } dismiss(); } }); @@ -128,30 +116,27 @@ public class TrackSelectSegmentBottomSheet extends MenuBottomSheetDialogFragment gpxTrackContainer.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - selectSegmentToFollow(gpxFile); + Fragment fragment = getTargetFragment(); + if (fragment instanceof OnSegmentSelectedListener) { + ((OnSegmentSelectedListener) fragment).onSegmentSelect(gpxFile, -1); + } dismiss(); } }); } - private void selectSegmentToFollow(GPXUtilities.GPXFile gpxFile) { - if (mapActivity != null) { - this.gpxFile = gpxFile; - TargetPointsHelper targetPointsHelper = app.getTargetPointsHelper(); - RoutingHelper routingHelper = app.getRoutingHelper(); - List points = gpxFile.getRoutePoints(); - if (!points.isEmpty()) { - ApplicationMode mode = ApplicationMode.valueOfStringKey(points.get(0).getProfileType(), null); - if (mode != null) { - routingHelper.setAppMode(mode); - app.initVoiceCommandPlayer(mapActivity, mode, true, null, false, false, true); - } - } - mapActivity.getMapActions().setGPXRouteParams(gpxFile); - targetPointsHelper.updateRouteAndRefresh(true); - routingHelper.onSettingsChanged(true); + public interface OnSegmentSelectedListener { + void onSegmentSelect(GPXFile gpxFile, int selectedSegment); + } + + public static void showInstance(@NonNull FragmentManager fragmentManager, @NonNull GPXFile gpxFile, @Nullable Fragment target) { + if (!fragmentManager.isStateSaved()) { + TrackSelectSegmentBottomSheet fragment = new TrackSelectSegmentBottomSheet(); + fragment.setRetainInstance(true); + fragment.setTargetFragment(target, 0); + fragment.gpxFile = gpxFile; + fragment.show(fragmentManager, TAG); } } -} - +} \ No newline at end of file From 454831591bd2bb06fbaee7c4d1e4aa437656950f Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Mon, 15 Feb 2021 13:39:43 +0200 Subject: [PATCH 28/45] Fix "Download all button" request after code review --- .../java/net/osmand/map/OsmandRegions.java | 7 ++--- .../main/java/net/osmand/map/WorldRegion.java | 30 ++++--------------- .../main/java/net/osmand/util/Algorithms.java | 11 +++++++ .../osmand/plus/download/DownloadItem.java | 7 ++--- .../plus/download/DownloadResourceGroup.java | 2 +- .../plus/download/DownloadResources.java | 12 ++++---- .../net/osmand/plus/download/IndexItem.java | 14 ++++----- .../plus/download/MultipleIndexItem.java | 2 +- .../plus/download/ui/ItemViewHolder.java | 7 +---- 9 files changed, 36 insertions(+), 56 deletions(-) diff --git a/OsmAnd-java/src/main/java/net/osmand/map/OsmandRegions.java b/OsmAnd-java/src/main/java/net/osmand/map/OsmandRegions.java index eba0d94b2b..882231d8a6 100644 --- a/OsmAnd-java/src/main/java/net/osmand/map/OsmandRegions.java +++ b/OsmAnd-java/src/main/java/net/osmand/map/OsmandRegions.java @@ -10,7 +10,6 @@ import net.osmand.binary.BinaryMapIndexReader.TagValuePair; import net.osmand.data.LatLon; import net.osmand.data.QuadRect; import net.osmand.data.QuadTree; -import net.osmand.map.WorldRegion.RegionBoundingBox; import net.osmand.util.Algorithms; import net.osmand.util.MapAlgorithms; import net.osmand.util.MapUtils; @@ -463,9 +462,9 @@ public class OsmandRegions { return rd; } - private RegionBoundingBox findBoundingBox(BinaryMapDataObject object) { + private QuadRect findBoundingBox(BinaryMapDataObject object) { if (object.getPointsLength() == 0) { - return new RegionBoundingBox(0, 0, 0, 0); + return new QuadRect(0, 0, 0, 0); } double currentX = object.getPoint31XTile(0); @@ -497,7 +496,7 @@ public class OsmandRegions { double revertedMinY = MapUtils.get31LatitudeY((int) maxY); double revertedMaxY = MapUtils.get31LatitudeY((int) minY); - return new RegionBoundingBox(minX, maxX, revertedMinY, revertedMaxY); + return new QuadRect(minX, revertedMinY, maxX, revertedMaxY); } private String getSearchIndex(BinaryMapDataObject object) { diff --git a/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java b/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java index e95efb4f5b..99eca34f19 100644 --- a/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java +++ b/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java @@ -1,6 +1,7 @@ package net.osmand.map; import net.osmand.data.LatLon; +import net.osmand.data.QuadRect; import net.osmand.util.Algorithms; import java.io.Serializable; @@ -40,7 +41,7 @@ public class WorldRegion implements Serializable { protected String regionDownloadName; protected boolean regionMapDownload; protected LatLon regionCenter; - protected RegionBoundingBox boundingBox; + protected QuadRect boundingBox; public static class RegionParams { protected String regionLeftHandDriving; @@ -184,31 +185,10 @@ public class WorldRegion implements Serializable { return res; } - public static boolean isFirstRegionInsideTheSecond(WorldRegion first, - WorldRegion second) { - RegionBoundingBox bbox1 = first.boundingBox; - RegionBoundingBox bbox2 = second.boundingBox; - if ((bbox1.minX > bbox2.minX) && (bbox1.maxX < bbox2.maxX)) { - if ((bbox1.minY > bbox2.minY) && (bbox1.maxY < bbox2.maxY)) { - return true; - } + public boolean containsRegion(WorldRegion region) { + if (this.boundingBox != null && region.boundingBox != null) { + return this.boundingBox.contains(region.boundingBox); } return false; } - - public static class RegionBoundingBox { - - double minX; - double maxX; - double minY; - double maxY; - - public RegionBoundingBox(double minX, double maxX, double minY, double maxY) { - this.minX = minX; - this.maxX = maxX; - this.minY = minY; - this.maxY = maxY; - } - - } } \ No newline at end of file diff --git a/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java b/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java index a9d85ce118..83b7c14b44 100644 --- a/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java +++ b/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java @@ -127,6 +127,17 @@ public class Algorithms { return def; } + public static double parseDoubleSilently(String input, double def) { + if (input != null && input.length() > 0) { + try { + return Double.parseDouble(input); + } catch (NumberFormatException e) { + return def; + } + } + return def; + } + public static String getFileNameWithoutExtension(File f) { return getFileNameWithoutExtension(f.getName()); } diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadItem.java b/OsmAnd/src/net/osmand/plus/download/DownloadItem.java index f0a566cea6..23e9f410a7 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadItem.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadItem.java @@ -35,9 +35,8 @@ public abstract class DownloadItem { @NonNull public String getSizeDescription(Context ctx) { - String pattern = ctx.getString(R.string.ltr_or_rtl_combine_via_space); String size = String.format(Locale.US, "%.2f", getSizeToDownloadInMb()); - return String.format(pattern, size, "MB"); + return ctx.getString(R.string.ltr_or_rtl_combine_via_space, size, "MB"); } public String getVisibleName(Context ctx, OsmandRegions osmandRegions) { @@ -48,8 +47,8 @@ public abstract class DownloadItem { return type.getVisibleName(this, ctx, osmandRegions, includingParent); } - public String getVisibleDescription(OsmandApplication clctx) { - return type.getVisibleDescription(this, clctx); + public String getVisibleDescription(OsmandApplication ctx) { + return type.getVisibleDescription(this, ctx); } public String getBasename() { diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java b/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java index dc4e697cb4..5d34c95ec4 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java @@ -21,7 +21,7 @@ public class DownloadResourceGroup { private final DownloadResourceGroupType type; private final DownloadResourceGroup parentGroup; - // ASSERT: individualDisplayItems are not empty if and only if groups are empty + // ASSERT: individualDownloadItems are not empty if and only if groups are empty private final List individualDownloadItems; private final List groups; protected final String id; diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadResources.java b/OsmAnd/src/net/osmand/plus/download/DownloadResources.java index a3aa20c79f..86c89f9cc5 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadResources.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadResources.java @@ -533,13 +533,13 @@ public class DownloadResources extends DownloadResourceGroup { // collect duplicates Set duplicates = new HashSet<>(); for (int i = 0; i < regions.size() - 1; i++) { - WorldRegion firstRegion = regions.get(i); + WorldRegion r1 = regions.get(i); for (int j = i + 1; j < regions.size(); j++) { - WorldRegion secondRegion = regions.get(j); - if (WorldRegion.isFirstRegionInsideTheSecond(firstRegion, secondRegion)) { - duplicates.add(firstRegion); - } else if (WorldRegion.isFirstRegionInsideTheSecond(secondRegion, firstRegion)) { - duplicates.add(secondRegion); + WorldRegion r2 = regions.get(j); + if (r1.containsRegion(r2)) { + duplicates.add(r1); + } else if (r2.containsRegion(r1)) { + duplicates.add(r2); } } } diff --git a/OsmAnd/src/net/osmand/plus/download/IndexItem.java b/OsmAnd/src/net/osmand/plus/download/IndexItem.java index a746d4aa90..637b1f5467 100644 --- a/OsmAnd/src/net/osmand/plus/download/IndexItem.java +++ b/OsmAnd/src/net/osmand/plus/download/IndexItem.java @@ -7,13 +7,14 @@ import net.osmand.PlatformUtil; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.helpers.FileNameTranslationHelper; +import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; import java.io.File; import java.io.IOException; import java.text.DateFormat; -import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.List; @@ -58,11 +59,10 @@ public class IndexItem extends DownloadItem implements Comparable { @Override public List getDownloadedFiles(OsmandApplication app) { File targetFile = getTargetFile(app); - List result = new ArrayList<>(); if (targetFile.exists()) { - result.add(targetFile); + return Collections.singletonList(targetFile); } - return result; + return Collections.emptyList(); } public String getDescription() { @@ -91,11 +91,7 @@ public class IndexItem extends DownloadItem implements Comparable { @Override protected double getSizeToDownloadInMb() { - try { - return Double.parseDouble(size); - } catch (Exception e) { - return 0; - } + return Algorithms.parseDoubleSilently(size, 0.0); } public DownloadEntry createDownloadEntry(OsmandApplication ctx) { diff --git a/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java b/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java index e28d606653..9e58db0655 100644 --- a/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java +++ b/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java @@ -104,7 +104,7 @@ public class MultipleIndexItem extends DownloadItem { double totalSizeMb = 0.0d; for (IndexItem item : items) { if (item.hasActualDataToDownload()) { - totalSizeMb += Double.parseDouble(item.size); + totalSizeMb += item.getSizeToDownloadInMb(); } } return totalSizeMb; diff --git a/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java b/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java index 7fd4172fce..5c71fa342b 100644 --- a/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java +++ b/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java @@ -48,7 +48,6 @@ import net.osmand.util.Algorithms; import java.io.File; import java.text.DateFormat; -import java.util.ArrayList; import java.util.List; public class ItemViewHolder { @@ -412,7 +411,7 @@ public class ItemViewHolder { final List downloadedFiles = downloadItem.getDownloadedFiles(app); if (!Algorithms.isEmpty(downloadedFiles)) { item = optionsMenu.getMenu().add(R.string.shared_string_remove) - .setIcon(getThemedIcon(context, R.drawable.ic_action_remove_dark)); + .setIcon(getContentIcon(context, R.drawable.ic_action_remove_dark)); item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { @@ -560,10 +559,6 @@ public class ItemViewHolder { return type; } - private Drawable getThemedIcon(DownloadActivity context, int resourceId) { - return context.getMyApplication().getUIUtilities().getThemedIcon(resourceId); - } - private Drawable getContentIcon(DownloadActivity context, int resourceId) { return context.getMyApplication().getUIUtilities().getThemedIcon(resourceId); } From d379b6cf4a58a65efc0d6194a10f2ee5b4d4942a Mon Sep 17 00:00:00 2001 From: Skalii Date: Mon, 15 Feb 2021 16:07:01 +0200 Subject: [PATCH 29/45] fix crash after screen rotation; remove unnecessary layout for buttons; some other code fixes; --- .../bottom_sheet_item_button_with_icon.xml | 69 ------- .../ClearRecordedDataBottomSheetFragment.java | 89 ++++----- .../StopTrackRecordingBottomFragment.java | 131 ++++++------- .../TripRecordingActiveBottomSheet.java | 177 +++++++++++------- 4 files changed, 204 insertions(+), 262 deletions(-) delete mode 100644 OsmAnd/res/layout/bottom_sheet_item_button_with_icon.xml diff --git a/OsmAnd/res/layout/bottom_sheet_item_button_with_icon.xml b/OsmAnd/res/layout/bottom_sheet_item_button_with_icon.xml deleted file mode 100644 index 2e1c2cd881..0000000000 --- a/OsmAnd/res/layout/bottom_sheet_item_button_with_icon.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/monitoring/ClearRecordedDataBottomSheetFragment.java b/OsmAnd/src/net/osmand/plus/monitoring/ClearRecordedDataBottomSheetFragment.java index 0bdced7bc5..6a58b750ce 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/ClearRecordedDataBottomSheetFragment.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/ClearRecordedDataBottomSheetFragment.java @@ -1,10 +1,10 @@ package net.osmand.plus.monitoring; -import android.app.Dialog; import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; +import android.widget.FrameLayout; import android.widget.LinearLayout; import net.osmand.plus.OsmandApplication; @@ -13,17 +13,16 @@ import net.osmand.plus.UiUtilities; 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.DividerSpaceItem; +import net.osmand.plus.monitoring.TripRecordingActiveBottomSheet.ItemType; import net.osmand.plus.widgets.TextViewEx; -import androidx.annotation.DimenRes; -import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; -import androidx.annotation.StringRes; import androidx.appcompat.widget.AppCompatImageView; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; -public class ClearRecordedDataBottomSheetFragment extends MenuBottomSheetDialogFragment implements View.OnClickListener { +public class ClearRecordedDataBottomSheetFragment extends MenuBottomSheetDialogFragment { public static final String TAG = ClearRecordedDataBottomSheetFragment.class.getSimpleName(); @@ -32,6 +31,9 @@ public class ClearRecordedDataBottomSheetFragment extends MenuBottomSheetDialogF @Override public void createMenuItems(Bundle savedInstanceState) { app = requiredMyApplication(); + LayoutInflater inflater = UiUtilities.getInflater(app, nightMode); + int verticalBig = getResources().getDimensionPixelSize(R.dimen.dialog_content_margin); + int verticalSmall = getResources().getDimensionPixelSize(R.dimen.content_padding_small); items.add(new BottomSheetItemWithDescription.Builder() .setDescription(app.getString(R.string.clear_recorded_data_warning)) @@ -41,64 +43,65 @@ public class ClearRecordedDataBottomSheetFragment extends MenuBottomSheetDialogF .setLayoutId(R.layout.bottom_sheet_item_title_with_description) .create()); - LayoutInflater inflater = UiUtilities.getInflater(getContext(), nightMode); + items.add(new DividerSpaceItem(app, verticalBig)); items.add(new BaseBottomSheetItem.Builder() - .setCustomView(setupBtn(inflater, ButtonType.CLEAR)) - .setOnClickListener(this) + .setCustomView(setupBtn(inflater, ItemType.CLEAR_DATA)) + .setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + app.getSavingTrackHelper().clearRecordedData(true); + dismiss(); + } + }) .create()); + items.add(new DividerSpaceItem(app, verticalBig)); + items.add(new BaseBottomSheetItem.Builder() - .setCustomView(setupBtn(inflater, ButtonType.CANCEL)) - .setOnClickListener(this) + .setCustomView(setupBtn(inflater, ItemType.CANCEL)) + .setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dismiss(); + } + }) .create()); + items.add(new DividerSpaceItem(app, verticalSmall)); } - private View setupBtn(LayoutInflater inflater, ButtonType type) { - View button = inflater.inflate(R.layout.bottom_sheet_item_button_with_icon, null); + private View setupBtn(LayoutInflater inflater, ItemType type) { + View button = inflater.inflate(R.layout.bottom_sheet_button_with_icon, null); button.setTag(type); Context context = button.getContext(); + LinearLayout container = button.findViewById(R.id.button_container); + container.setClickable(false); + container.setFocusable(false); - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT); int horizontal = context.getResources().getDimensionPixelSize(R.dimen.content_padding); - int top = context.getResources().getDimensionPixelSize(type.topMarginRes); - int bottom = context.getResources().getDimensionPixelSize(R.dimen.content_padding_small); - params.setMargins(horizontal, top, horizontal, bottom); + params.setMargins(horizontal, 0, horizontal, 0); button.setLayoutParams(params); - UiUtilities.setupDialogButton(nightMode, button, type.effect, type.titleId); + UiUtilities.setupDialogButton(nightMode, button, type.getEffect(), type.getTitleId()); TextViewEx title = button.findViewById(R.id.button_text); int margin = context.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_medium); UiUtilities.setMargins(title, 0, margin, 0, margin); int colorRes; - if (type.effect == UiUtilities.DialogButtonType.SECONDARY_HARMFUL) { + if (type.getEffect() == UiUtilities.DialogButtonType.SECONDARY_HARMFUL) { colorRes = R.color.color_osm_edit_delete; } else { colorRes = nightMode ? R.color.dlg_btn_secondary_text_dark : R.color.dlg_btn_secondary_text_light; } AppCompatImageView icon = button.findViewById(R.id.icon); - icon.setImageDrawable(getIcon(type.iconRes, colorRes)); + icon.setImageDrawable(getIcon(type.getIconId(), colorRes)); return button; } - @Override - public void onClick(View v) { - Object o = v.getTag(); - if (!(o instanceof ButtonType)) { - return; - } - - ButtonType tag = (ButtonType) o; - if (tag == ButtonType.CLEAR) { - app.getSavingTrackHelper().clearRecordedData(true); - } - dismiss(); - } - @Override public void onResume() { super.onResume(); @@ -117,26 +120,6 @@ public class ClearRecordedDataBottomSheetFragment extends MenuBottomSheetDialogF } } - enum ButtonType { - CLEAR(R.string.clear_recorded_data, R.drawable.ic_action_delete_dark, R.dimen.dialog_content_margin, UiUtilities.DialogButtonType.SECONDARY_HARMFUL), - CANCEL(R.string.shared_string_cancel, R.drawable.ic_action_close, R.dimen.content_padding_small, UiUtilities.DialogButtonType.SECONDARY); - - @StringRes - private final int titleId; - @DrawableRes - private final int iconRes; - @DimenRes - private final int topMarginRes; - private final UiUtilities.DialogButtonType effect; - - ButtonType(int titleId, int iconRes, int topMarginRes, UiUtilities.DialogButtonType effect) { - this.titleId = titleId; - this.iconRes = iconRes; - this.topMarginRes = topMarginRes; - this.effect = effect; - } - } - @Override protected boolean hideButtonsContainer() { return true; diff --git a/OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java b/OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java index 3d648f432b..cca494b31b 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/StopTrackRecordingBottomFragment.java @@ -4,6 +4,7 @@ import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; +import android.widget.FrameLayout; import android.widget.LinearLayout; import net.osmand.plus.OsmandApplication; @@ -15,18 +16,17 @@ import net.osmand.plus.activities.MapActivity; 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.DividerSpaceItem; +import net.osmand.plus.monitoring.TripRecordingActiveBottomSheet.ItemType; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.widgets.TextViewEx; -import androidx.annotation.DimenRes; -import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; -import androidx.annotation.StringRes; import androidx.appcompat.widget.AppCompatImageView; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; -public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragment implements View.OnClickListener { +public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragment { public static final String TAG = StopTrackRecordingBottomFragment.class.getSimpleName(); @@ -34,7 +34,7 @@ public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragm private MapActivity mapActivity; private OsmandSettings settings; private OsmandMonitoringPlugin plugin; - private ButtonType tag = ButtonType.CANCEL; + private ItemType tag = ItemType.CANCEL; public void setMapActivity(MapActivity mapActivity) { this.mapActivity = mapActivity; @@ -45,6 +45,9 @@ public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragm app = requiredMyApplication(); settings = app.getSettings(); plugin = OsmandPlugin.getPlugin(OsmandMonitoringPlugin.class); + LayoutInflater inflater = UiUtilities.getInflater(app, nightMode); + int verticalBig = getResources().getDimensionPixelSize(R.dimen.dialog_content_margin); + int verticalSmall = getResources().getDimensionPixelSize(R.dimen.content_padding_small); items.add(new BottomSheetItemWithDescription.Builder() .setDescription(app.getString(R.string.track_recording_description)) @@ -54,52 +57,86 @@ public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragm .setLayoutId(R.layout.bottom_sheet_item_title_with_description) .create()); - LayoutInflater inflater = UiUtilities.getInflater(getContext(), nightMode); + items.add(new DividerSpaceItem(app, verticalBig)); items.add(new BaseBottomSheetItem.Builder() - .setCustomView(setupButton(inflater, ButtonType.STOP_AND_DISCARD)) - .setOnClickListener(this) + .setCustomView(setupButton(inflater, ItemType.STOP_AND_DISCARD)) + .setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + tag = ItemType.STOP_AND_DISCARD; + if (plugin != null && settings.SAVE_GLOBAL_TRACK_TO_GPX.get()) { + plugin.stopRecording(); + app.getNotificationHelper().refreshNotifications(); + } + app.getSavingTrackHelper().clearRecordedData(true); + dismiss(); + } + }) .create()); - items.add(new BaseBottomSheetItem.Builder() - .setCustomView(setupButton(inflater, ButtonType.SAVE_AND_STOP)) - .setOnClickListener(this) - .create()); + items.add(new DividerSpaceItem(app, verticalBig)); items.add(new BaseBottomSheetItem.Builder() - .setCustomView(setupButton(inflater, ButtonType.CANCEL)) - .setOnClickListener(this) + .setCustomView(setupButton(inflater, ItemType.SAVE_AND_STOP)) + .setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + tag = ItemType.SAVE_AND_STOP; + if (plugin != null && settings.SAVE_GLOBAL_TRACK_TO_GPX.get()) { + plugin.saveCurrentTrack(null, mapActivity); + app.getNotificationHelper().refreshNotifications(); + } + dismiss(); + } + }) .create()); + + items.add(new DividerSpaceItem(app, verticalSmall)); + + items.add(new BaseBottomSheetItem.Builder() + .setCustomView(setupButton(inflater, ItemType.CANCEL)) + .setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + tag = ItemType.CANCEL; + dismiss(); + } + }) + .create()); + + items.add(new DividerSpaceItem(app, verticalSmall)); } - private View setupButton(LayoutInflater inflater, ButtonType type) { - View button = inflater.inflate(R.layout.bottom_sheet_item_button_with_icon, null); + private View setupButton(LayoutInflater inflater, ItemType type) { + View button = inflater.inflate(R.layout.bottom_sheet_button_with_icon, null); button.setTag(type); Context context = button.getContext(); + LinearLayout container = button.findViewById(R.id.button_container); + container.setClickable(false); + container.setFocusable(false); - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT); int horizontal = context.getResources().getDimensionPixelSize(R.dimen.content_padding); - int top = context.getResources().getDimensionPixelSize(type.topMarginRes); - int bottom = context.getResources().getDimensionPixelSize(R.dimen.content_padding_small); - params.setMargins(horizontal, top, horizontal, bottom); + params.setMargins(horizontal, 0, horizontal, 0); button.setLayoutParams(params); - UiUtilities.setupDialogButton(nightMode, button, type.effect, type.titleId); + UiUtilities.setupDialogButton(nightMode, button, type.getEffect(), type.getTitleId()); TextViewEx title = button.findViewById(R.id.button_text); int margin = context.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_medium); UiUtilities.setMargins(title, 0, margin, 0, margin); int colorRes; - if (type.effect == DialogButtonType.SECONDARY_HARMFUL) { + if (type.getEffect() == DialogButtonType.SECONDARY_HARMFUL) { colorRes = R.color.color_osm_edit_delete; } else { colorRes = nightMode ? R.color.dlg_btn_secondary_text_dark : R.color.dlg_btn_secondary_text_light; } AppCompatImageView icon = button.findViewById(R.id.icon); - icon.setImageDrawable(getIcon(type.iconRes, colorRes)); + icon.setImageDrawable(getIcon(type.getIconId(), colorRes)); - if (type == ButtonType.STOP_AND_DISCARD) { + if (type == ItemType.STOP_AND_DISCARD) { int size = context.getResources().getDimensionPixelSize(R.dimen.map_widget_height); LinearLayout.LayoutParams iconParams = new LinearLayout.LayoutParams(size, size); icon.setLayoutParams(iconParams); @@ -108,29 +145,6 @@ public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragm return button; } - @Override - public void onClick(View v) { - Object o = v.getTag(); - if (!(o instanceof ButtonType)) { - return; - } - - tag = (ButtonType) o; - if (tag == ButtonType.STOP_AND_DISCARD) { - if (plugin != null && settings.SAVE_GLOBAL_TRACK_TO_GPX.get()) { - plugin.stopRecording(); - app.getNotificationHelper().refreshNotifications(); - } - app.getSavingTrackHelper().clearRecordedData(true); - } else if (tag == ButtonType.SAVE_AND_STOP) { - if (plugin != null && settings.SAVE_GLOBAL_TRACK_TO_GPX.get()) { - plugin.saveCurrentTrack(null, mapActivity); - app.getNotificationHelper().refreshNotifications(); - } - } - dismiss(); - } - @Override public void onResume() { super.onResume(); @@ -143,7 +157,7 @@ public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragm @Override public void onPause() { super.onPause(); - if (tag == ButtonType.CANCEL) { + if (tag == ItemType.CANCEL) { Fragment target = getTargetFragment(); if (target instanceof TripRecordingActiveBottomSheet) { ((TripRecordingActiveBottomSheet) target).show(); @@ -151,27 +165,6 @@ public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragm } } - enum ButtonType { - STOP_AND_DISCARD(R.string.track_recording_stop_without_saving, R.drawable.ic_action_rec_stop, R.dimen.dialog_content_margin, DialogButtonType.SECONDARY_HARMFUL), - SAVE_AND_STOP(R.string.track_recording_save_and_stop, R.drawable.ic_action_save_to_file, R.dimen.content_padding_small, DialogButtonType.SECONDARY), - CANCEL(R.string.shared_string_cancel, R.drawable.ic_action_close, R.dimen.zero, DialogButtonType.SECONDARY); - - @StringRes - private final int titleId; - @DrawableRes - private final int iconRes; - @DimenRes - private final int topMarginRes; - private final DialogButtonType effect; - - ButtonType(int titleId, int iconRes, int topMarginRes, DialogButtonType type) { - this.titleId = titleId; - this.iconRes = iconRes; - this.topMarginRes = topMarginRes; - this.effect = type; - } - } - @Override protected boolean hideButtonsContainer() { return true; diff --git a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java index a06064bcb4..70b0198633 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java @@ -42,6 +42,7 @@ import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; +import net.osmand.plus.UiUtilities.DialogButtonType; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.SavingTrackHelper; import net.osmand.plus.activities.SavingTrackHelper.SaveGpxResult; @@ -67,6 +68,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen public static final String TAG = TripRecordingActiveBottomSheet.class.getSimpleName(); private static final Log log = PlatformUtil.getLog(TripRecordingActiveBottomSheet.class); + private static final String UPDATE_CURRENT_GPX_FILE = "update_current_gpx_file"; private OsmandApplication app; private OsmandSettings settings; @@ -137,6 +139,11 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen updateStatus(); RecyclerView statBlocks = itemView.findViewById(R.id.block_statistics); + if (savedInstanceState != null) { + if (savedInstanceState.containsKey(UPDATE_CURRENT_GPX_FILE) && savedInstanceState.getBoolean(UPDATE_CURRENT_GPX_FILE)) { + selectedGpxFile = app.getSavingTrackHelper().getCurrentTrack(); + } + } blockStatisticsBuilder = new GpxBlockStatisticsBuilder(app, selectedGpxFile); blockStatisticsBuilder.setBlocksView(statBlocks); blockStatisticsBuilder.setBlocksClickable(false); @@ -262,17 +269,29 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen }); } + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(UPDATE_CURRENT_GPX_FILE, true); + } + private void updateStatus() { TextView statusTitle = statusContainer.findViewById(R.id.text_status); AppCompatImageView statusIcon = statusContainer.findViewById(R.id.icon_status); ItemType status = searchingGPS() ? ItemType.SEARCHING_GPS : !wasTrackMonitored() ? ItemType.ON_PAUSE : ItemType.RECORDING; - statusTitle.setText(status.getTitleId()); + Integer titleId = status.getTitleId(); + if (titleId != null) { + statusTitle.setText(titleId); + } int colorText = status.equals(ItemType.SEARCHING_GPS) ? getSecondaryTextColorId(nightMode) : getOsmandIconColorId(nightMode); statusTitle.setTextColor(ContextCompat.getColor(app, colorText)); - int colorDrawable = ContextCompat.getColor(app, - status.equals(ItemType.SEARCHING_GPS) ? getSecondaryIconColorId(nightMode) : getOsmandIconColorId(nightMode)); - Drawable statusDrawable = UiUtilities.tintDrawable(AppCompatResources.getDrawable(app, status.getIconId()), colorDrawable); - statusIcon.setImageDrawable(statusDrawable); + Integer iconId = status.getIconId(); + if (iconId != null) { + int colorDrawable = ContextCompat.getColor(app, + status.equals(ItemType.SEARCHING_GPS) ? getSecondaryIconColorId(nightMode) : getOsmandIconColorId(nightMode)); + Drawable statusDrawable = UiUtilities.tintDrawable(AppCompatResources.getDrawable(app, iconId), colorDrawable); + statusIcon.setImageDrawable(statusDrawable); + } } private void createItem(View view, ItemType type, boolean enabled, @Nullable String description) { @@ -281,13 +300,14 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen AppCompatImageView icon = view.findViewById(R.id.icon); if (icon != null) { - type.setTintedIcon(icon, app, enabled, false, nightMode); + setTintedIcon(icon, app, enabled, false, nightMode, type); } TextView title = view.findViewById(R.id.button_text); - if (title != null) { - title.setText(type.getTitleId()); - type.setTextColor(title, app, enabled, false, nightMode); + Integer titleId = type.getTitleId(); + if (title != null && titleId != null) { + title.setText(titleId); + setTextColor(title, app, enabled, false, nightMode, type); } TextViewEx desc = view.findViewById(R.id.desc); @@ -295,13 +315,15 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen boolean isShowDesc = !Algorithms.isBlank(description); int marginDesc = isShowDesc ? 0 : app.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_medium); AndroidUiHelper.updateVisibility(desc, isShowDesc); - UiUtilities.setMargins(title, 0, marginDesc, 0, marginDesc); + if (title != null) { + UiUtilities.setMargins(title, 0, marginDesc, 0, marginDesc); + } desc.setText(description); - type.setTextColor(desc, app, false, false, nightMode); + setTextColor(desc, app, false, false, nightMode, type); } setItemBackgroundInactive(button != null ? button : (LinearLayout) view, app, nightMode); - type.changeOnTouch(button != null ? button : (LinearLayout) view, icon, title, app, enabled, nightMode); + changeOnTouch(button != null ? button : (LinearLayout) view, icon, title, app, enabled, nightMode, type); } private String getTimeTrackSaved() { @@ -457,89 +479,102 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen view.setBackgroundDrawable(background); } - enum ItemType { - SHOW_TRACK(R.string.shared_string_show_on_map, null), - APPEARANCE(null, null), - SEARCHING_GPS(R.string.searching_gps, R.drawable.ic_action_gps_info), - RECORDING(R.string.recording_default_name, R.drawable.ic_action_track_recordable), - ON_PAUSE(R.string.on_pause, R.drawable.ic_pause), - CLEAR_DATA(R.string.clear_recorded_data, R.drawable.ic_action_delete_dark), - START_SEGMENT(R.string.gpx_start_new_segment, R.drawable.ic_action_new_segment), - SAVE(R.string.shared_string_save, R.drawable.ic_action_save_to_file), - PAUSE(R.string.shared_string_pause, R.drawable.ic_pause), - RESUME(R.string.shared_string_resume, R.drawable.ic_play_dark), - STOP(R.string.shared_string_control_stop, R.drawable.ic_action_rec_stop); + public enum ItemType { + SHOW_TRACK(R.string.shared_string_show_on_map, null, null), + APPEARANCE(null, null, null), + SEARCHING_GPS(R.string.searching_gps, R.drawable.ic_action_gps_info, null), + RECORDING(R.string.recording_default_name, R.drawable.ic_action_track_recordable, null), + ON_PAUSE(R.string.on_pause, R.drawable.ic_pause, null), + CLEAR_DATA(R.string.clear_recorded_data, R.drawable.ic_action_delete_dark, UiUtilities.DialogButtonType.SECONDARY_HARMFUL), + START_SEGMENT(R.string.gpx_start_new_segment, R.drawable.ic_action_new_segment, null), + SAVE(R.string.shared_string_save, R.drawable.ic_action_save_to_file, null), + PAUSE(R.string.shared_string_pause, R.drawable.ic_pause, null), + RESUME(R.string.shared_string_resume, R.drawable.ic_play_dark, null), + STOP(R.string.shared_string_control_stop, R.drawable.ic_action_rec_stop, null), + STOP_AND_DISCARD(R.string.track_recording_stop_without_saving, R.drawable.ic_action_rec_stop, DialogButtonType.SECONDARY_HARMFUL), + SAVE_AND_STOP(R.string.track_recording_save_and_stop, R.drawable.ic_action_save_to_file, DialogButtonType.SECONDARY), + CANCEL(R.string.shared_string_cancel, R.drawable.ic_action_close, DialogButtonType.SECONDARY); @StringRes private final Integer titleId; @DrawableRes private final Integer iconId; + private final DialogButtonType effect; - ItemType(@Nullable @StringRes Integer titleId, @Nullable @DrawableRes Integer iconId) { + ItemType(@Nullable @StringRes Integer titleId, @Nullable @DrawableRes Integer iconId, @Nullable DialogButtonType effect) { this.titleId = titleId; this.iconId = iconId; + this.effect = effect; } + @Nullable public Integer getTitleId() { return titleId; } + @Nullable public Integer getIconId() { return iconId; } - public void setTextColor(TextView tv, Context context, boolean enabled, boolean pressed, boolean nightMode) { - if (tv != null) { - tv.setTextColor(ContextCompat.getColor(context, - enabled ? pressed ? getPressedColorId(nightMode) - : this == ItemType.CLEAR_DATA ? R.color.color_osm_edit_delete - : getActiveTextColorId(nightMode) : getSecondaryTextColorId(nightMode))); + @Nullable + public DialogButtonType getEffect() { + return effect; + } + } + + public void setTextColor(TextView tv, Context context, boolean enabled, boolean pressed, boolean nightMode, ItemType type) { + if (tv != null) { + tv.setTextColor(ContextCompat.getColor(context, + enabled ? pressed ? getPressedColorId(nightMode) + : type == ItemType.CLEAR_DATA ? R.color.color_osm_edit_delete + : getActiveTextColorId(nightMode) : getSecondaryTextColorId(nightMode))); + } + } + + public void setTintedIcon(AppCompatImageView iv, Context context, boolean enabled, boolean pressed, boolean nightMode, ItemType type) { + Integer iconId = type.getIconId(); + if (iv != null && iconId != null) { + Drawable icon = AppCompatResources.getDrawable(context, iconId); + int iconColor = enabled ? pressed ? getPressedColorId(nightMode) + : type == ItemType.CLEAR_DATA ? R.color.color_osm_edit_delete + : getActiveIconColorId(nightMode) : getSecondaryIconColorId(nightMode); + Drawable tintedIcon = UiUtilities.tintDrawable(icon, ContextCompat.getColor(context, iconColor)); + iv.setImageDrawable(tintedIcon); + if (type == ItemType.STOP) { + int stopSize = iv.getResources().getDimensionPixelSize(R.dimen.bottom_sheet_icon_margin_large); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(stopSize, stopSize); + iv.setLayoutParams(params); } } + } - public void setTintedIcon(AppCompatImageView iv, Context context, boolean enabled, boolean pressed, boolean nightMode) { - if (iv != null) { - Drawable icon = AppCompatResources.getDrawable(context, iconId); - int iconColor = enabled ? pressed ? getPressedColorId(nightMode) - : this == ItemType.CLEAR_DATA ? R.color.color_osm_edit_delete - : getActiveIconColorId(nightMode) : getSecondaryIconColorId(nightMode); - Drawable tintedIcon = UiUtilities.tintDrawable(icon, ContextCompat.getColor(context, iconColor)); - iv.setImageDrawable(tintedIcon); - if (this == ItemType.STOP) { - int stopSize = iv.getResources().getDimensionPixelSize(R.dimen.bottom_sheet_icon_margin_large); - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(stopSize, stopSize); - iv.setLayoutParams(params); - } - } - } - - @SuppressLint("ClickableViewAccessibility") - private void changeOnTouch(final LinearLayout button, @Nullable final AppCompatImageView iv, @Nullable final TextView tv, - final Context context, final boolean enabled, final boolean nightMode) { - button.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (enabled) { - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: { - setItemBackgroundActive(button, context, nightMode); - setTintedIcon(iv, context, true, true, nightMode); - setTextColor(tv, context, true, true, nightMode); - break; - } - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: { - setItemBackgroundInactive(button, context, nightMode); - setTintedIcon(iv, context, true, false, nightMode); - setTextColor(tv, context, true, false, nightMode); - break; - } + @SuppressLint("ClickableViewAccessibility") + private void changeOnTouch(final LinearLayout button, @Nullable final AppCompatImageView iv, @Nullable final TextView tv, + final Context context, final boolean enabled, final boolean nightMode, final ItemType type) { + button.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (enabled) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: { + setItemBackgroundActive(button, context, nightMode); + setTintedIcon(iv, context, true, true, nightMode, type); + setTextColor(tv, context, true, true, nightMode, type); + break; + } + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: { + setItemBackgroundInactive(button, context, nightMode); + setTintedIcon(iv, context, true, false, nightMode, type); + setTextColor(tv, context, true, false, nightMode, type); + break; } } - return false; } - }); - } + return false; + } + }); } @ColorRes From 8af6416366d6c7425e0db773a8f4a279e9fb7559 Mon Sep 17 00:00:00 2001 From: cepprice Date: Fri, 12 Feb 2021 22:39:38 +0500 Subject: [PATCH 30/45] Fix UI --- OsmAnd/res/drawable/btn_unstroked.xml | 13 +++ .../layout/dialog_edit_gpx_description.xml | 28 +++--- .../layout/dialog_read_gpx_description.xml | 93 ++++++++++++++----- .../layout/gpx_description_preview_card.xml | 24 +++-- OsmAnd/res/values/attrs.xml | 1 + OsmAnd/res/values/styles.xml | 2 + .../osmand/plus/track/DescriptionCard.java | 22 ++++- .../GpxEditDescriptionDialogFragment.java | 72 ++++++++++---- .../GpxReadDescriptionDialogFragment.java | 90 +++++++----------- 9 files changed, 219 insertions(+), 126 deletions(-) create mode 100644 OsmAnd/res/drawable/btn_unstroked.xml diff --git a/OsmAnd/res/drawable/btn_unstroked.xml b/OsmAnd/res/drawable/btn_unstroked.xml new file mode 100644 index 0000000000..e9405e72c7 --- /dev/null +++ b/OsmAnd/res/drawable/btn_unstroked.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/layout/dialog_edit_gpx_description.xml b/OsmAnd/res/layout/dialog_edit_gpx_description.xml index 1d2428f82b..66c0d57f0a 100644 --- a/OsmAnd/res/layout/dialog_edit_gpx_description.xml +++ b/OsmAnd/res/layout/dialog_edit_gpx_description.xml @@ -21,11 +21,13 @@ android:layout_marginLeft="@dimen/card_padding" android:padding="@dimen/context_menu_padding_margin_small" android:paddingStart="@dimen/context_menu_padding_margin_small" - android:paddingEnd="@dimen/context_menu_padding_margin_small"> + android:paddingEnd="@dimen/context_menu_padding_margin_small" + android:background="@null"> @@ -43,18 +45,20 @@ osmand:typeface="@string/font_roboto_medium" /> + android:layout_gravity="center_vertical"> + android:layout_height="match_parent" + android:layout_marginStart="@dimen/content_padding" + android:layout_marginLeft="@dimen/content_padding" + android:layout_marginTop="@dimen/content_padding_half" + android:layout_marginRight="@dimen/content_padding" + android:layout_marginEnd="@dimen/content_padding" + android:layout_marginBottom="@dimen/content_padding_half"> + android:orientation="vertical"> - + android:layout_height="@dimen/action_bar_height" + android:background="?attr/pstsTabBackground" + android:orientation="horizontal" + android:gravity="center_vertical"> - + - + + + + + + + + + + + + + + android:layout_height="match_parent" + android:background="?attr/activity_background_basic"> + android:visibility="gone" + tools:visibility="visible"> + osmand:typeface="@string/font_roboto_medium" /> diff --git a/OsmAnd/res/layout/gpx_description_preview_card.xml b/OsmAnd/res/layout/gpx_description_preview_card.xml index a3b0ab8b25..551110d028 100644 --- a/OsmAnd/res/layout/gpx_description_preview_card.xml +++ b/OsmAnd/res/layout/gpx_description_preview_card.xml @@ -68,19 +68,18 @@ android:orientation="horizontal"> + android:layout_marginStart="@dimen/content_padding_half" + android:layout_marginLeft="@dimen/content_padding_half"> + android:layout_marginRight="@dimen/content_padding_half" + android:layout_marginEnd="@dimen/content_padding_half" + android:layout_gravity="end"> @@ -142,7 +140,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_vertical" - android:background="?attr/selectableItemBackgroundBorderless" + android:duplicateParentState="true" android:padding="@dimen/bottom_sheet_content_padding_small" android:paddingStart="@dimen/bottom_sheet_content_padding_small" android:paddingEnd="@dimen/bottom_sheet_content_padding_small" diff --git a/OsmAnd/res/values/attrs.xml b/OsmAnd/res/values/attrs.xml index c745589ef7..104471ab6d 100644 --- a/OsmAnd/res/values/attrs.xml +++ b/OsmAnd/res/values/attrs.xml @@ -142,6 +142,7 @@ + diff --git a/OsmAnd/res/values/styles.xml b/OsmAnd/res/values/styles.xml index 5c074185ef..b406c0d5f9 100644 --- a/OsmAnd/res/values/styles.xml +++ b/OsmAnd/res/values/styles.xml @@ -249,6 +249,7 @@ @color/text_input_background_light @drawable/img_help_announcement_time_day @color/switch_button_active_light + @color/active_buttons_and_links_bg_pressed_light @@ -549,7 +548,6 @@ @color/text_input_background_dark @drawable/img_help_announcement_time_night @color/switch_button_active_dark - @color/active_buttons_and_links_bg_pressed_dark @drawable/bottom_navigation_item_bg_dark diff --git a/OsmAnd/src/net/osmand/plus/track/DescriptionCard.java b/OsmAnd/src/net/osmand/plus/track/DescriptionCard.java index ac384809e0..5db16f7f45 100644 --- a/OsmAnd/src/net/osmand/plus/track/DescriptionCard.java +++ b/OsmAnd/src/net/osmand/plus/track/DescriptionCard.java @@ -24,7 +24,6 @@ import net.osmand.util.Algorithms; import androidx.annotation.NonNull; import androidx.appcompat.widget.AppCompatImageView; -import androidx.core.content.ContextCompat; import static net.osmand.plus.myplaces.TrackActivityFragmentAdapter.getMetadataImageLink; @@ -120,7 +119,7 @@ public class DescriptionCard extends BaseCard { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { AndroidUtils.setBackground(ctx, button, nightMode, R.drawable.ripple_light, R.drawable.ripple_dark); } else { - AndroidUtils.setBackground(button, ContextCompat.getDrawable(ctx, R.drawable.btn_unstroked)); + AndroidUtils.setBackground(ctx, button, nightMode, R.drawable.btn_unstroked_light, R.drawable.btn_unstroked_dark); } } diff --git a/OsmAnd/src/net/osmand/plus/track/GpxEditDescriptionDialogFragment.java b/OsmAnd/src/net/osmand/plus/track/GpxEditDescriptionDialogFragment.java index ae95e05174..b8ef1c24d2 100644 --- a/OsmAnd/src/net/osmand/plus/track/GpxEditDescriptionDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/track/GpxEditDescriptionDialogFragment.java @@ -126,7 +126,7 @@ public class GpxEditDescriptionDialogFragment extends BaseOsmAndDialogFragment { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { AndroidUtils.setBackground(ctx, btnSave, isNightMode(true), R.drawable.ripple_light, R.drawable.ripple_dark); } else { - AndroidUtils.setBackground(btnSave, ContextCompat.getDrawable(ctx, R.drawable.btn_unstroked)); + AndroidUtils.setBackground(ctx, btnSave, isNightMode(true), R.drawable.btn_unstroked_light, R.drawable.btn_unstroked_dark); } } diff --git a/OsmAnd/src/net/osmand/plus/track/GpxReadDescriptionDialogFragment.java b/OsmAnd/src/net/osmand/plus/track/GpxReadDescriptionDialogFragment.java index 9bbfd3bd90..c9171111d8 100644 --- a/OsmAnd/src/net/osmand/plus/track/GpxReadDescriptionDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/track/GpxReadDescriptionDialogFragment.java @@ -1,5 +1,7 @@ package net.osmand.plus.track; +import android.app.Activity; +import android.app.Dialog; import android.content.Context; import android.graphics.Color; import android.os.Build; @@ -8,6 +10,7 @@ import android.util.Base64; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.Window; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; @@ -95,6 +98,25 @@ public class GpxReadDescriptionDialogFragment extends BaseOsmAndDialogFragment { outState.putString(CONTENT_KEY, contentHtml); } + @NonNull + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + Activity ctx = getActivity(); + int themeId = isNightMode(true) ? R.style.OsmandDarkTheme_DarkActionbar : R.style.OsmandLightTheme_DarkActionbar_LightStatusBar; + Dialog dialog = new Dialog(ctx, themeId); + Window window = dialog.getWindow(); + if (window != null) { + if (!getSettings().DO_NOT_USE_ANIMATIONS.get()) { + window.getAttributes().windowAnimations = R.style.Animations_Alpha; + } + if (Build.VERSION.SDK_INT >= 21) { + int statusBarColor = isNightMode(true) ? R.color.status_bar_color_dark : R.color.status_bar_color_light; + window.setStatusBarColor(ContextCompat.getColor(ctx, statusBarColor)); + } + } + return dialog; + } + private void setupToolbar(View view) { View back = view.findViewById(R.id.toolbar_back); back.setOnClickListener(new View.OnClickListener() { @@ -195,7 +217,7 @@ public class GpxReadDescriptionDialogFragment extends BaseOsmAndDialogFragment { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { AndroidUtils.setBackground(ctx, editBtn, isNightMode(true), R.drawable.ripple_light, R.drawable.ripple_dark); } else { - AndroidUtils.setBackground(editBtn, ContextCompat.getDrawable(ctx, R.drawable.btn_unstroked)); + AndroidUtils.setBackground(ctx, editBtn, isNightMode(true), R.drawable.btn_unstroked_light, R.drawable.btn_unstroked_dark); } editBtn.setOnClickListener(new View.OnClickListener() { From 1be4d3b21361e9238961c141ea10ad25c06ae33c Mon Sep 17 00:00:00 2001 From: Vitaliy Date: Tue, 16 Feb 2021 11:00:49 +0200 Subject: [PATCH 42/45] Fix compilation --- .../plus/monitoring/TripRecordingActiveBottomSheet.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java index d1368d4a17..6dcca6d355 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/TripRecordingActiveBottomSheet.java @@ -231,7 +231,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen if (wasTrackMonitored()) { blockStatisticsBuilder.stopUpdatingStatBlocks(); helper.startNewSegment(); - blockStatisticsBuilder.runUpdatingStatBlocks(); + blockStatisticsBuilder.runUpdatingStatBlocksIfNeeded(); } } }); @@ -245,7 +245,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen @Override public void run() { blockStatisticsBuilder.stopUpdatingStatBlocks(); - blockStatisticsBuilder.runUpdatingStatBlocks(); + blockStatisticsBuilder.runUpdatingStatBlocksIfNeeded(); stopUpdatingTimeTrackSaved(); runUpdatingTimeTrackSaved(); } @@ -261,7 +261,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen if (!wasTrackMonitored) { blockStatisticsBuilder.stopUpdatingStatBlocks(); } else { - blockStatisticsBuilder.runUpdatingStatBlocks(); + blockStatisticsBuilder.runUpdatingStatBlocksIfNeeded(); } settings.SAVE_GLOBAL_TRACK_TO_GPX.set(wasTrackMonitored); updateStatus(); @@ -386,7 +386,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen @Override public void onResume() { super.onResume(); - blockStatisticsBuilder.runUpdatingStatBlocks(); + blockStatisticsBuilder.runUpdatingStatBlocksIfNeeded(); runUpdatingGPS(); runUpdatingTimeTrackSaved(); } From fe8bd8549cf9adc12ad42310b5e195ee23ea406f Mon Sep 17 00:00:00 2001 From: cepprice Date: Tue, 16 Feb 2021 20:15:39 +0500 Subject: [PATCH 43/45] Add text if app restart required after settings import --- OsmAnd/res/values/strings.xml | 1 + .../osmand/plus/settings/fragments/ImportCompleteFragment.java | 2 ++ 2 files changed, 3 insertions(+) diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index d2c6622fe6..c8c73ec331 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -12,6 +12,7 @@ --> + Application restart required to apply some settings. On pause Are you sure you want to stop recording?\nAll unsaved data will be lost. Track recording stopped diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/ImportCompleteFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/ImportCompleteFragment.java index abcd5afc0a..29f90c2cfe 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/ImportCompleteFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/ImportCompleteFragment.java @@ -102,6 +102,8 @@ public class ImportCompleteFragment extends BaseOsmAndFragment { } }); if (needRestart) { + description.append("\n\n"); + description.append(app.getString(R.string.app_restart_required)); setupRestartButton(root); } if (Build.VERSION.SDK_INT >= 21) { From bf2956f922709d2597781aab69c5215129221554 Mon Sep 17 00:00:00 2001 From: max-klaus Date: Tue, 16 Feb 2021 18:34:46 +0300 Subject: [PATCH 44/45] Fix Amazon free icon --- OsmAnd/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/OsmAnd/build.gradle b/OsmAnd/build.gradle index 11c9388fa0..91a8ce39ab 100644 --- a/OsmAnd/build.gradle +++ b/OsmAnd/build.gradle @@ -85,6 +85,7 @@ android { } amazonFree { java.srcDirs = ["src-nogms", "src-google"] + manifest.srcFile "AndroidManifest-gplayFree.xml" } amazonFull { java.srcDirs = ["src-nogms", "src-google"] From 2465e964494381ff2930d1ec46bff9146b85a1ef Mon Sep 17 00:00:00 2001 From: Skalii Date: Tue, 16 Feb 2021 17:42:14 +0200 Subject: [PATCH 45/45] fix show keyboard after open osm note --- .../net/osmand/plus/osmedit/dialogs/BugBottomSheetDialog.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OsmAnd/src/net/osmand/plus/osmedit/dialogs/BugBottomSheetDialog.java b/OsmAnd/src/net/osmand/plus/osmedit/dialogs/BugBottomSheetDialog.java index 7b4067c2f7..5104e98c03 100644 --- a/OsmAnd/src/net/osmand/plus/osmedit/dialogs/BugBottomSheetDialog.java +++ b/OsmAnd/src/net/osmand/plus/osmedit/dialogs/BugBottomSheetDialog.java @@ -64,6 +64,9 @@ public class BugBottomSheetDialog extends MenuBottomSheetDialogFragment { textBox.setDefaultHintTextColor(colorStateList); noteText = osmNoteView.findViewById(R.id.name_edit_text); noteText.setText(text); + if (noteText.requestFocus()) { + AndroidUtils.showSoftKeyboard(getActivity(), noteText); + } BaseBottomSheetItem editOsmNote = new BaseBottomSheetItem.Builder() .setCustomView(osmNoteView)