From 908033e0a924b6cafef83a23b00834c50ae64092 Mon Sep 17 00:00:00 2001 From: cepprice Date: Sat, 6 Mar 2021 15:03:26 +0500 Subject: [PATCH] Finish UI of Track appearance context menu --- OsmAnd/res/drawable/bg_track_gradient.xml | 13 ++ OsmAnd/res/layout/gradient_card.xml | 46 +++++ OsmAnd/res/layout/track_coloring_card.xml | 13 +- OsmAnd/res/layout/track_width_card.xml | 3 +- OsmAnd/res/values/colors.xml | 4 + OsmAnd/res/values/strings.xml | 3 + .../net/osmand/plus/track/GradientCard.java | 81 ++++++++ .../plus/track/TrackAppearanceFragment.java | 34 +++- .../osmand/plus/track/TrackColoringCard.java | 186 ++++++++++++------ 9 files changed, 301 insertions(+), 82 deletions(-) create mode 100644 OsmAnd/res/drawable/bg_track_gradient.xml create mode 100644 OsmAnd/res/layout/gradient_card.xml create mode 100644 OsmAnd/src/net/osmand/plus/track/GradientCard.java diff --git a/OsmAnd/res/drawable/bg_track_gradient.xml b/OsmAnd/res/drawable/bg_track_gradient.xml new file mode 100644 index 0000000000..c72829a45e --- /dev/null +++ b/OsmAnd/res/drawable/bg_track_gradient.xml @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/layout/gradient_card.xml b/OsmAnd/res/layout/gradient_card.xml new file mode 100644 index 0000000000..ff0834bee0 --- /dev/null +++ b/OsmAnd/res/layout/gradient_card.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/layout/track_coloring_card.xml b/OsmAnd/res/layout/track_coloring_card.xml index 2c7721f61d..0b1738293b 100644 --- a/OsmAnd/res/layout/track_coloring_card.xml +++ b/OsmAnd/res/layout/track_coloring_card.xml @@ -20,9 +20,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" - android:paddingTop="@dimen/context_menu_padding_margin_tiny" - android:visibility="gone" - android:paddingBottom="@dimen/content_padding"> + android:paddingTop="@dimen/context_menu_buttons_padding_bottom"> - - \ No newline at end of file diff --git a/OsmAnd/res/layout/track_width_card.xml b/OsmAnd/res/layout/track_width_card.xml index 3710ad43b4..744c90d137 100644 --- a/OsmAnd/res/layout/track_width_card.xml +++ b/OsmAnd/res/layout/track_width_card.xml @@ -45,14 +45,13 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:paddingBottom="@dimen/content_padding"> + android:paddingBottom="@dimen/favorites_select_group_button_height"> #1AFFFFFF #67727272 + #5ADC5F + #D4EF32 + #F3374D + \ No newline at end of file diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index ed1259ed1f..98c8410b5e 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -12,6 +12,9 @@ --> + Please select another type of colorization. + The track does not contain speed data. + The track does not contain altitude data. The recording will be continued. Distance by tap A toggle to show or hide the Coordinates widget on the map. diff --git a/OsmAnd/src/net/osmand/plus/track/GradientCard.java b/OsmAnd/src/net/osmand/plus/track/GradientCard.java new file mode 100644 index 0000000000..77d881574e --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/track/GradientCard.java @@ -0,0 +1,81 @@ +package net.osmand.plus.track; + +import android.text.Spannable; +import android.text.SpannableString; +import android.text.style.ForegroundColorSpan; +import android.widget.TextView; + +import net.osmand.AndroidUtils; +import net.osmand.GPXUtilities.GPXTrackAnalysis; +import net.osmand.plus.OsmAndFormatter; +import net.osmand.plus.R; +import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.helpers.AndroidUiHelper; +import net.osmand.plus.routepreparationmenu.cards.BaseCard; + +import androidx.annotation.NonNull; + +public class GradientCard extends BaseCard { + + private GPXTrackAnalysis gpxTrackAnalysis; + private GradientScaleType selectedScaleType = null; + + public GradientCard(@NonNull MapActivity mapActivity, @NonNull GPXTrackAnalysis gpxTrackAnalysis) { + super(mapActivity); + this.gpxTrackAnalysis = gpxTrackAnalysis; + } + + @Override + public int getCardLayoutId() { + return R.layout.gradient_card; + } + + @Override + protected void updateContent() { + if (selectedScaleType == null) { + AndroidUiHelper.updateVisibility(view, false); + return; + } + + AndroidUiHelper.updateVisibility(view, true); + TextView minValue = view.findViewById(R.id.min_value); + TextView maxValue = view.findViewById(R.id.max_value); + float min = getMinValue(); + float max = getMaxValue(min); + minValue.setText(formatValue(min)); + maxValue.setText(formatValue(max)); + } + + public void setSelectedScaleType(GradientScaleType type) { + this.selectedScaleType = type; + updateContent(); + } + + private float getMinValue() { + return (float) (selectedScaleType == GradientScaleType.ALTITUDE ? gpxTrackAnalysis.minElevation : 0.0); + } + + private float getMaxValue(float minValue) { + if (selectedScaleType == GradientScaleType.SPEED) { + return (Math.max(gpxTrackAnalysis.maxSpeed, app.getSettings().getApplicationMode().getMaxSpeed())); + } else if (selectedScaleType == GradientScaleType.ALTITUDE) { + return (float) Math.max(gpxTrackAnalysis.maxElevation, minValue + 50); + } else { + return 25; + } + } + + private CharSequence formatValue(float value) { + if (selectedScaleType == GradientScaleType.ALTITUDE) { + return OsmAndFormatter.getFormattedAlt(value, app); + } else if (selectedScaleType == GradientScaleType.SLOPE) { + return (int) value + " %"; + } + String speed = OsmAndFormatter.getFormattedSpeed(value, app); + Spannable formattedSpeed = new SpannableString(speed); + formattedSpeed.setSpan( + new ForegroundColorSpan(AndroidUtils.getColorFromAttr(app, android.R.attr.textColorSecondary)), + speed.indexOf(" "), speed.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + return formattedSpeed; + } +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/track/TrackAppearanceFragment.java b/OsmAnd/src/net/osmand/plus/track/TrackAppearanceFragment.java index 4642175b09..1de2c1c6ee 100644 --- a/OsmAnd/src/net/osmand/plus/track/TrackAppearanceFragment.java +++ b/OsmAnd/src/net/osmand/plus/track/TrackAppearanceFragment.java @@ -15,14 +15,6 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ScrollView; -import androidx.activity.OnBackPressedCallback; -import androidx.annotation.ColorInt; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentActivity; -import androidx.fragment.app.FragmentManager; - import net.osmand.AndroidUtils; import net.osmand.GPXUtilities.GPXFile; import net.osmand.PlatformUtil; @@ -60,6 +52,14 @@ import java.io.File; import java.util.ArrayList; import java.util.List; +import androidx.activity.OnBackPressedCallback; +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; + import static net.osmand.plus.dialogs.ConfigureMapMenu.CURRENT_TRACK_COLOR_ATTR; import static net.osmand.plus.dialogs.GpxAppearanceAdapter.TRACK_WIDTH_BOLD; import static net.osmand.plus.dialogs.GpxAppearanceAdapter.TRACK_WIDTH_MEDIUM; @@ -89,6 +89,7 @@ public class TrackAppearanceFragment extends ContextMenuScrollFragment implement private SplitIntervalCard splitIntervalCard; private TrackColoringCard trackColoringCard; private ColorsCard colorsCard; + private GradientCard gradientCard; private boolean showStartFinishIconsInitialValue; private ImageView trackIcon; @@ -340,6 +341,14 @@ public class TrackAppearanceFragment extends ContextMenuScrollFragment implement if (mapActivity != null) { if (card instanceof SplitIntervalCard) { SplitIntervalBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), trackDrawInfo, this); + } else if (card instanceof TrackColoringCard) { + GradientScaleType currentScaleType = ((TrackColoringCard) card).getSelectedScaleType(); + if (gradientCard != null) { + gradientCard.setSelectedScaleType(currentScaleType); + } + if (colorsCard != null) { + AndroidUiHelper.updateVisibility(colorsCard.getView(), currentScaleType == null); + } } else if (card instanceof ColorsCard) { int color = ((ColorsCard) card).getSelectedColor(); trackDrawInfo.setColor(color); @@ -553,6 +562,9 @@ public class TrackAppearanceFragment extends ContextMenuScrollFragment implement if (trackWidthCard != null) { trackWidthCard.updateItems(); } + if (trackColoringCard != null) { + trackColoringCard.updateColor(); + } MapActivity mapActivity = getMapActivity(); if (mapActivity != null) { mapActivity.refreshMap(); @@ -640,12 +652,16 @@ public class TrackAppearanceFragment extends ContextMenuScrollFragment implement showStartFinishCard.setListener(this); cardsContainer.addView(showStartFinishCard.build(mapActivity)); - trackColoringCard = new TrackColoringCard(mapActivity, trackDrawInfo, this); + trackColoringCard = new TrackColoringCard(mapActivity, selectedGpxFile.getTrackAnalysis(app), trackDrawInfo); trackColoringCard.setListener(this); cardsContainer.addView(trackColoringCard.build(mapActivity)); setupColorsCard(cardsContainer); + gradientCard = new GradientCard(mapActivity, selectedGpxFile.getTrackAnalysis(app)); + AndroidUiHelper.updateVisibility(gradientCard.build(mapActivity), false); + cardsContainer.addView(gradientCard.getView()); + trackWidthCard = new TrackWidthCard(mapActivity, trackDrawInfo, new OnNeedScrollListener() { @Override diff --git a/OsmAnd/src/net/osmand/plus/track/TrackColoringCard.java b/OsmAnd/src/net/osmand/plus/track/TrackColoringCard.java index 0a17f5e06b..44645180ea 100644 --- a/OsmAnd/src/net/osmand/plus/track/TrackColoringCard.java +++ b/OsmAnd/src/net/osmand/plus/track/TrackColoringCard.java @@ -7,14 +7,10 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import androidx.annotation.DrawableRes; -import androidx.annotation.NonNull; -import androidx.appcompat.content.res.AppCompatResources; -import androidx.core.content.ContextCompat; -import androidx.fragment.app.Fragment; -import androidx.recyclerview.widget.RecyclerView; +import com.google.android.material.snackbar.Snackbar; import net.osmand.AndroidUtils; +import net.osmand.GPXUtilities.GPXTrackAnalysis; import net.osmand.PlatformUtil; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; @@ -27,26 +23,29 @@ import org.apache.commons.logging.Log; import java.util.ArrayList; import java.util.List; -public class TrackColoringCard extends BaseCard { +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.appcompat.content.res.AppCompatResources; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; - private static final int MINIMUM_CONTRAST_RATIO = 3; +public class TrackColoringCard extends BaseCard { private final static String SOLID_COLOR = "solid_color"; private static final Log log = PlatformUtil.getLog(TrackColoringCard.class); + private GPXTrackAnalysis gpxTrackAnalysis; private TrackDrawInfo trackDrawInfo; private TrackColoringAdapter coloringAdapter; private TrackAppearanceItem selectedAppearanceItem; private List appearanceItems; - private Fragment target; - - public TrackColoringCard(MapActivity mapActivity, TrackDrawInfo trackDrawInfo, Fragment target) { + public TrackColoringCard(MapActivity mapActivity, GPXTrackAnalysis gpxTrackAnalysis, TrackDrawInfo trackDrawInfo) { super(mapActivity); - this.target = target; this.trackDrawInfo = trackDrawInfo; - appearanceItems = getGradientAppearanceItems(); + this.gpxTrackAnalysis = gpxTrackAnalysis; + appearanceItems = getTrackAppearanceItems(); } @Override @@ -58,25 +57,44 @@ public class TrackColoringCard extends BaseCard { protected void updateContent() { updateHeader(); -// coloringAdapter = new TrackColoringAdapter(appearanceItems); -// RecyclerView groupRecyclerView = view.findViewById(R.id.recycler_view); -// groupRecyclerView.setAdapter(coloringAdapter); -// groupRecyclerView.setLayoutManager(new LinearLayoutManager(app, RecyclerView.HORIZONTAL, false)); + coloringAdapter = new TrackColoringAdapter(appearanceItems); + RecyclerView groupRecyclerView = view.findViewById(R.id.recycler_view); + groupRecyclerView.setLayoutManager(new LinearLayoutManager(app, RecyclerView.HORIZONTAL, false)); + groupRecyclerView.setAdapter(coloringAdapter); AndroidUiHelper.updateVisibility(view.findViewById(R.id.top_divider), isShowDivider()); } - private List getGradientAppearanceItems() { + public void updateColor() { + if (coloringAdapter != null) { + // Provide empty object to update item without animation + coloringAdapter.notifyItemChanged(0, new Object()); + } + } + + public GradientScaleType getSelectedScaleType() { + String attrName = selectedAppearanceItem.getAttrName(); + return attrName.equals(SOLID_COLOR) ? null : GradientScaleType.valueOf(attrName.toUpperCase()); + } + + private List getTrackAppearanceItems() { List items = new ArrayList<>(); - items.add(new TrackAppearanceItem(SOLID_COLOR, app.getString(R.string.track_coloring_solid), R.drawable.ic_action_circle)); - -// for (GradientScaleType scaleType : GradientScaleType.values()) { -// items.add(new TrackAppearanceItem(scaleType.getTypeName(), scaleType.getHumanString(app), scaleType.getIconId())); -// } - + items.add(new TrackAppearanceItem(SOLID_COLOR, app.getString(R.string.track_coloring_solid), R.drawable.ic_action_circle, true)); + for (GradientScaleType scaleType : GradientScaleType.values()) { + items.add(new TrackAppearanceItem(scaleType.getTypeName(), + scaleType.getHumanString(app), scaleType.getIconId(), isScaleTypeActive(scaleType))); + } return items; } + private boolean isScaleTypeActive(GradientScaleType scaleType) { + if (scaleType == GradientScaleType.SPEED) { + return gpxTrackAnalysis.isSpeedSpecified(); + } else { + return gpxTrackAnalysis.isElevationSpecified(); + } + } + private TrackAppearanceItem getSelectedAppearanceItem() { if (selectedAppearanceItem == null) { GradientScaleType scaleType = trackDrawInfo.getGradientScaleType(); @@ -98,27 +116,22 @@ public class TrackColoringCard extends BaseCard { headerView.setBackgroundDrawable(null); TextView titleView = view.findViewById(R.id.title); - titleView.setText(R.string.select_color); + titleView.setText(R.string.shared_string_color); TextView descriptionView = view.findViewById(R.id.description); descriptionView.setText(getSelectedAppearanceItem().getLocalizedValue()); } - private void updateColorSelector() { - boolean visible = getSelectedAppearanceItem().getAttrName().equals(SOLID_COLOR); - AndroidUiHelper.updateVisibility(view.findViewById(R.id.select_color), visible); - } - public void setGradientScaleType(TrackAppearanceItem item) { + selectedAppearanceItem = item; if (item.getAttrName().equals(SOLID_COLOR)) { trackDrawInfo.setGradientScaleType(null); } else { - trackDrawInfo.setGradientScaleType(GradientScaleType.valueOf(item.getAttrName())); + trackDrawInfo.setGradientScaleType(GradientScaleType.valueOf(item.getAttrName().toUpperCase())); } mapActivity.refreshMap(); updateHeader(); - updateColorSelector(); } private class TrackColoringAdapter extends RecyclerView.Adapter { @@ -136,42 +149,38 @@ public class TrackColoringCard extends BaseCard { View view = themedInflater.inflate(R.layout.point_editor_group_select_item, parent, false); view.getLayoutParams().width = app.getResources().getDimensionPixelSize(R.dimen.gpx_group_button_width); view.getLayoutParams().height = app.getResources().getDimensionPixelSize(R.dimen.gpx_group_button_height); - - TrackAppearanceViewHolder holder = new TrackAppearanceViewHolder(view); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - AndroidUtils.setBackground(app, holder.button, nightMode, R.drawable.ripple_solid_light_6dp, - R.drawable.ripple_solid_dark_6dp); - } - return holder; + return new TrackAppearanceViewHolder(view); } @Override public void onBindViewHolder(@NonNull final TrackAppearanceViewHolder holder, int position) { - TrackAppearanceItem item = items.get(position); - holder.title.setText(item.getLocalizedValue()); + final TrackAppearanceItem item = items.get(position); - updateButtonBg(holder, item); - - int colorId; - if (item.getAttrName().equals(SOLID_COLOR)) { - colorId = trackDrawInfo.getColor(); - } else if (item.getAttrName().equals(getSelectedAppearanceItem().getAttrName())) { - colorId = ContextCompat.getColor(app, nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light); - } else { - colorId = AndroidUtils.getColorFromAttr(holder.itemView.getContext(), R.attr.default_icon_color); + if (item.isActive() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + AndroidUtils.setBackground(app, holder.button, nightMode, R.drawable.ripple_solid_light_6dp, + R.drawable.ripple_solid_dark_6dp); } - holder.icon.setImageDrawable(app.getUIUtilities().getPaintedIcon(item.getIconId(), colorId)); + updateButtonBg(holder, item); + updateTextAndIconColor(holder, item); + holder.title.setText(item.getLocalizedValue()); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { + if (!item.isActive()) { + showSnackbar(view, item.getAttrName()); + return; + } + int prevSelectedPosition = getItemPosition(getSelectedAppearanceItem()); selectedAppearanceItem = items.get(holder.getAdapterPosition()); notifyItemChanged(holder.getAdapterPosition()); notifyItemChanged(prevSelectedPosition); - setGradientScaleType(selectedAppearanceItem); + if (getListener() != null) { + getListener().onCardPressed(TrackColoringCard.this); + } } }); } @@ -179,18 +188,70 @@ public class TrackColoringCard extends BaseCard { private void updateButtonBg(TrackAppearanceViewHolder holder, TrackAppearanceItem item) { GradientDrawable rectContourDrawable = (GradientDrawable) AppCompatResources.getDrawable(app, R.drawable.bg_select_group_button_outline); if (rectContourDrawable != null) { - if (getSelectedAppearanceItem() != null && getSelectedAppearanceItem().equals(item)) { - int strokeColor = ContextCompat.getColor(app, nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light); - rectContourDrawable.setStroke(AndroidUtils.dpToPx(app, 2), strokeColor); + boolean itemSelected = getSelectedAppearanceItem() != null && getSelectedAppearanceItem().equals(item); + + int strokeColor; + int backgroundColor; + int strokeWidth; + + if (itemSelected) { + strokeColor = AndroidUtils.getColorFromAttr(app, R.attr.pstsIndicatorColor); + backgroundColor = 0; + strokeWidth = 2; + } else if (!item.isActive()) { + strokeColor = AndroidUtils.getColorFromAttr(app, R.attr.stroked_buttons_and_links_outline); + backgroundColor = AndroidUtils.getColorFromAttr(app, R.attr.ctx_menu_card_btn); + strokeWidth = 2; } else { - int strokeColor = ContextCompat.getColor(app, nightMode ? R.color.stroked_buttons_and_links_outline_dark - : R.color.stroked_buttons_and_links_outline_light); - rectContourDrawable.setStroke(AndroidUtils.dpToPx(app, 1), strokeColor); + strokeColor = AndroidUtils.getColorFromAttr(app, R.attr.stroked_buttons_and_links_outline); + backgroundColor = 0; + strokeWidth = 1; } + + rectContourDrawable.mutate(); + rectContourDrawable.setColor(backgroundColor); + rectContourDrawable.setStroke(AndroidUtils.dpToPx(app, strokeWidth), strokeColor); holder.button.setImageDrawable(rectContourDrawable); } } + private void updateTextAndIconColor(TrackAppearanceViewHolder holder, TrackAppearanceItem item) { + boolean isSelected = item.getAttrName().equals(getSelectedAppearanceItem().getAttrName()); + int iconColorId; + int textColorId; + + if (isSelected) { + iconColorId = AndroidUtils.getColorFromAttr(app, R.attr.default_icon_color); + textColorId = AndroidUtils.getColorFromAttr(app, android.R.attr.textColor); + } else if (!item.isActive()) { + iconColorId = AndroidUtils.getColorFromAttr(app, R.attr.default_icon_color); + textColorId = AndroidUtils.getColorFromAttr(app, android.R.attr.textColorSecondary); + } else { + iconColorId = AndroidUtils.getColorFromAttr(app, R.attr.pstsIndicatorColor); + textColorId = iconColorId; + } + + if (item.getAttrName().equals(SOLID_COLOR)) { + iconColorId = trackDrawInfo.getColor(); + } + + holder.icon.setImageDrawable(app.getUIUtilities().getPaintedIcon(item.getIconId(), iconColorId)); + holder.title.setTextColor(textColorId); + } + + private void showSnackbar(View view, String attrName) { + if (view == null || mapActivity == null) { + return; + } + String text = attrName.equals(GradientScaleType.SPEED.getTypeName()) ? + app.getString(R.string.track_has_no_speed) : app.getString(R.string.track_has_no_altitude); + text += " " + app.getString(R.string.select_another_colorization); + Snackbar snackbar = Snackbar.make(view, text, Snackbar.LENGTH_LONG) + .setAnchorView(mapActivity.findViewById(R.id.dismiss_button)); + UiUtilities.setupSnackbar(snackbar, nightMode); + snackbar.show(); + } + @Override public int getItemCount() { return items.size(); @@ -209,10 +270,13 @@ public class TrackColoringCard extends BaseCard { @DrawableRes private int iconId; - public TrackAppearanceItem(String attrName, String localizedValue, int iconId) { + private boolean isActive; + + public TrackAppearanceItem(String attrName, String localizedValue, int iconId, boolean isActive) { this.attrName = attrName; this.localizedValue = localizedValue; this.iconId = iconId; + this.isActive = isActive; } public String getAttrName() { @@ -226,5 +290,9 @@ public class TrackColoringCard extends BaseCard { public int getIconId() { return iconId; } + + public boolean isActive() { + return isActive; + } } } \ No newline at end of file