Merge pull request #10123 from osmandapp/Colors-customs

Add favorite custom colors
This commit is contained in:
Vitaliy 2020-11-02 04:13:27 +02:00 committed by GitHub
commit ca7244a1e5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 368 additions and 259 deletions

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.material.internal.FlowLayout
android:id="@+id/select_color"
android:layout_width="match_parent"
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

@ -444,9 +444,9 @@
osmand:typeface="@string/font_roboto_medium" /> osmand:typeface="@string/font_roboto_medium" />
</LinearLayout> </LinearLayout>
<net.osmand.plus.widgets.FlowLayout <LinearLayout
android:id="@+id/select_color" android:id="@+id/select_color"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding_small" android:layout_marginStart="@dimen/content_padding_small"
android:layout_marginLeft="@dimen/content_padding_small" android:layout_marginLeft="@dimen/content_padding_small"

View file

@ -22,6 +22,7 @@ import android.view.inputmethod.InputMethodManager;
import android.widget.EditText; import android.widget.EditText;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView; import android.widget.ScrollView;
import android.widget.TextView; import android.widget.TextView;
@ -52,6 +53,10 @@ import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.ColorDialogs; import net.osmand.plus.helpers.ColorDialogs;
import net.osmand.plus.mapcontextmenu.MapContextMenu; import net.osmand.plus.mapcontextmenu.MapContextMenu;
import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter; import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter;
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener;
import net.osmand.plus.track.ColorsCard;
import net.osmand.plus.track.CustomColorBottomSheet.ColorPickerListener;
import net.osmand.plus.widgets.FlowLayout; import net.osmand.plus.widgets.FlowLayout;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
@ -72,7 +77,7 @@ import static net.osmand.data.FavouritePoint.DEFAULT_UI_ICON_ID;
import static net.osmand.plus.FavouritesDbHelper.FavoriteGroup.PERSONAL_CATEGORY; import static net.osmand.plus.FavouritesDbHelper.FavoriteGroup.PERSONAL_CATEGORY;
import static net.osmand.plus.FavouritesDbHelper.FavoriteGroup.isPersonalCategoryDisplayName; import static net.osmand.plus.FavouritesDbHelper.FavoriteGroup.isPersonalCategoryDisplayName;
public abstract class PointEditorFragmentNew extends BaseOsmAndFragment { public abstract class PointEditorFragmentNew extends BaseOsmAndFragment implements ColorPickerListener, CardListener {
public static final String TAG = PointEditorFragmentNew.class.getSimpleName(); public static final String TAG = PointEditorFragmentNew.class.getSimpleName();
@ -101,6 +106,7 @@ public abstract class PointEditorFragmentNew extends BaseOsmAndFragment {
private EditText descriptionEdit; private EditText descriptionEdit;
private EditText addressEdit; private EditText addressEdit;
private int layoutHeightPrevious = 0; private int layoutHeightPrevious = 0;
private ColorsCard colorsCard;
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
@ -458,48 +464,49 @@ public abstract class PointEditorFragmentNew extends BaseOsmAndFragment {
} }
private void createColorSelector() { private void createColorSelector() {
FlowLayout selectColor = view.findViewById(R.id.select_color); MapActivity mapActivity = getMapActivity();
for (int color : ColorDialogs.pallette) { if (mapActivity != null) {
selectColor.addView(createColorItemView(color, selectColor), new FlowLayout.LayoutParams(0, 0)); List<Integer> colors = new ArrayList<>();
} for (int color : ColorDialogs.pallette) {
int customColor = getPointColor(); colors.add(color);
if (!ColorDialogs.isPaletteColor(customColor)) { }
selectColor.addView(createColorItemView(customColor, selectColor), new FlowLayout.LayoutParams(0, 0)); int customColor = getPointColor();
if (!ColorDialogs.isPaletteColor(customColor)) {
colors.add(customColor);
}
colorsCard = new ColorsCard(mapActivity, selectedColor, this, colors);
colorsCard.setListener(this);
LinearLayout selectColor = view.findViewById(R.id.select_color);
selectColor.addView(colorsCard.build(view.getContext()));
} }
} }
private View createColorItemView(@ColorInt final int color, final FlowLayout rootView) { @Override
FrameLayout colorItemView = (FrameLayout) UiUtilities.getInflater(getContext(), nightMode) public void onColorSelected(Integer prevColor, int newColor) {
.inflate(R.layout.point_editor_button, rootView, false); colorsCard.onColorSelected(prevColor, newColor);
ImageView outline = colorItemView.findViewById(R.id.outline); int color = colorsCard.getSelectedColor();
outline.setImageDrawable( updateColorSelector(color, view);
UiUtilities.tintDrawable(AppCompatResources.getDrawable(app, R.drawable.bg_point_circle_contour), }
ContextCompat.getColor(app,
nightMode ? R.color.stroked_buttons_and_links_outline_dark @Override
: R.color.stroked_buttons_and_links_outline_light))); public void onCardLayoutNeeded(@NonNull BaseCard card) {
ImageView backgroundCircle = colorItemView.findViewById(R.id.background);
backgroundCircle.setImageDrawable(UiUtilities.tintDrawable(AppCompatResources.getDrawable(app, R.drawable.bg_point_circle), color)); }
backgroundCircle.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onCardPressed(@NonNull BaseCard card) {
updateColorSelector(color, rootView); if (card instanceof ColorsCard) {
} int color = ((ColorsCard) card).getSelectedColor();
}); updateColorSelector(color, view);
colorItemView.setTag(color); }
return colorItemView; }
@Override
public void onCardButtonPressed(@NonNull BaseCard card, int buttonIndex) {
} }
private void updateColorSelector(int color, View rootView) { private void updateColorSelector(int color, View rootView) {
View oldColor = rootView.findViewWithTag(selectedColor);
if (oldColor != null) {
oldColor.findViewById(R.id.outline).setVisibility(View.INVISIBLE);
ImageView icon = oldColor.findViewById(R.id.icon);
icon.setImageDrawable(UiUtilities.tintDrawable(icon.getDrawable(), R.color.icon_color_default_light));
}
View newColor = rootView.findViewWithTag(color);
if (newColor != null) {
newColor.findViewById(R.id.outline).setVisibility(View.VISIBLE);
}
((TextView) view.findViewById(R.id.color_name)).setText(ColorDialogs.getColorName(color)); ((TextView) view.findViewById(R.id.color_name)).setText(ColorDialogs.getColorName(color));
selectedColor = color; selectedColor = color;
setColor(color); setColor(color);

View file

@ -36,9 +36,9 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
public class RouteInfoCard extends BaseCard { import static net.osmand.plus.track.ColorsCard.MINIMUM_CONTRAST_RATIO;
private static final int MINIMUM_CONTRAST_RATIO = 3; public class RouteInfoCard extends BaseCard {
private RouteStatistics routeStatistics; private RouteStatistics routeStatistics;
private GPXTrackAnalysis analysis; private GPXTrackAnalysis analysis;

View file

@ -0,0 +1,244 @@
package net.osmand.plus.track;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.ColorUtils;
import androidx.fragment.app.Fragment;
import com.google.android.material.internal.FlowLayout;
import net.osmand.AndroidUtils;
import net.osmand.PlatformUtil;
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.routepreparationmenu.cards.BaseCard;
import net.osmand.plus.track.CustomColorBottomSheet.ColorPickerListener;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
import java.util.ArrayList;
import java.util.List;
public class ColorsCard extends BaseCard implements ColorPickerListener {
public static final int MAX_CUSTOM_COLORS = 6;
public static final int MINIMUM_CONTRAST_RATIO = 3;
private static final Log log = PlatformUtil.getLog(TrackColoringCard.class);
public static final int INVALID_VALUE = -1;
private Fragment targetFragment;
private List<Integer> colors;
private List<Integer> customColors;
private int selectedColor;
@Override
public int getCardLayoutId() {
return R.layout.colors_card;
}
public ColorsCard(MapActivity mapActivity, int selectedColor, Fragment targetFragment, List<Integer> colors) {
super(mapActivity);
this.targetFragment = targetFragment;
this.selectedColor = selectedColor;
this.colors = colors;
customColors = getCustomColors(app);
}
public int getSelectedColor() {
return selectedColor;
}
public void setSelectedColor(int selectedColor) {
this.selectedColor = selectedColor;
}
@Override
public void onColorSelected(Integer prevColor, int newColor) {
if (prevColor != null) {
int index = customColors.indexOf(prevColor);
if (index != INVALID_VALUE) {
customColors.set(index, newColor);
}
if (selectedColor == prevColor) {
selectedColor = newColor;
}
} else if (customColors.size() < MAX_CUSTOM_COLORS) {
customColors.add(newColor);
selectedColor = newColor;
}
saveCustomColors();
updateContent();
}
@Override
protected void updateContent() {
createColorSelector();
updateColorSelector(selectedColor, view);
}
private void createColorSelector() {
FlowLayout selectColor = view.findViewById(R.id.select_color);
selectColor.removeAllViews();
for (int color : customColors) {
selectColor.addView(createColorItemView(color, selectColor, true));
}
if (customColors.size() < 6) {
selectColor.addView(createAddCustomColorItemView(selectColor));
}
selectColor.addView(createDividerView(selectColor));
for (int color : colors) {
selectColor.addView(createColorItemView(color, selectColor, false));
}
updateColorSelector(selectedColor, selectColor);
}
private void updateColorSelector(int color, View rootView) {
View oldColor = rootView.findViewWithTag(selectedColor);
if (oldColor != null) {
oldColor.findViewById(R.id.outline).setVisibility(View.INVISIBLE);
ImageView icon = oldColor.findViewById(R.id.icon);
icon.setImageDrawable(UiUtilities.tintDrawable(icon.getDrawable(), R.color.icon_color_default_light));
}
View newColor = rootView.findViewWithTag(color);
if (newColor != null) {
newColor.findViewById(R.id.outline).setVisibility(View.VISIBLE);
}
}
private View createColorItemView(@ColorInt final int color, final FlowLayout rootView, boolean customColor) {
View colorItemView = createCircleView(rootView);
ImageView backgroundCircle = colorItemView.findViewById(R.id.background);
Drawable transparencyIcon = getTransparencyIcon(app, color);
Drawable colorIcon = app.getUIUtilities().getPaintedIcon(R.drawable.bg_point_circle, color);
Drawable layeredIcon = UiUtilities.getLayeredIcon(transparencyIcon, colorIcon);
double contrastRatio = ColorUtils.calculateContrast(color, ContextCompat.getColor(app, nightMode ? R.color.card_and_list_background_dark : R.color.card_and_list_background_light));
if (contrastRatio < MINIMUM_CONTRAST_RATIO) {
backgroundCircle.setBackgroundResource(nightMode ? R.drawable.circle_contour_bg_dark : R.drawable.circle_contour_bg_light);
}
backgroundCircle.setImageDrawable(layeredIcon);
backgroundCircle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
updateColorSelector(color, rootView);
selectedColor = color;
CardListener listener = getListener();
if (listener != null) {
listener.onCardPressed(ColorsCard.this);
}
}
});
if (customColor) {
backgroundCircle.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
CustomColorBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), targetFragment, color);
}
return false;
}
});
}
colorItemView.setTag(color);
return colorItemView;
}
private View createAddCustomColorItemView(FlowLayout rootView) {
View colorItemView = createCircleView(rootView);
ImageView backgroundCircle = colorItemView.findViewById(R.id.background);
int bgColorId = nightMode ? R.color.activity_background_color_dark : R.color.activity_background_color_light;
Drawable backgroundIcon = app.getUIUtilities().getIcon(R.drawable.bg_point_circle, bgColorId);
ImageView icon = colorItemView.findViewById(R.id.icon);
icon.setVisibility(View.VISIBLE);
int activeColorResId = nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light;
icon.setImageDrawable(app.getUIUtilities().getIcon(R.drawable.ic_action_plus, activeColorResId));
backgroundCircle.setImageDrawable(backgroundIcon);
backgroundCircle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
CustomColorBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), targetFragment, null);
}
}
});
return colorItemView;
}
private View createDividerView(FlowLayout rootView) {
LayoutInflater themedInflater = UiUtilities.getInflater(view.getContext(), nightMode);
View divider = themedInflater.inflate(R.layout.simple_divider_item, rootView, false);
LinearLayout dividerContainer = new LinearLayout(view.getContext());
dividerContainer.addView(divider);
dividerContainer.setPadding(0, AndroidUtils.dpToPx(app, 1), 0, AndroidUtils.dpToPx(app, 5));
return dividerContainer;
}
private View createCircleView(ViewGroup rootView) {
LayoutInflater themedInflater = UiUtilities.getInflater(view.getContext(), nightMode);
View circleView = themedInflater.inflate(R.layout.point_editor_button, rootView, false);
ImageView outline = circleView.findViewById(R.id.outline);
int colorId = nightMode ? R.color.stroked_buttons_and_links_outline_dark : R.color.stroked_buttons_and_links_outline_light;
Drawable contourIcon = app.getUIUtilities().getIcon(R.drawable.bg_point_circle_contour, colorId);
outline.setImageDrawable(contourIcon);
return circleView;
}
private Drawable getTransparencyIcon(OsmandApplication app, @ColorInt int color) {
int colorWithoutAlpha = UiUtilities.removeAlpha(color);
int transparencyColor = UiUtilities.getColorWithAlpha(colorWithoutAlpha, 0.8f);
return app.getUIUtilities().getPaintedIcon(R.drawable.ic_bg_transparency, transparencyColor);
}
public static List<Integer> getCustomColors(@NonNull OsmandApplication app) {
List<Integer> colors = new ArrayList<>();
List<String> colorNames = app.getSettings().CUSTOM_TRACK_COLORS.getStringsList();
if (colorNames != null) {
for (String colorHex : colorNames) {
try {
if (!Algorithms.isEmpty(colorHex)) {
int color = Algorithms.parseColor(colorHex);
colors.add(color);
}
} catch (IllegalArgumentException e) {
log.error(e);
}
}
}
return colors;
}
private void saveCustomColors() {
List<String> colorNames = new ArrayList<>();
for (Integer color : customColors) {
String colorHex = Algorithms.colorToString(color);
colorNames.add(colorHex);
}
app.getSettings().CUSTOM_TRACK_COLORS.setStringsList(colorNames);
}
}

