Finish UI of Track appearance context menu

This commit is contained in:
cepprice 2021-03-06 15:03:26 +05:00
parent c762e072d2
commit 908033e0a9
9 changed files with 301 additions and 82 deletions

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<gradient
android:angle="0"
android:startColor="@color/track_gradient_start"
android:centerColor="@color/track_gradient_center"
android:endColor="@color/track_gradient_end"
android:type="linear" />
</shape>
</item>
</selector>

View file

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="@dimen/content_padding"
android:paddingStart="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding">
<View
android:layout_width="match_parent"
android:layout_height="@dimen/pages_item_size"
android:layout_marginBottom="@dimen/content_padding_half"
android:background="@drawable/bg_track_gradient" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/min_value"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="?attr/main_font_color_basic"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_regular"
tools:text="100 m"/>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/max_value"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end"
android:textColor="?attr/main_font_color_basic"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_regular"
tools:text="100 m"/>
</LinearLayout>
</LinearLayout>

View file

@ -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">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
@ -41,13 +39,4 @@
</LinearLayout>
<com.google.android.material.internal.FlowLayout
android:id="@+id/select_color"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding_small"
android:layout_marginLeft="@dimen/content_padding_small"
android:layout_marginTop="@dimen/context_menu_padding_margin_tiny"
android:layout_marginBottom="@dimen/content_padding_half" />
</LinearLayout>

View file

@ -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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="@dimen/content_padding"
android:paddingTop="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding">
<net.osmand.plus.widgets.TextViewEx

View file

@ -482,4 +482,8 @@
<color name="text_input_background_dark">#1AFFFFFF</color>
<color name="mtrl_textinput_default_box_stroke_color">#67727272</color>
<color name="track_gradient_start">#5ADC5F</color>
<color name="track_gradient_center">#D4EF32</color>
<color name="track_gradient_end">#F3374D</color>
</resources>

View file

@ -12,6 +12,9 @@
-->
<string name="select_another_colorization">Please select another type of colorization.</string>
<string name="track_has_no_speed">The track does not contain speed data.</string>
<string name="track_has_no_altitude">The track does not contain altitude data.</string>
<string name="track_recording_will_be_continued">The recording will be continued.</string>
<string name="map_widget_distance_by_tap">Distance by tap</string>
<string name="quick_action_coordinates_widget_descr">A toggle to show or hide the Coordinates widget on the map.</string>

View file

@ -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;
}
}

View file

@ -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

View file

@ -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<TrackAppearanceItem> 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<TrackAppearanceItem> 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<TrackAppearanceItem> getTrackAppearanceItems() {
List<TrackAppearanceItem> 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<TrackAppearanceViewHolder> {
@ -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;
}
}
}