View file

@ -38,6 +38,8 @@ import net.osmand.plus.UiUtilities.DialogButtonType;
import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.ContextMenuScrollFragment; import net.osmand.plus.base.ContextMenuScrollFragment;
import net.osmand.plus.dialogs.GpxAppearanceAdapter; 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.helpers.AndroidUiHelper;
import net.osmand.plus.routepreparationmenu.cards.BaseCard; import net.osmand.plus.routepreparationmenu.cards.BaseCard;
import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener; import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener;
@ -58,6 +60,7 @@ import static net.osmand.plus.activities.TrackActivity.TRACK_FILE_NAME;
import static net.osmand.plus.dialogs.ConfigureMapMenu.CURRENT_TRACK_COLOR_ATTR; 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_BOLD;
import static net.osmand.plus.dialogs.GpxAppearanceAdapter.TRACK_WIDTH_MEDIUM; import static net.osmand.plus.dialogs.GpxAppearanceAdapter.TRACK_WIDTH_MEDIUM;
import static net.osmand.plus.dialogs.GpxAppearanceAdapter.getAppearanceItems;
public class TrackAppearanceFragment extends ContextMenuScrollFragment implements CardListener, ColorPickerListener { public class TrackAppearanceFragment extends ContextMenuScrollFragment implements CardListener, ColorPickerListener {
@ -80,6 +83,7 @@ public class TrackAppearanceFragment extends ContextMenuScrollFragment implement
private TrackWidthCard trackWidthCard; private TrackWidthCard trackWidthCard;
private SplitIntervalCard splitIntervalCard; private SplitIntervalCard splitIntervalCard;
private TrackColoringCard trackColoringCard; private TrackColoringCard trackColoringCard;
private ColorsCard colorsCard;
private boolean showStartFinishIconsInitialValue; private boolean showStartFinishIconsInitialValue;
private ImageView trackIcon; private ImageView trackIcon;
@ -339,7 +343,9 @@ public class TrackAppearanceFragment extends ContextMenuScrollFragment implement
if (mapActivity != null) { if (mapActivity != null) {
if (card instanceof SplitIntervalCard) { if (card instanceof SplitIntervalCard) {
SplitIntervalBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), trackDrawInfo, this); SplitIntervalBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), trackDrawInfo, this);
} else if (card instanceof TrackColoringCard) { } else if (card instanceof ColorsCard) {
int color = ((ColorsCard) card).getSelectedColor();
trackDrawInfo.setColor(color);
updateColorItems(); updateColorItems();
} else if (card instanceof TrackWidthCard) { } else if (card instanceof TrackWidthCard) {
updateAppearanceIcon(); updateAppearanceIcon();
@ -356,7 +362,15 @@ public class TrackAppearanceFragment extends ContextMenuScrollFragment implement
@Override @Override
public void onColorSelected(Integer prevColor, int newColor) { public void onColorSelected(Integer prevColor, int newColor) {
trackColoringCard.onColorSelected(prevColor, newColor); if (prevColor != null) {
List<Integer> customColors = ColorsCard.getCustomColors(app);
int index = customColors.indexOf(prevColor);
if (index != ColorsCard.INVALID_VALUE) {
saveCustomColorsToTracks(prevColor, newColor);
}
}
trackDrawInfo.setColor(newColor);
colorsCard.onColorSelected(prevColor, newColor);
updateColorItems(); updateColorItems();
} }
@ -475,6 +489,7 @@ public class TrackAppearanceFragment extends ContextMenuScrollFragment implement
AndroidUiHelper.updateVisibility(saveButton, true); AndroidUiHelper.updateVisibility(saveButton, true);
AndroidUiHelper.updateVisibility(view.findViewById(R.id.buttons_divider), true); AndroidUiHelper.updateVisibility(view.findViewById(R.id.buttons_divider), true);
} }
private void showShadowButton() { private void showShadowButton() {
buttonsShadow.setVisibility(View.VISIBLE); buttonsShadow.setVisibility(View.VISIBLE);
buttonsShadow.animate() buttonsShadow.animate()
@ -511,11 +526,30 @@ public class TrackAppearanceFragment extends ContextMenuScrollFragment implement
AndroidUiHelper.updateVisibility(buttonsShadow, scrollToBottomAvailable); AndroidUiHelper.updateVisibility(buttonsShadow, scrollToBottomAvailable);
} }
private void saveCustomColorsToTracks(int prevColor, int newColor) {
List<GpxDataItem> gpxDataItems = app.getGpxDbHelper().getItems();
for (GpxDataItem dataItem : gpxDataItems) {
if (prevColor == dataItem.getColor()) {
app.getGpxDbHelper().updateColor(dataItem, newColor);
}
}
List<SelectedGpxFile> files = app.getSelectedGpxHelper().getSelectedGPXFiles();
for (SelectedGpxFile selectedGpxFile : files) {
if (prevColor == selectedGpxFile.getGpxFile().getColor(0)) {
selectedGpxFile.getGpxFile().setColor(newColor);
}
}
}
private void updateColorItems() { private void updateColorItems() {
updateAppearanceIcon(); updateAppearanceIcon();
if (trackWidthCard != null) { if (trackWidthCard != null) {
trackWidthCard.updateItems(); trackWidthCard.updateItems();
} }
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.refreshMap();
}
} }
private void saveTrackInfo() { private void saveTrackInfo() {
@ -627,6 +661,8 @@ public class TrackAppearanceFragment extends ContextMenuScrollFragment implement
trackColoringCard.setListener(this); trackColoringCard.setListener(this);
cardsContainer.addView(trackColoringCard.build(mapActivity)); cardsContainer.addView(trackColoringCard.build(mapActivity));
setupColorsCard(cardsContainer);
trackWidthCard = new TrackWidthCard(mapActivity, trackDrawInfo, new OnNeedScrollListener() { trackWidthCard = new TrackWidthCard(mapActivity, trackDrawInfo, new OnNeedScrollListener() {
@Override @Override
@ -647,6 +683,26 @@ public class TrackAppearanceFragment extends ContextMenuScrollFragment implement
} }
} }
private void setupColorsCard(ViewGroup cardsContainer) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
List<Integer> colors = getTrackColors();
colorsCard = new ColorsCard(mapActivity, trackDrawInfo.getColor(), this, colors);
colorsCard.setListener(this);
cardsContainer.addView(colorsCard.build(mapActivity));
}
}
private List<Integer> getTrackColors() {
List<Integer> colors = new ArrayList<>();
for (AppearanceListItem appearanceListItem : getAppearanceItems(app, GpxAppearanceAdapterType.TRACK_COLOR)) {
if (!colors.contains(appearanceListItem.getColor())) {
colors.add(appearanceListItem.getColor());
}
}
return colors;
}
public List<GpxDisplayGroup> getGpxDisplayGroups() { public List<GpxDisplayGroup> getGpxDisplayGroups() {
GPXFile gpxFile = selectedGpxFile.getGpxFile(); GPXFile gpxFile = selectedGpxFile.getGpxFile();
if (gpxFile == null) { if (gpxFile == null) {

View file

@ -1,53 +1,36 @@
package net.osmand.plus.track; package net.osmand.plus.track;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.GradientDrawable;
import android.os.Build; import android.os.Build;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes; import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.content.res.AppCompatResources; import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.core.graphics.ColorUtils;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.internal.FlowLayout;
import net.osmand.AndroidUtils; import net.osmand.AndroidUtils;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
import net.osmand.plus.GPXDatabase.GpxDataItem;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.UiUtilities; import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.MapActivity;
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.helpers.AndroidUiHelper;
import net.osmand.plus.routepreparationmenu.cards.BaseCard; import net.osmand.plus.routepreparationmenu.cards.BaseCard;
import net.osmand.plus.track.CustomColorBottomSheet.ColorPickerListener;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class TrackColoringCard extends BaseCard implements ColorPickerListener { public class TrackColoringCard extends BaseCard {
private static final int MINIMUM_CONTRAST_RATIO = 3; private static final int MINIMUM_CONTRAST_RATIO = 3;
public static final int INVALID_VALUE = -1;
private final static String SOLID_COLOR = "solid_color"; private final static String SOLID_COLOR = "solid_color";
private static final Log log = PlatformUtil.getLog(TrackColoringCard.class); private static final Log log = PlatformUtil.getLog(TrackColoringCard.class);
@ -57,7 +40,6 @@ public class TrackColoringCard extends BaseCard implements ColorPickerListener {
private TrackAppearanceItem selectedAppearanceItem; private TrackAppearanceItem selectedAppearanceItem;
private List<TrackAppearanceItem> appearanceItems; private List<TrackAppearanceItem> appearanceItems;
private List<Integer> customColors;
private Fragment target; private Fragment target;
public TrackColoringCard(MapActivity mapActivity, TrackDrawInfo trackDrawInfo, Fragment target) { public TrackColoringCard(MapActivity mapActivity, TrackDrawInfo trackDrawInfo, Fragment target) {
@ -65,7 +47,6 @@ public class TrackColoringCard extends BaseCard implements ColorPickerListener {
this.target = target; this.target = target;
this.trackDrawInfo = trackDrawInfo; this.trackDrawInfo = trackDrawInfo;
appearanceItems = getGradientAppearanceItems(); appearanceItems = getGradientAppearanceItems();
customColors = getCustomColors();
} }
@Override @Override
@ -76,8 +57,6 @@ public class TrackColoringCard extends BaseCard implements ColorPickerListener {
@Override @Override
protected void updateContent() { protected void updateContent() {
updateHeader(); updateHeader();
createColorSelector();
updateColorSelector();
// coloringAdapter = new TrackColoringAdapter(appearanceItems); // coloringAdapter = new TrackColoringAdapter(appearanceItems);
// RecyclerView groupRecyclerView = view.findViewById(R.id.recycler_view); // RecyclerView groupRecyclerView = view.findViewById(R.id.recycler_view);
@ -87,25 +66,6 @@ public class TrackColoringCard extends BaseCard implements ColorPickerListener {
AndroidUiHelper.updateVisibility(view.findViewById(R.id.top_divider), isShowDivider()); AndroidUiHelper.updateVisibility(view.findViewById(R.id.top_divider), isShowDivider());
} }
private List<Integer> getCustomColors() {
List<Integer> colors = new ArrayList<>();
List<String> colorNames = app.getSettings().CUSTOM_TRACK_COLORS.getStringsList();
if (colorNames != null) {
for (String colorHex : colorNames) {
try {
if (!Algorithms.isEmpty(colorHex)) {
int color = Algorithms.parseColor(colorHex);
colors.add(color);
}
} catch (IllegalArgumentException e) {
log.error(e);
}
}
}
return colors;
}
private List<TrackAppearanceItem> getGradientAppearanceItems() { private List<TrackAppearanceItem> getGradientAppearanceItems() {
List<TrackAppearanceItem> items = new ArrayList<>(); List<TrackAppearanceItem> items = new ArrayList<>();
items.add(new TrackAppearanceItem(SOLID_COLOR, app.getString(R.string.track_coloring_solid), R.drawable.ic_action_circle)); items.add(new TrackAppearanceItem(SOLID_COLOR, app.getString(R.string.track_coloring_solid), R.drawable.ic_action_circle));
@ -117,138 +77,6 @@ public class TrackColoringCard extends BaseCard implements ColorPickerListener {
return items; return items;
} }
private void createColorSelector() {
FlowLayout selectColor = view.findViewById(R.id.select_color);
selectColor.removeAllViews();
for (int color : customColors) {
selectColor.addView(createColorItemView(color, selectColor, true));
}
if (customColors.size() < 6) {
selectColor.addView(createAddCustomColorItemView(selectColor));
}
selectColor.addView(createDividerView(selectColor));
List<Integer> colors = new ArrayList<>();
for (AppearanceListItem appearanceListItem : GpxAppearanceAdapter.getAppearanceItems(app, GpxAppearanceAdapterType.TRACK_COLOR)) {
if (!colors.contains(appearanceListItem.getColor())) {
colors.add(appearanceListItem.getColor());
}
}
for (int color : colors) {
selectColor.addView(createColorItemView(color, selectColor, false));
}
updateColorSelector(trackDrawInfo.getColor(), selectColor);
}
private View createColorItemView(@ColorInt final int color, final FlowLayout rootView, boolean customColor) {
View colorItemView = createCircleView(rootView);
ImageView backgroundCircle = colorItemView.findViewById(R.id.background);
Drawable transparencyIcon = getTransparencyIcon(app, color);
Drawable colorIcon = app.getUIUtilities().getPaintedIcon(R.drawable.bg_point_circle, color);
Drawable layeredIcon = UiUtilities.getLayeredIcon(transparencyIcon, colorIcon);
double contrastRatio = ColorUtils.calculateContrast(color, ContextCompat.getColor(app, nightMode ? R.color.card_and_list_background_dark : R.color.card_and_list_background_light));
if (contrastRatio < MINIMUM_CONTRAST_RATIO) {
backgroundCircle.setBackgroundResource(nightMode ? R.drawable.circle_contour_bg_dark : R.drawable.circle_contour_bg_light);
}
backgroundCircle.setImageDrawable(layeredIcon);
backgroundCircle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
updateColorSelector(color, rootView);
// coloringAdapter.notifyDataSetChanged();
trackDrawInfo.setColor(color);
CardListener listener = getListener();
if (listener != null) {
listener.onCardPressed(TrackColoringCard.this);
}
}
});
if (customColor) {
backgroundCircle.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
CustomColorBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), target, color);
}
return false;
}
});
}
colorItemView.setTag(color);
return colorItemView;
}
private Drawable getTransparencyIcon(OsmandApplication app, @ColorInt int color) {
int colorWithoutAlpha = UiUtilities.removeAlpha(color);
int transparencyColor = UiUtilities.getColorWithAlpha(colorWithoutAlpha, 0.8f);
return app.getUIUtilities().getPaintedIcon(R.drawable.ic_bg_transparency, transparencyColor);
}
private View createAddCustomColorItemView(FlowLayout rootView) {
View colorItemView = createCircleView(rootView);
ImageView backgroundCircle = colorItemView.findViewById(R.id.background);
int bgColorId = nightMode ? R.color.activity_background_color_dark : R.color.activity_background_color_light;
Drawable backgroundIcon = app.getUIUtilities().getIcon(R.drawable.bg_point_circle, bgColorId);
ImageView icon = colorItemView.findViewById(R.id.icon);
icon.setVisibility(View.VISIBLE);
int activeColorResId = nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light;
icon.setImageDrawable(app.getUIUtilities().getIcon(R.drawable.ic_action_plus, activeColorResId));
backgroundCircle.setImageDrawable(backgroundIcon);
backgroundCircle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
CustomColorBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), target, null);
}
}
});
return colorItemView;
}
private View createDividerView(FlowLayout rootView) {
LayoutInflater themedInflater = UiUtilities.getInflater(view.getContext(), nightMode);
View divider = themedInflater.inflate(R.layout.simple_divider_item, rootView, false);
LinearLayout dividerContainer = new LinearLayout(view.getContext());
dividerContainer.addView(divider);
dividerContainer.setPadding(0, AndroidUtils.dpToPx(app, 1), 0, AndroidUtils.dpToPx(app, 5));
return dividerContainer;
}
private View createCircleView(ViewGroup rootView) {
LayoutInflater themedInflater = UiUtilities.getInflater(view.getContext(), nightMode);
View circleView = themedInflater.inflate(R.layout.point_editor_button, rootView, false);
ImageView outline = circleView.findViewById(R.id.outline);
int colorId = nightMode ? R.color.stroked_buttons_and_links_outline_dark : R.color.stroked_buttons_and_links_outline_light;
Drawable contourIcon = app.getUIUtilities().getIcon(R.drawable.bg_point_circle_contour, colorId);
outline.setImageDrawable(contourIcon);
return circleView;
}
private void updateColorSelector(int color, View rootView) {
View oldColor = rootView.findViewWithTag(trackDrawInfo.getColor());
if (oldColor != null) {
oldColor.findViewById(R.id.outline).setVisibility(View.INVISIBLE);
ImageView icon = oldColor.findViewById(R.id.icon);
icon.setImageDrawable(UiUtilities.tintDrawable(icon.getDrawable(), R.color.icon_color_default_light));
}
View newColor = rootView.findViewWithTag(color);
if (newColor != null) {
newColor.findViewById(R.id.outline).setVisibility(View.VISIBLE);
}
mapActivity.refreshMap();
}
private TrackAppearanceItem getSelectedAppearanceItem() { private TrackAppearanceItem getSelectedAppearanceItem() {
if (selectedAppearanceItem == null) { if (selectedAppearanceItem == null) {
GradientScaleType scaleType = trackDrawInfo.getGradientScaleType(); GradientScaleType scaleType = trackDrawInfo.getGradientScaleType();
@ -293,49 +121,6 @@ public class TrackColoringCard extends BaseCard implements ColorPickerListener {
updateColorSelector(); updateColorSelector();
} }
@Override
public void onColorSelected(Integer prevColor, int newColor) {
if (prevColor != null) {
int index = customColors.indexOf(prevColor);
if (index != INVALID_VALUE) {
customColors.set(index, newColor);
saveCustomColorsToTracks(prevColor, newColor);
}
if (trackDrawInfo.getColor() == prevColor) {
trackDrawInfo.setColor(newColor);
}
} else if (customColors.size() < 6) {
customColors.add(newColor);
trackDrawInfo.setColor(newColor);
}
saveCustomColors();
updateContent();
}
private void saveCustomColorsToTracks(int prevColor, int newColor) {
List<GpxDataItem> gpxDataItems = app.getGpxDbHelper().getItems();
for (GpxDataItem dataItem : gpxDataItems) {
if (prevColor == dataItem.getColor()) {
app.getGpxDbHelper().updateColor(dataItem, newColor);
}
}
List<SelectedGpxFile> files = app.getSelectedGpxHelper().getSelectedGPXFiles();
for (SelectedGpxFile selectedGpxFile : files) {
if (prevColor == selectedGpxFile.getGpxFile().getColor(0)) {
selectedGpxFile.getGpxFile().setColor(newColor);
}
}
}
private void saveCustomColors() {
List<String> colorNames = new ArrayList<>();
for (Integer color : customColors) {
String colorHex = Algorithms.colorToString(color);
colorNames.add(colorHex);
}
app.getSettings().CUSTOM_TRACK_COLORS.setStringsList(colorNames);
}
private class TrackColoringAdapter extends RecyclerView.Adapter<TrackAppearanceViewHolder> { private class TrackColoringAdapter extends RecyclerView.Adapter<TrackAppearanceViewHolder> {
private List<TrackAppearanceItem> items; private List<TrackAppearanceItem> items;