From bd3e864b59f7944f9702af7e3060c3fdc7c30039 Mon Sep 17 00:00:00 2001 From: chumv Date: Wed, 11 Dec 2024 18:06:13 +0200 Subject: [PATCH 1/2] Add DefaultButtonsAppearanceFragment for #18357 --- OsmAnd/res/layout/card_multi_state.xml | 1 + .../layout/map_button_appearance_fragment.xml | 1 - OsmAnd/res/layout/map_button_icons_card.xml | 1 + OsmAnd/res/layout/map_button_opacity_card.xml | 26 +- OsmAnd/res/layout/min_max_container.xml | 29 ++ OsmAnd/res/layout/slider_with_buttons.xml | 82 +++--- OsmAnd/res/values/strings.xml | 3 + .../quickaction/ButtonAppearanceParams.kt | 2 + .../plus/quickaction/ButtonSizeCard.java | 59 +++- .../plus/quickaction/CornerRadiusCard.java | 60 +++- .../MapButtonAppearanceFragment.java | 6 +- .../plus/quickaction/MapButtonsHelper.java | 28 +- .../plus/quickaction/OpacitySliderCard.java | 93 +++++- .../plus/quickaction/SliderButtonsCard.java | 60 +++- .../routepreparationmenu/cards/BaseCard.java | 9 +- .../DefaultButtonsAppearanceFragment.java | 267 ++++++++++++++++++ .../buttons/DefaultMapButtonsFragment.java | 20 +- .../configure/buttons/MapButtonCard.java | 8 +- .../configure/buttons/MapButtonState.java | 12 +- 19 files changed, 656 insertions(+), 111 deletions(-) create mode 100644 OsmAnd/res/layout/min_max_container.xml create mode 100644 OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultButtonsAppearanceFragment.java diff --git a/OsmAnd/res/layout/card_multi_state.xml b/OsmAnd/res/layout/card_multi_state.xml index 63002473c19..4f2fefcabc7 100644 --- a/OsmAnd/res/layout/card_multi_state.xml +++ b/OsmAnd/res/layout/card_multi_state.xml @@ -46,6 +46,7 @@ tools:text="Solid" /> diff --git a/OsmAnd/res/layout/map_button_icons_card.xml b/OsmAnd/res/layout/map_button_icons_card.xml index 0fe9bfaddc0..11acf66c1f0 100644 --- a/OsmAnd/res/layout/map_button_icons_card.xml +++ b/OsmAnd/res/layout/map_button_icons_card.xml @@ -3,6 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" + android:background="?attr/card_and_list_background_basic" android:orientation="vertical"> - - - - - - - + \ No newline at end of file diff --git a/OsmAnd/res/layout/min_max_container.xml b/OsmAnd/res/layout/min_max_container.xml new file mode 100644 index 00000000000..391d8d17064 --- /dev/null +++ b/OsmAnd/res/layout/min_max_container.xml @@ -0,0 +1,29 @@ + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/layout/slider_with_buttons.xml b/OsmAnd/res/layout/slider_with_buttons.xml index 5775deb0ea9..f05803e95a7 100644 --- a/OsmAnd/res/layout/slider_with_buttons.xml +++ b/OsmAnd/res/layout/slider_with_buttons.xml @@ -8,61 +8,61 @@ android:orientation="vertical" android:paddingBottom="@dimen/content_padding_half"> + + + android:orientation="vertical"> - + android:orientation="horizontal" + android:paddingHorizontal="@dimen/content_padding_round_medium"> - + + + + + + + - - + android:orientation="vertical"> - + - + diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index e75b808b505..21f62a232f8 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -11,6 +11,9 @@ Thx - Hardy --> + Each button would keep its own size. + Each button would keep its own corner radius. + Each button would keep its own background opacity. Selected profile \"%s\" Interpolation Location interpolation percentage diff --git a/OsmAnd/src/net/osmand/plus/quickaction/ButtonAppearanceParams.kt b/OsmAnd/src/net/osmand/plus/quickaction/ButtonAppearanceParams.kt index 49cf34e0270..e1d0d52dffa 100644 --- a/OsmAnd/src/net/osmand/plus/quickaction/ButtonAppearanceParams.kt +++ b/OsmAnd/src/net/osmand/plus/quickaction/ButtonAppearanceParams.kt @@ -44,5 +44,7 @@ data class ButtonAppearanceParams( internal const val ROUND_RADIUS_DP = 36 internal const val RECTANGULAR_RADIUS_DP = 2 + + internal const val ORIGINAL_VALUE = -1 } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/quickaction/ButtonSizeCard.java b/OsmAnd/src/net/osmand/plus/quickaction/ButtonSizeCard.java index 76af69a2d09..a26ed2e6caa 100644 --- a/OsmAnd/src/net/osmand/plus/quickaction/ButtonSizeCard.java +++ b/OsmAnd/src/net/osmand/plus/quickaction/ButtonSizeCard.java @@ -1,6 +1,7 @@ package net.osmand.plus.quickaction; import static com.google.android.material.slider.LabelFormatter.LABEL_FLOATING; +import static net.osmand.plus.quickaction.ButtonAppearanceParams.ORIGINAL_VALUE; import android.view.View; @@ -8,9 +9,15 @@ import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.card.base.multistate.CardState; import net.osmand.plus.utils.ColorUtilities; import net.osmand.plus.utils.UiUtilities; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + public class ButtonSizeCard extends SliderButtonsCard { public static final int MIN_BUTTON_SIZE = 40; @@ -19,15 +26,22 @@ public class ButtonSizeCard extends SliderButtonsCard { private final ButtonAppearanceParams appearanceParams; - public ButtonSizeCard(@NonNull MapActivity activity, @NonNull ButtonAppearanceParams appearanceParams) { - super(activity); + public ButtonSizeCard(@NonNull MapActivity activity, + @NonNull ButtonAppearanceParams appearanceParams, boolean showOriginal) { + super(activity, showOriginal); this.appearanceParams = appearanceParams; } protected void setupHeader(@NonNull View view) { super.setupHeader(view); title.setText(R.string.shared_string_size); - description.setText(getFormattedValue(appearanceParams.getSize())); + valueTv.setText(getFormattedValue(appearanceParams.getSize())); + } + + @Override + protected void setupDescription(@NonNull @NotNull View view) { + super.setupDescription(view); + description.setText(R.string.default_buttons_corners_original_description); } protected void setupSlider(@NonNull View view) { @@ -37,22 +51,57 @@ protected void setupSlider(@NonNull View view) { slider.setValueTo(MAX_BUTTON_SIZE); slider.setValueFrom(MIN_BUTTON_SIZE); slider.setStepSize(BUTTON_SIZE_STEP); - slider.setValue(appearanceParams.getSize()); slider.setLabelBehavior(LABEL_FLOATING); slider.setLabelFormatter(ButtonSizeCard.this::getFormattedValue); + + if (!isOriginalValue()) { + slider.setValue(appearanceParams.getSize()); + } } protected void onValueSelected(float value) { super.onValueSelected(value); appearanceParams.setSize((int) value); - description.setText(getFormattedValue(appearanceParams.getSize())); + valueTv.setText(getFormattedValue(appearanceParams.getSize())); notifyCardPressed(); } + @Override + protected boolean isOriginalValue() { + return appearanceParams.getSize() == ORIGINAL_VALUE; + } + @NonNull protected String getFormattedValue(float value) { + if (value == ORIGINAL_VALUE) { + return getString(R.string.shared_string_original); + } return getString(R.string.ltr_or_rtl_combine_via_space, (int) value, getString(R.string.shared_string_dp)); } + + @NonNull + @Override + protected List getCardStates() { + List list = new ArrayList<>(); + + list.add(new CardState(R.string.shared_string_original).setTag(ORIGINAL_VALUE)); + + for (int i = MIN_BUTTON_SIZE; i <= MAX_BUTTON_SIZE; i += BUTTON_SIZE_STEP) { + list.add(new CardState(getFormattedValue(i)) + .setShowTopDivider(i == MIN_BUTTON_SIZE) + .setTag(i)); + } + return list; + } + + @Override + protected void setSelectedState(@NonNull CardState cardState) { + if (cardState.getTag() instanceof Integer value) { + appearanceParams.setSize(value); + } + updateContent(); + notifyCardPressed(); + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/quickaction/CornerRadiusCard.java b/OsmAnd/src/net/osmand/plus/quickaction/CornerRadiusCard.java index c5285f80811..ad9f4c94b7c 100644 --- a/OsmAnd/src/net/osmand/plus/quickaction/CornerRadiusCard.java +++ b/OsmAnd/src/net/osmand/plus/quickaction/CornerRadiusCard.java @@ -2,6 +2,7 @@ import static com.google.android.material.slider.LabelFormatter.LABEL_FLOATING; +import static net.osmand.plus.quickaction.ButtonAppearanceParams.ORIGINAL_VALUE; import android.view.View; @@ -9,24 +10,37 @@ import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.card.base.multistate.CardState; import net.osmand.plus.utils.ColorUtilities; import net.osmand.plus.utils.UiUtilities; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + public class CornerRadiusCard extends SliderButtonsCard { public static final int[] CORNER_RADIUS_VALUES = {3, 6, 9, 12, 36}; private final ButtonAppearanceParams appearanceParams; - public CornerRadiusCard(@NonNull MapActivity activity, @NonNull ButtonAppearanceParams appearanceParams) { - super(activity); + public CornerRadiusCard(@NonNull MapActivity activity, + @NonNull ButtonAppearanceParams appearanceParams, boolean showOriginal) { + super(activity, showOriginal); this.appearanceParams = appearanceParams; } protected void setupHeader(@NonNull View view) { super.setupHeader(view); title.setText(R.string.corner_radius); - description.setText(getFormattedValue(appearanceParams.getCornerRadius())); + valueTv.setText(getFormattedValue(appearanceParams.getCornerRadius())); + } + + @Override + protected void setupDescription(@NonNull @NotNull View view) { + super.setupDescription(view); + description.setText(R.string.default_buttons_corners_original_description); } protected void setupSlider(@NonNull View view) { @@ -36,9 +50,12 @@ protected void setupSlider(@NonNull View view) { slider.setValueTo(CORNER_RADIUS_VALUES.length - 1); slider.setValueFrom(0); slider.setStepSize(1); - slider.setValue(getSelectedIndex()); slider.setLabelBehavior(LABEL_FLOATING); slider.setLabelFormatter(value -> CornerRadiusCard.this.getFormattedValue(CORNER_RADIUS_VALUES[(int) value])); + + if (!isOriginalValue()) { + slider.setValue(getSelectedIndex()); + } } protected void onValueSelected(float value) { @@ -46,11 +63,16 @@ protected void onValueSelected(float value) { int index = (int) value; appearanceParams.setCornerRadius(CORNER_RADIUS_VALUES[index]); - description.setText(getFormattedValue(appearanceParams.getCornerRadius())); + valueTv.setText(getFormattedValue(appearanceParams.getCornerRadius())); notifyCardPressed(); } + @Override + protected boolean isOriginalValue() { + return appearanceParams.getCornerRadius() == ORIGINAL_VALUE; + } + private int getSelectedIndex() { int value = appearanceParams.getCornerRadius(); for (int i = 0; i < CORNER_RADIUS_VALUES.length; i++) { @@ -63,6 +85,34 @@ private int getSelectedIndex() { @NonNull protected String getFormattedValue(float value) { + if (value == ORIGINAL_VALUE) { + return getString(R.string.shared_string_original); + } return getString(R.string.ltr_or_rtl_combine_via_space, (int) value, getString(R.string.shared_string_dp)); } + + @NonNull + @Override + protected List getCardStates() { + List list = new ArrayList<>(); + + list.add(new CardState(R.string.shared_string_original).setTag(ORIGINAL_VALUE)); + + for (int i = 0; i < CORNER_RADIUS_VALUES.length; i++) { + int value = CORNER_RADIUS_VALUES[i]; + list.add(new CardState(getFormattedValue(value)) + .setShowTopDivider(i == 0) + .setTag(value)); + } + return list; + } + + @Override + protected void setSelectedState(@NonNull CardState cardState) { + if (cardState.getTag() instanceof Integer value) { + appearanceParams.setCornerRadius(value); + } + updateContent(); + notifyCardPressed(); + } } diff --git a/OsmAnd/src/net/osmand/plus/quickaction/MapButtonAppearanceFragment.java b/OsmAnd/src/net/osmand/plus/quickaction/MapButtonAppearanceFragment.java index b4a5a7604ce..6a163b1001d 100644 --- a/OsmAnd/src/net/osmand/plus/quickaction/MapButtonAppearanceFragment.java +++ b/OsmAnd/src/net/osmand/plus/quickaction/MapButtonAppearanceFragment.java @@ -133,11 +133,11 @@ private void setupCards(@NonNull View view) { mapButtonCard = new MapButtonCard(activity, buttonState, appearanceParams); addCard(container, mapButtonCard); addCard(container, new ButtonIconsCard(activity, iconController)); - addCard(container, new CornerRadiusCard(activity, appearanceParams)); + addCard(container, new CornerRadiusCard(activity, appearanceParams, false)); container.addView(themedInflater.inflate(R.layout.simple_divider_item, container, false)); - addCard(container, new ButtonSizeCard(activity, appearanceParams)); + addCard(container, new ButtonSizeCard(activity, appearanceParams, false)); container.addView(themedInflater.inflate(R.layout.simple_divider_item, container, false)); - addCard(container, new OpacitySliderCard(activity, appearanceParams)); + addCard(container, new OpacitySliderCard(activity, appearanceParams, false)); } private void addCard(@NonNull ViewGroup container, @NonNull BaseCard card) { diff --git a/OsmAnd/src/net/osmand/plus/quickaction/MapButtonsHelper.java b/OsmAnd/src/net/osmand/plus/quickaction/MapButtonsHelper.java index b95bf4a040f..3d3e5aaccd2 100644 --- a/OsmAnd/src/net/osmand/plus/quickaction/MapButtonsHelper.java +++ b/OsmAnd/src/net/osmand/plus/quickaction/MapButtonsHelper.java @@ -1,5 +1,6 @@ package net.osmand.plus.quickaction; +import static net.osmand.plus.quickaction.ButtonAppearanceParams.ORIGINAL_VALUE; import static net.osmand.plus.quickaction.QuickActionType.CREATE_CATEGORY; import static net.osmand.plus.views.mapwidgets.configure.buttons.QuickActionButtonState.DEFAULT_BUTTON_ID; @@ -21,6 +22,7 @@ import net.osmand.plus.quickaction.actions.special.OpenWunderLINQDatagridAction; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.OsmandSettings; +import net.osmand.plus.settings.backend.preferences.CommonPreference; import net.osmand.plus.views.mapwidgets.configure.buttons.*; import net.osmand.util.Algorithms; @@ -99,9 +101,14 @@ public static QuickActionType getCategoryActionTypeFromId(int typeId) { private final OsmandApplication app; private final OsmandSettings settings; + private final Collator collator = OsmAndCollator.primaryCollator(); private final QuickActionSerializer serializer = new QuickActionSerializer(); private final Gson gson = new GsonBuilder().registerTypeAdapter(QuickAction.class, serializer).create(); + private final CommonPreference defaultSizePref; + private final CommonPreference defaultOpacityPref; + private final CommonPreference defaultCornerRadiusPref; + private Map3DButtonState map3DButtonState; private MyLocationButtonState myLocationButtonState; private NavigationMenuButtonState navigationMenuButtonState; @@ -117,11 +124,15 @@ public static QuickActionType getCategoryActionTypeFromId(int typeId) { private Map quickActionTypesInt = new TreeMap<>(); private Map quickActionTypesStr = new TreeMap<>(); private Set updatesListeners = new HashSet<>(); - private final Collator collator = OsmAndCollator.primaryCollator(); + public MapButtonsHelper(@NonNull OsmandApplication app) { this.app = app; this.settings = app.getSettings(); + this.defaultSizePref = settings.registerIntPreference("default_map_button_size", ORIGINAL_VALUE).makeProfile().cache(); + this.defaultOpacityPref = settings.registerFloatPreference("default_map_button_opacity", ORIGINAL_VALUE).makeProfile().cache(); + this.defaultCornerRadiusPref = settings.registerIntPreference("default_map_button_corner_radius", ORIGINAL_VALUE).makeProfile().cache(); + updateActionTypes(); initDefaultButtons(); } @@ -597,6 +608,21 @@ public QuickActionButtonState getButtonStateByAction(@NonNull QuickAction action return null; } + @NonNull + public CommonPreference getDefaultSizePref() { + return defaultSizePref; + } + + @NonNull + public CommonPreference getDefaultOpacityPref() { + return defaultOpacityPref; + } + + @NonNull + public CommonPreference getDefaultCornerRadiusPref() { + return defaultCornerRadiusPref; + } + @NonNull public String createNewButtonStateId() { return DEFAULT_BUTTON_ID + "_" + System.currentTimeMillis(); diff --git a/OsmAnd/src/net/osmand/plus/quickaction/OpacitySliderCard.java b/OsmAnd/src/net/osmand/plus/quickaction/OpacitySliderCard.java index df3e2534141..fa6e86eb08d 100644 --- a/OsmAnd/src/net/osmand/plus/quickaction/OpacitySliderCard.java +++ b/OsmAnd/src/net/osmand/plus/quickaction/OpacitySliderCard.java @@ -1,8 +1,12 @@ package net.osmand.plus.quickaction; import static com.google.android.material.slider.LabelFormatter.LABEL_FLOATING; +import static net.osmand.plus.quickaction.ButtonAppearanceParams.ORIGINAL_VALUE; +import static net.osmand.plus.quickaction.ButtonAppearanceParams.TRANSPARENT_ALPHA; +import android.content.Context; import android.view.View; +import android.view.ViewGroup; import android.widget.TextView; import androidx.annotation.NonNull; @@ -10,9 +14,16 @@ import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.base.ProgressHelper; +import net.osmand.plus.card.base.multistate.CardState; +import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.utils.ColorUtilities; import net.osmand.plus.utils.UiUtilities; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + public class OpacitySliderCard extends SliderButtonsCard { public static final int MIN_OPACITY = 0; @@ -20,25 +31,25 @@ public class OpacitySliderCard extends SliderButtonsCard { private final ButtonAppearanceParams appearanceParams; - @Override - public int getCardLayoutId() { - return R.layout.map_button_opacity_card; - } + private float selectedOpacity; - public OpacitySliderCard(@NonNull MapActivity activity, @NonNull ButtonAppearanceParams appearanceParams) { - super(activity); + public OpacitySliderCard(@NonNull MapActivity activity, + @NonNull ButtonAppearanceParams appearanceParams, boolean showOriginal) { + super(activity, showOriginal); + this.selectedOpacity = appearanceParams.getOpacity(); this.appearanceParams = appearanceParams; } + @NonNull @Override - protected void updateContent() { - setupHeader(view); - setupSlider(view); + public View inflate(@NonNull Context ctx) { + View view = super.inflate(ctx); + addMinMaxRow(view.findViewById(R.id.slider_container)); + return view; } - @Override - protected void setupHeader(@NonNull View view) { - super.setupHeader(view); + private void addMinMaxRow(@NonNull ViewGroup container) { + View view = themedInflater.inflate(R.layout.min_max_container, container, false); TextView valueMin = view.findViewById(R.id.value_min); TextView valueMax = view.findViewById(R.id.value_max); @@ -46,9 +57,23 @@ protected void setupHeader(@NonNull View view) { valueMin.setText(getFormattedValue(MIN_OPACITY)); valueMax.setText(getFormattedValue(MAX_OPACITY)); + container.addView(view); + } + + @Override + protected void setupHeader(@NonNull View view) { + super.setupHeader(view); + + title.setText(R.string.background_opacity); updateDescription(); } + @Override + protected void setupDescription(@NonNull @NotNull View view) { + super.setupDescription(view); + description.setText(R.string.default_buttons_corners_original_description); + } + @Override protected void setupSlider(@NonNull View view) { super.setupSlider(view); @@ -56,23 +81,63 @@ protected void setupSlider(@NonNull View view) { slider.setValueTo(MAX_OPACITY); slider.setValueFrom(MIN_OPACITY); - slider.setValue(appearanceParams.getOpacity()); slider.setLabelBehavior(LABEL_FLOATING); slider.setLabelFormatter(OpacitySliderCard.this::getFormattedValue); + + if (!isOriginalValue()) { + slider.setValue(appearanceParams.getOpacity()); + } + } + + @Override + protected void setupButtons(@NonNull @NotNull View view) { + super.setupButtons(view); + + AndroidUiHelper.updateVisibility(increaseButton, false); + AndroidUiHelper.updateVisibility(decreaseButton, false); } protected void onValueSelected(float value) { + selectedOpacity = value; appearanceParams.setOpacity(value); updateDescription(); notifyCardPressed(); } + @Override + protected boolean isOriginalValue() { + return appearanceParams.getOpacity() == ORIGINAL_VALUE; + } + + @NonNull + @Override + protected List getCardStates() { + List list = new ArrayList<>(); + float value = selectedOpacity != ORIGINAL_VALUE ? selectedOpacity : TRANSPARENT_ALPHA; + list.add(new CardState(R.string.shared_string_original).setTag(ORIGINAL_VALUE)); + list.add(new CardState(R.string.shared_string_custom).setTag(value).setShowTopDivider(true)); + + return list; + } + private void updateDescription() { - description.setText(getFormattedValue(appearanceParams.getOpacity())); + valueTv.setText(getFormattedValue(appearanceParams.getOpacity())); } @NonNull protected String getFormattedValue(float value) { + if (value == ORIGINAL_VALUE) { + return getString(R.string.shared_string_original); + } return ProgressHelper.normalizeProgressPercent((int) (value * 100)) + "%"; } + + @Override + protected void setSelectedState(@NonNull CardState cardState) { + if (cardState.getTag() instanceof Number value) { + appearanceParams.setOpacity(value.floatValue()); + } + updateContent(); + notifyCardPressed(); + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/quickaction/SliderButtonsCard.java b/OsmAnd/src/net/osmand/plus/quickaction/SliderButtonsCard.java index 965fef5b406..6d896a875f5 100644 --- a/OsmAnd/src/net/osmand/plus/quickaction/SliderButtonsCard.java +++ b/OsmAnd/src/net/osmand/plus/quickaction/SliderButtonsCard.java @@ -12,37 +12,63 @@ import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.card.base.multistate.CardState; +import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.routepreparationmenu.cards.MapBaseCard; import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.ColorUtilities; +import net.osmand.plus.widgets.popup.PopUpMenu; +import net.osmand.plus.widgets.popup.PopUpMenuDisplayData; +import net.osmand.plus.widgets.popup.PopUpMenuItem; + +import java.util.ArrayList; +import java.util.List; public abstract class SliderButtonsCard extends MapBaseCard { protected Slider slider; protected TextView title; + protected TextView valueTv; protected TextView description; protected ImageButton increaseButton; protected ImageButton decreaseButton; + protected boolean showOriginal; + @Override public int getCardLayoutId() { return R.layout.slider_with_buttons; } - public SliderButtonsCard(@NonNull MapActivity activity) { + public SliderButtonsCard(@NonNull MapActivity activity, boolean showOriginal) { super(activity, false); + this.showOriginal = showOriginal; } @Override protected void updateContent() { setupHeader(view); setupSlider(view); + setupDescription(view); setupButtons(view); } protected void setupHeader(@NonNull View view) { - title = view.findViewById(R.id.title); - description = view.findViewById(R.id.description); + View container = view.findViewById(R.id.header_container); + title = container.findViewById(R.id.card_title); + valueTv = container.findViewById(R.id.title); + + View selector = view.findViewById(R.id.card_selector); + if (showOriginal) { + selector.setOnClickListener(v -> showMenu(selector)); + } + AndroidUiHelper.updateVisibility(selector.findViewById(R.id.drop_down_icon), showOriginal); + } + + protected void setupDescription(@NonNull View view) { + View container = view.findViewById(R.id.description_container); + description = container.findViewById(R.id.summary); + AndroidUiHelper.updateVisibility(container, showOriginal && isOriginalValue()); } protected void setupSlider(@NonNull View view) { @@ -52,6 +78,7 @@ protected void setupSlider(@NonNull View view) { onValueSelected(value); } }); + AndroidUiHelper.updateVisibility(view.findViewById(R.id.slider_container), !showOriginal || !isOriginalValue()); } protected void setupButtons(@NonNull View view) { @@ -80,9 +107,36 @@ protected void onValueSelected(float value) { decreaseButton.setEnabled(value > slider.getValueFrom()); } + public void showMenu(@NonNull View view) { + List items = new ArrayList<>(); + for (CardState state : getCardStates()) { + items.add(new PopUpMenuItem.Builder(app) + .setTitle(state.toHumanString(app)) + .showTopDivider(state.isShowTopDivider()) + .setTitleColor(ColorUtilities.getPrimaryTextColor(app, nightMode)) + .setTag(state) + .create() + ); + } + PopUpMenuDisplayData data = new PopUpMenuDisplayData(); + data.anchorView = view; + data.menuItems = items; + data.nightMode = nightMode; + data.onItemClickListener = item -> setSelectedState((CardState) item.getTag()); + PopUpMenu.show(data); + } + + + protected abstract boolean isOriginalValue(); + @NonNull protected abstract String getFormattedValue(float value); + @NonNull + protected abstract List getCardStates(); + + protected abstract void setSelectedState(@NonNull CardState cardState); + @NonNull protected Drawable getPersistentPrefIcon(@DrawableRes int iconId) { Drawable enabled = getColoredIcon(iconId, ColorUtilities.getActiveColorId(nightMode)); diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/BaseCard.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/BaseCard.java index 1e51d77c74c..bf94ca070cf 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/BaseCard.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/BaseCard.java @@ -128,12 +128,17 @@ public View build() { @NonNull public View build(@NonNull Context ctx) { - themedInflater = UiUtilities.getInflater(ctx, nightMode); - view = themedInflater.inflate(getCardLayoutId(), null); + view = inflate(ctx); update(); return view; } + @NonNull + public View inflate(@NonNull Context ctx) { + themedInflater = UiUtilities.getInflater(ctx, nightMode); + return themedInflater.inflate(getCardLayoutId(), null); + } + public OsmandApplication getMyApplication() { return app; } diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultButtonsAppearanceFragment.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultButtonsAppearanceFragment.java new file mode 100644 index 00000000000..f68a4320a5b --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultButtonsAppearanceFragment.java @@ -0,0 +1,267 @@ +package net.osmand.plus.views.mapwidgets.configure.buttons; + +import android.graphics.Typeface; +import android.os.Bundle; +import android.text.SpannableString; +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.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; +import androidx.core.view.ViewCompat; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; + +import com.google.android.material.snackbar.Snackbar; + +import net.osmand.plus.R; +import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.base.BaseOsmAndFragment; +import net.osmand.plus.helpers.AndroidUiHelper; +import net.osmand.plus.quickaction.ButtonAppearanceParams; +import net.osmand.plus.quickaction.ButtonSizeCard; +import net.osmand.plus.quickaction.CornerRadiusCard; +import net.osmand.plus.quickaction.MapButtonsHelper; +import net.osmand.plus.quickaction.OpacitySliderCard; +import net.osmand.plus.routepreparationmenu.cards.BaseCard; +import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener; +import net.osmand.plus.settings.backend.preferences.CommonPreference; +import net.osmand.plus.utils.AndroidUtils; +import net.osmand.plus.utils.ColorUtilities; +import net.osmand.plus.utils.UiUtilities; +import net.osmand.plus.widgets.dialogbutton.DialogButton; +import net.osmand.util.Algorithms; + +import java.util.ArrayList; +import java.util.List; + +public class DefaultButtonsAppearanceFragment extends BaseOsmAndFragment implements CardListener { + + public static final String TAG = DefaultButtonsAppearanceFragment.class.getSimpleName(); + + private CommonPreference defaultSizePref; + private CommonPreference defaultOpacityPref; + private CommonPreference defaultCornerRadiusPref; + + private ButtonAppearanceParams appearanceParams; + private ButtonAppearanceParams originalAppearanceParams; + + private List cards; + private DialogButton applyButton; + + public boolean getContentStatusBarNightMode() { + return nightMode; + } + + @Override + public int getStatusBarColorId() { + AndroidUiHelper.setStatusBarContentColor(getView(), nightMode); + return ColorUtilities.getListBgColorId(nightMode); + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + MapButtonsHelper helper = app.getMapButtonsHelper(); + defaultSizePref = helper.getDefaultSizePref(); + defaultOpacityPref = helper.getDefaultOpacityPref(); + defaultCornerRadiusPref = helper.getDefaultCornerRadiusPref(); + + appearanceParams = createAppearanceParams(); + originalAppearanceParams = createAppearanceParams(); + + if (savedInstanceState != null) { + appearanceParams.readBundle(savedInstanceState); + } + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + updateNightMode(); + View view = themedInflater.inflate(R.layout.map_button_appearance_fragment, container, false); + AndroidUtils.addStatusBarPadding21v(requireMyActivity(), view); + + setupToolbar(view); + setupCards(view); + setupApplyButton(view); + + updateContent(); + + return view; + } + + private void setupToolbar(@NonNull View view) { + Toolbar toolbar = view.findViewById(R.id.toolbar); + ViewCompat.setElevation(view.findViewById(R.id.appbar), 5.0f); + toolbar.setBackgroundColor(ColorUtilities.getAppBarSecondaryColor(view.getContext(), nightMode)); + + TextView title = toolbar.findViewById(R.id.toolbar_title); + title.setText(R.string.default_appearance); + title.setTextColor(ColorUtilities.getPrimaryTextColor(view.getContext(), nightMode)); + + ImageView closeButton = toolbar.findViewById(R.id.close_button); + closeButton.setImageDrawable(getContentIcon(R.drawable.ic_action_close)); + closeButton.setOnClickListener(v -> { + FragmentActivity activity = getActivity(); + if (activity != null) { + activity.onBackPressed(); + } + }); + ImageView resetButton = toolbar.findViewById(R.id.action_button); + resetButton.setOnClickListener(v -> resetAppearance()); + resetButton.setImageDrawable(getContentIcon(R.drawable.ic_action_reset)); + resetButton.setContentDescription(getString(R.string.shared_string_reset)); + AndroidUiHelper.updateVisibility(resetButton, true); + } + + private void setupCards(@NonNull View view) { + cards = new ArrayList<>(); + + ViewGroup container = view.findViewById(R.id.cards_container); + container.removeAllViews(); + + MapActivity activity = requireMapActivity(); + addCard(container, new CornerRadiusCard(activity, appearanceParams, true)); + container.addView(themedInflater.inflate(R.layout.list_item_divider, container, false)); + addCard(container, new ButtonSizeCard(activity, appearanceParams, true)); + container.addView(themedInflater.inflate(R.layout.list_item_divider, container, false)); + addCard(container, new OpacitySliderCard(activity, appearanceParams, true)); + } + + private void addCard(@NonNull ViewGroup container, @NonNull BaseCard card) { + cards.add(card); + card.setListener(this); + container.addView(card.build()); + } + + private void setupApplyButton(@NonNull View view) { + applyButton = view.findViewById(R.id.apply_button); + applyButton.setOnClickListener(v -> { + saveChanges(false); + showAllModesSnackbar(); + + FragmentActivity activity = getActivity(); + if (activity != null) { + activity.onBackPressed(); + } + }); + } + + private void showAllModesSnackbar() { + View containerView = getView(); + if (containerView != null) { + String name = settings.getApplicationMode().toHumanString(); + String text = app.getString(R.string.changes_applied_to_profile, name); + SpannableString message = UiUtilities.createSpannableString(text, Typeface.BOLD, name); + Snackbar snackbar = Snackbar.make(containerView, message, Snackbar.LENGTH_LONG) + .setAction(R.string.apply_to_all_profiles, view -> saveChanges(true)); + UiUtilities.setupSnackbarVerticalLayout(snackbar); + UiUtilities.setupSnackbar(snackbar, nightMode); + snackbar.show(); + } + } + + private void saveChanges(boolean applyToAllProfiles) { + if (applyToAllProfiles) { + settings.setPreferenceForAllModes(defaultSizePref.getId(), appearanceParams.getSize()); + settings.setPreferenceForAllModes(defaultOpacityPref.getId(), appearanceParams.getOpacity()); + settings.setPreferenceForAllModes(defaultCornerRadiusPref.getId(), appearanceParams.getCornerRadius()); + } else { + defaultSizePref.set(appearanceParams.getSize()); + defaultOpacityPref.set(appearanceParams.getOpacity()); + defaultCornerRadiusPref.set(appearanceParams.getCornerRadius()); + } + } + + private void updateContent() { + updateCards(); + updateButtons(); + } + + private void updateCards() { + for (BaseCard card : cards) { + card.update(); + } + } + + private void updateButtons() { + applyButton.setEnabled(!Algorithms.objectEquals(originalAppearanceParams, appearanceParams)); + } + + private void resetAppearance() { + appearanceParams.setSize(defaultSizePref.getDefaultValue()); + appearanceParams.setOpacity(defaultOpacityPref.getDefaultValue()); + appearanceParams.setCornerRadius(defaultCornerRadiusPref.getDefaultValue()); + updateContent(); + } + + @NonNull + private ButtonAppearanceParams createAppearanceParams() { + return new ButtonAppearanceParams(null, defaultSizePref.get(), + defaultOpacityPref.get(), defaultCornerRadiusPref.get()); + } + + @Override + public void onCardPressed(@NonNull BaseCard card) { + updateButtons(); + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + appearanceParams.saveToBundle(outState); + originalAppearanceParams.saveToBundle(outState); + } + + @Override + public void onResume() { + super.onResume(); + + MapActivity activity = getMapActivity(); + if (activity != null) { + activity.disableDrawer(); + } + } + + @Override + public void onPause() { + super.onPause(); + + MapActivity activity = getMapActivity(); + if (activity != null) { + activity.enableDrawer(); + } + } + + @Nullable + public MapActivity getMapActivity() { + FragmentActivity activity = getActivity(); + return activity instanceof MapActivity ? ((MapActivity) activity) : null; + } + + @NonNull + public MapActivity requireMapActivity() { + FragmentActivity activity = getActivity(); + if (!(activity instanceof MapActivity)) { + throw new IllegalStateException("Fragment " + this + " not attached to an activity."); + } + return (MapActivity) activity; + } + + public static void showInstance(@NonNull FragmentManager manager) { + if (AndroidUtils.isFragmentCanBeAdded(manager, TAG)) { + DefaultButtonsAppearanceFragment fragment = new DefaultButtonsAppearanceFragment(); + manager.beginTransaction() + .replace(R.id.fragmentContainer, fragment, TAG) + .addToBackStack(TAG) + .commitAllowingStateLoss(); + } + } +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultMapButtonsFragment.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultMapButtonsFragment.java index 66a8b29b750..5332e64b069 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultMapButtonsFragment.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultMapButtonsFragment.java @@ -1,5 +1,6 @@ package net.osmand.plus.views.mapwidgets.configure.buttons; +import android.content.Context; import android.os.Bundle; import android.view.View; import android.widget.ImageView; @@ -69,8 +70,22 @@ public void onItemClick(@NonNull MapButtonState buttonState) { protected void showOptionsMenu(@NonNull View view) { List items = new ArrayList<>(); - items.add(new PopUpMenuItem.Builder(view.getContext()) + Context context = view.getContext(); + + items.add(new PopUpMenuItem.Builder(context) + .setTitleId(R.string.shared_string_appearance) + .setIcon(getContentIcon(R.drawable.ic_action_appearance)) + .setOnClickListener(v -> { + FragmentActivity activity = getActivity(); + if (activity != null) { + FragmentManager manager = activity.getSupportFragmentManager(); + DefaultButtonsAppearanceFragment.showInstance(manager); + } + }).create()); + + items.add(new PopUpMenuItem.Builder(context) .setTitle(getString(R.string.reset_to_default)) + .showTopDivider(true) .setIcon(getContentIcon(R.drawable.ic_action_reset)) .setOnClickListener(v -> { FragmentActivity activity = getActivity(); @@ -80,7 +95,7 @@ protected void showOptionsMenu(@NonNull View view) { } }).create()); - items.add(new PopUpMenuItem.Builder(view.getContext()) + items.add(new PopUpMenuItem.Builder(context) .setTitle(getString(R.string.copy_from_other_profile)) .setIcon(getContentIcon(R.drawable.ic_action_copy)) .setOnClickListener(v -> { @@ -96,7 +111,6 @@ protected void showOptionsMenu(@NonNull View view) { displayData.anchorView = view; displayData.menuItems = items; displayData.nightMode = nightMode; - displayData.layoutId = R.layout.simple_popup_menu_item; PopUpMenu.show(displayData); } diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapButtonCard.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapButtonCard.java index 881c003a50e..3ec3bde9c55 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapButtonCard.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapButtonCard.java @@ -10,6 +10,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.quickaction.ButtonAppearanceParams; @@ -28,7 +29,7 @@ public class MapButtonCard extends MapBaseCard { private MapButton mapButton; public MapButtonCard(@NonNull MapActivity mapActivity, @NonNull MapButtonState buttonState, - @Nullable ButtonAppearanceParams customAppearanceParams) { + @Nullable ButtonAppearanceParams customAppearanceParams) { super(mapActivity, false); this.buttonState = buttonState; this.customAppearanceParams = customAppearanceParams; @@ -45,7 +46,7 @@ protected void updateContent() { container.removeAllViews(); setupButton(container); - setupButtonBackground(container); + setupButtonBackground(container, nightMode); } public void setupButton(@NonNull ViewGroup container) { @@ -71,7 +72,8 @@ public void updateButton(@NonNull ButtonAppearanceParams appearanceParams) { } } - private void setupButtonBackground(@NonNull View view) { + public static void setupButtonBackground(@NonNull View view, boolean nightMode) { + OsmandApplication app = (OsmandApplication) view.getContext().getApplicationContext(); RenderingRulesStorage renderer = app.getRendererRegistry().getCurrentSelectedRenderer(); if (renderer != null) { MapRenderRepositories maps = app.getResourceManager().getRenderer(); diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapButtonState.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapButtonState.java index e6ca647e305..a0dbe391c38 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapButtonState.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapButtonState.java @@ -1,6 +1,7 @@ package net.osmand.plus.views.mapwidgets.configure.buttons; import static net.osmand.plus.quickaction.ButtonAppearanceParams.BIG_SIZE_DP; +import static net.osmand.plus.quickaction.ButtonAppearanceParams.ORIGINAL_VALUE; import static net.osmand.plus.quickaction.ButtonAppearanceParams.ROUND_RADIUS_DP; import static net.osmand.plus.quickaction.ButtonAppearanceParams.TRANSPARENT_ALPHA; @@ -18,6 +19,7 @@ import net.osmand.plus.OsmandApplication; import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.quickaction.ButtonAppearanceParams; +import net.osmand.plus.quickaction.MapButtonsHelper; import net.osmand.plus.render.RenderingIcons; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.OsmandSettings; @@ -60,11 +62,11 @@ public MapButtonState(@NonNull OsmandApplication app, @NonNull String id) { this.allPreferences = new ArrayList<>(); this.iconPref = addPreference(settings.registerStringPreference(id + "_icon", null)).makeProfile().cache(); - this.sizePref = addPreference(settings.registerIntPreference(id + "_size", -1)).makeProfile().cache(); - this.opacityPref = addPreference(settings.registerFloatPreference(id + "_opacity", -1)).makeProfile().cache(); - this.cornerRadiusPref = addPreference(settings.registerIntPreference(id + "_corner_radius", -1)).makeProfile().cache(); - this.portraitPositionPref = addPreference(settings.registerLongPreference(id + "_position_portrait", -1)).makeProfile().cache(); - this.landscapePositionPref = addPreference(settings.registerLongPreference(id + "_position_landscape", -1)).makeProfile().cache(); + this.sizePref = addPreference(settings.registerIntPreference(id + "_size", ORIGINAL_VALUE)).makeProfile().cache(); + this.opacityPref = addPreference(settings.registerFloatPreference(id + "_opacity", ORIGINAL_VALUE)).makeProfile().cache(); + this.cornerRadiusPref = addPreference(settings.registerIntPreference(id + "_corner_radius", ORIGINAL_VALUE)).makeProfile().cache(); + this.portraitPositionPref = addPreference(settings.registerLongPreference(id + "_position_portrait", ORIGINAL_VALUE)).makeProfile().cache(); + this.landscapePositionPref = addPreference(settings.registerLongPreference(id + "_position_landscape", ORIGINAL_VALUE)).makeProfile().cache(); this.positionSize = setupButtonPosition(new ButtonPositionSize(getId())); this.defaultPositionSize = setupButtonPosition(new ButtonPositionSize(getId())); From 164f2917e8a96c19f431f1574034faf0081c72a3 Mon Sep 17 00:00:00 2001 From: chumv Date: Mon, 16 Dec 2024 13:26:17 +0200 Subject: [PATCH 2/2] Add MapHudCard --- OsmAnd/res/layout/map_hud_card.xml | 13 +++ OsmAnd/res/values/sizes.xml | 1 + .../controls/maphudbuttons/MapButton.java | 81 ++++++++++--- .../maphudbuttons/MyLocationButton.java | 4 +- .../DefaultButtonsAppearanceFragment.java | 16 +++ .../configure/buttons/MapButtonCard.java | 1 + .../configure/buttons/MapButtonState.java | 20 +++- .../configure/buttons/MapHudCard.java | 110 ++++++++++++++++++ 8 files changed, 224 insertions(+), 22 deletions(-) create mode 100644 OsmAnd/res/layout/map_hud_card.xml create mode 100644 OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapHudCard.java diff --git a/OsmAnd/res/layout/map_hud_card.xml b/OsmAnd/res/layout/map_hud_card.xml new file mode 100644 index 00000000000..742d4141413 --- /dev/null +++ b/OsmAnd/res/layout/map_hud_card.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/values/sizes.xml b/OsmAnd/res/values/sizes.xml index b71191b2d02..c8082765b71 100644 --- a/OsmAnd/res/values/sizes.xml +++ b/OsmAnd/res/values/sizes.xml @@ -478,5 +478,6 @@ 160dp 126dp 130dp + 290dp \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/views/controls/maphudbuttons/MapButton.java b/OsmAnd/src/net/osmand/plus/views/controls/maphudbuttons/MapButton.java index 0143244dcb5..e07cd1194bc 100644 --- a/OsmAnd/src/net/osmand/plus/views/controls/maphudbuttons/MapButton.java +++ b/OsmAnd/src/net/osmand/plus/views/controls/maphudbuttons/MapButton.java @@ -4,6 +4,7 @@ import static android.graphics.drawable.GradientDrawable.RECTANGLE; import static android.widget.ImageView.ScaleType.CENTER; import static net.osmand.plus.quickaction.ButtonAppearanceParams.BIG_SIZE_DP; +import static net.osmand.plus.quickaction.ButtonAppearanceParams.ORIGINAL_VALUE; import static net.osmand.plus.quickaction.ButtonAppearanceParams.ROUND_RADIUS_DP; import static net.osmand.plus.quickaction.ButtonAppearanceParams.TRANSPARENT_ALPHA; import static net.osmand.plus.views.layers.ContextMenuLayer.VIBRATE_SHORT; @@ -101,11 +102,13 @@ public MapButton(@NonNull Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } - public MapButton(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) { + public MapButton(@NonNull Context context, @Nullable AttributeSet attrs, + @AttrRes int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } - public MapButton(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) { + public MapButton(@NonNull Context context, @Nullable AttributeSet attrs, + @AttrRes int defStyleAttr, @StyleRes int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); this.app = (OsmandApplication) context.getApplicationContext(); @@ -121,7 +124,7 @@ public MapButton(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRe @NonNull protected ImageView setupImageView(@NonNull Context context, @Nullable AttributeSet attrs, - @AttrRes int defStyleAttr, @StyleRes int defStyleRes) { + @AttrRes int defStyleAttr, @StyleRes int defStyleRes) { int imageSize = (int) getImageSize(); ImageView imageView = new ImageView(context, attrs, defStyleAttr, defStyleRes); imageView.setClickable(false); @@ -181,7 +184,13 @@ public ButtonAppearanceParams getAppearanceParams() { public ButtonPositionSize getDefaultPositionSize() { MapButtonState buttonState = getButtonState(); if (buttonState != null) { - return buttonState.getDefaultPositionSize(); + ButtonPositionSize position = buttonState.getDefaultPositionSize(); + + int size = getSize(); + size = (size / 8) + 1; + position.setSize(size, size); + + return position; } return null; } @@ -253,7 +262,8 @@ protected void setIconColor(@ColorInt int iconColor) { } } - protected void setBackgroundColors(@ColorInt int backgroundColor, @ColorInt int backgroundPressedColor) { + protected void setBackgroundColors(@ColorInt int backgroundColor, + @ColorInt int backgroundPressedColor) { if (this.backgroundColor != backgroundColor || this.backgroundPressedColor != backgroundPressedColor) { this.backgroundColor = backgroundColor; this.backgroundPressedColor = backgroundPressedColor; @@ -269,8 +279,8 @@ public void update() { updateColors(nightMode); ButtonAppearanceParams params = getAppearanceParams(); - if (invalidated || !Algorithms.objectEquals(appearanceParams, params) || customAppearanceParams != null) { - this.appearanceParams = customAppearanceParams != null ? customAppearanceParams : params; + if (invalidated || !Algorithms.objectEquals(appearanceParams, params)) { + this.appearanceParams = params; this.invalidated = false; updateContent(); } @@ -290,7 +300,10 @@ protected void updateContent() { } protected void updateIcon() { - String iconName = appearanceParams.getIconName(); + String iconName = customAppearanceParams != null ? customAppearanceParams.getIconName() : null; + if (Algorithms.isEmpty(iconName)) { + iconName = appearanceParams.getIconName(); + } int iconId = AndroidUtils.getDrawableId(app, iconName); if (iconId == 0) { iconId = RenderingIcons.getBigIconResourceId(iconName); @@ -321,8 +334,8 @@ protected void updateSize(@NonNull View view, int size) { protected void updateBackground() { Context context = getContext(); - float opacity = appearanceParams.getOpacity(); - int cornerRadius = AndroidUtils.dpToPx(context, appearanceParams.getCornerRadius()); + float opacity = getOpacity(); + int cornerRadius = AndroidUtils.dpToPx(context, getCornerRadius()); GradientDrawable normal = new GradientDrawable(); normal.setShape(RECTANGLE); @@ -342,7 +355,7 @@ protected void updateBackground() { } protected void updateShadow() { - int radius = AndroidUtils.dpToPx(getContext(), appearanceParams.getCornerRadius()); + int radius = AndroidUtils.dpToPx(getContext(), getCornerRadius()); float[] outerRadius = new float[] {radius, radius, radius, radius, radius, radius, radius, radius}; ShapeDrawable drawable = new ShapeDrawable(); @@ -358,7 +371,7 @@ protected void updateShadow() { protected void onDraw(@NotNull Canvas canvas) { super.onDraw(canvas); - if (!nightMode && appearanceParams != null) { + if (!nightMode && (appearanceParams != null || customAppearanceParams != null)) { drawShadow(canvas); } } @@ -369,7 +382,7 @@ protected void drawShadow(@NotNull Canvas canvas) { int width = getWidth(); int height = getHeight(); int padding = (int) shadowPadding; - int radius = AndroidUtils.dpToPx(getContext(), appearanceParams.getCornerRadius()); + int radius = AndroidUtils.dpToPx(getContext(), getCornerRadius()); clipPath.reset(); clipPath.addRoundRect(padding, padding, width - padding, height - padding, radius, radius, Direction.CW); @@ -420,8 +433,7 @@ public float getFrameSize() { } public float getImageSize() { - ButtonAppearanceParams params = appearanceParams != null ? appearanceParams : getAppearanceParams(); - return AndroidUtils.dpToPxF(getContext(), params.getSize()); + return AndroidUtils.dpToPxF(getContext(), getSize()); } @NonNull @@ -454,4 +466,43 @@ protected void onVisibilityChanged(@NonNull View changedView, int visibility) { visibilityListener.onVisibilityChanged(changedView, visibility); } } + + public int getSize() { + if (customAppearanceParams != null) { + int size = customAppearanceParams.getSize(); + if (size == ORIGINAL_VALUE) { + MapButtonState buttonState = getButtonState(); + return buttonState != null ? buttonState.getDefaultSize() : createDefaultAppearanceParams().getSize(); + } + return size; + } + ButtonAppearanceParams params = appearanceParams != null ? appearanceParams : getAppearanceParams(); + return params.getSize(); + } + + public float getOpacity() { + if (customAppearanceParams != null) { + float opacity = customAppearanceParams.getOpacity(); + if (opacity == ORIGINAL_VALUE) { + MapButtonState buttonState = getButtonState(); + return buttonState != null ? buttonState.getDefaultOpacity() : createDefaultAppearanceParams().getOpacity(); + } + return opacity; + } + ButtonAppearanceParams params = appearanceParams != null ? appearanceParams : getAppearanceParams(); + return params.getOpacity(); + } + + public int getCornerRadius() { + if (customAppearanceParams != null) { + int cornerRadius = customAppearanceParams.getCornerRadius(); + if (cornerRadius == ORIGINAL_VALUE) { + MapButtonState buttonState = getButtonState(); + return buttonState != null ? buttonState.getDefaultCornerRadius() : createDefaultAppearanceParams().getCornerRadius(); + } + return cornerRadius; + } + ButtonAppearanceParams params = appearanceParams != null ? appearanceParams : getAppearanceParams(); + return params.getCornerRadius(); + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/views/controls/maphudbuttons/MyLocationButton.java b/OsmAnd/src/net/osmand/plus/views/controls/maphudbuttons/MyLocationButton.java index c97daa072b4..ac9599871c6 100644 --- a/OsmAnd/src/net/osmand/plus/views/controls/maphudbuttons/MyLocationButton.java +++ b/OsmAnd/src/net/osmand/plus/views/controls/maphudbuttons/MyLocationButton.java @@ -111,11 +111,11 @@ protected boolean shouldShow() { protected void updateBackground() { Context context = getContext(); - int cornerRadius = AndroidUtils.dpToPx(context, appearanceParams.getCornerRadius()); + int cornerRadius = AndroidUtils.dpToPx(context, getCornerRadius()); GradientDrawable normal = new GradientDrawable(); normal.setShape(RECTANGLE); - normal.setColor(ColorUtilities.getColorWithAlpha(backgroundColor, appearanceParams.getOpacity())); + normal.setColor(ColorUtilities.getColorWithAlpha(backgroundColor, getOpacity())); normal.setCornerRadius(cornerRadius); GradientDrawable pressed = new GradientDrawable(); diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultButtonsAppearanceFragment.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultButtonsAppearanceFragment.java index f68a4320a5b..a3095cca65d 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultButtonsAppearanceFragment.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultButtonsAppearanceFragment.java @@ -50,6 +50,7 @@ public class DefaultButtonsAppearanceFragment extends BaseOsmAndFragment impleme private ButtonAppearanceParams appearanceParams; private ButtonAppearanceParams originalAppearanceParams; + private MapHudCard mapHudCard; private List cards; private DialogButton applyButton; @@ -128,6 +129,8 @@ private void setupCards(@NonNull View view) { container.removeAllViews(); MapActivity activity = requireMapActivity(); + mapHudCard = new MapHudCard(activity, appearanceParams); + addCard(container, mapHudCard); addCard(container, new CornerRadiusCard(activity, appearanceParams, true)); container.addView(themedInflater.inflate(R.layout.list_item_divider, container, false)); addCard(container, new ButtonSizeCard(activity, appearanceParams, true)); @@ -211,6 +214,10 @@ private ButtonAppearanceParams createAppearanceParams() { @Override public void onCardPressed(@NonNull BaseCard card) { updateButtons(); + + if (mapHudCard != null) { + mapHudCard.updateContent(); + } } @Override @@ -240,6 +247,15 @@ public void onPause() { } } + @Override + public void onDestroyView() { + super.onDestroyView(); + + if (mapHudCard != null) { + mapHudCard.clearWidgets(); + } + } + @Nullable public MapActivity getMapActivity() { FragmentActivity activity = getActivity(); diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapButtonCard.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapButtonCard.java index 3ec3bde9c55..328a9253839 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapButtonCard.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapButtonCard.java @@ -68,6 +68,7 @@ public void updateButton(@NonNull ButtonAppearanceParams appearanceParams) { if (mapButton != null) { customAppearanceParams = appearanceParams; mapButton.setCustomAppearanceParams(appearanceParams); + mapButton.setInvalidated(true); mapButton.update(); } } diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapButtonState.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapButtonState.java index a0dbe391c38..6cb8e34bba5 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapButtonState.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapButtonState.java @@ -92,7 +92,20 @@ public String getId() { @NonNull public ButtonAppearanceParams createDefaultAppearanceParams() { - return new ButtonAppearanceParams(getDefaultIconName(), getDefaultSize(), getDefaultOpacity(), getDefaultCornerRadius()); + MapButtonsHelper buttonsHelper = app.getMapButtonsHelper(); + int size = buttonsHelper.getDefaultSizePref().get(); + if (size <= 0) { + size = getDefaultSize(); + } + float opacity = buttonsHelper.getDefaultOpacityPref().get(); + if (opacity < 0) { + opacity = getDefaultOpacity(); + } + int cornerRadius = buttonsHelper.getDefaultCornerRadiusPref().get(); + if (cornerRadius < 0) { + cornerRadius = getDefaultCornerRadius(); + } + return new ButtonAppearanceParams(getDefaultIconName(), size, opacity, cornerRadius); } @LayoutRes @@ -211,10 +224,7 @@ private void updatePosition(@NonNull ButtonPositionSize position) { if (value != null && value > 0) { position.fromLongValue(value); } - int size = sizePref.get(); - if (size <= 0) { - size = getDefaultSize(); - } + int size = createAppearanceParams().getSize(); size = (size / 8) + 1; position.setSize(size, size); } diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapHudCard.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapHudCard.java new file mode 100644 index 00000000000..0ba4e4cbbb6 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/MapHudCard.java @@ -0,0 +1,110 @@ +package net.osmand.plus.views.mapwidgets.configure.buttons; + +import android.content.Context; +import android.view.View; + +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import net.osmand.plus.R; +import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.quickaction.ButtonAppearanceParams; +import net.osmand.plus.routepreparationmenu.cards.MapBaseCard; +import net.osmand.plus.views.MapLayers; +import net.osmand.plus.views.controls.MapHudLayout; +import net.osmand.plus.views.controls.maphudbuttons.MapButton; +import net.osmand.plus.views.mapwidgets.widgets.RulerWidget; + +import java.util.ArrayList; +import java.util.List; + +public class MapHudCard extends MapBaseCard { + + private final List mapButtons = new ArrayList<>(); + private final ButtonAppearanceParams appearanceParams; + + private MapHudLayout mapHudLayout; + private RulerWidget rulerWidget; + + public MapHudCard(@NonNull MapActivity mapActivity, + @Nullable ButtonAppearanceParams appearanceParams) { + super(mapActivity, false); + this.appearanceParams = appearanceParams; + } + + @Override + public int getCardLayoutId() { + return R.layout.map_hud_card; + } + + @NonNull + @Override + public View inflate(@NonNull Context ctx) { + View view = super.inflate(ctx); + initMapButtons(view); + return view; + } + + public void initMapButtons(@NonNull View view) { + mapHudLayout = view.findViewById(R.id.map_hud_layout); + + addMapButton(createMapButton(R.layout.configure_map_button)); + addMapButton(createMapButton(R.layout.map_search_button)); + addMapButton(createMapButton(R.layout.map_compass_button)); + addMapButton(createMapButton(R.layout.map_zoom_out_button)); + addMapButton(createMapButton(R.layout.map_zoom_in_button)); + addMapButton(createMapButton(R.layout.my_location_button)); + addMapButton(createMapButton(R.layout.drawer_menu_button)); + addMapButton(createMapButton(R.layout.navigation_menu_button)); + addMapButton(createMapButton(R.layout.map_3d_button)); + + setupRulerWidget(); + } + + @NonNull + private MapButton createMapButton(@LayoutRes int layoutId) { + MapButton button = (MapButton) themedInflater.inflate(layoutId, mapHudLayout, false); + button.setAlwaysVisible(true); + button.setNightMode(nightMode); + button.setMapActivity(mapActivity); + button.setOnTouchListener(null); + button.setOnClickListener(null); + button.setOnLongClickListener(null); + button.setCustomAppearanceParams(appearanceParams); + + return button; + } + + private void addMapButton(@NonNull MapButton mapButton) { + mapButtons.add(mapButton); + mapHudLayout.addMapButton(mapButton); + } + + private void setupRulerWidget() { + rulerWidget = (RulerWidget) themedInflater.inflate(R.layout.map_ruler, mapHudLayout, false); + + MapLayers mapLayers = app.getOsmandMap().getMapLayers(); + mapLayers.getMapInfoLayer().setupRulerWidget(rulerWidget); + mapHudLayout.addWidget(rulerWidget); + } + + @Override + protected void updateContent() { + updateButtons(); + MapButtonCard.setupButtonBackground(view, nightMode); + } + + private void updateButtons() { + for (MapButton button : mapButtons) { + button.setInvalidated(true); + button.update(); + } + mapHudLayout.updateButtons(); + } + + public void clearWidgets() { + MapLayers mapLayers = app.getOsmandMap().getMapLayers(); + mapLayers.getMapInfoLayer().setupRulerWidget(rulerWidget); + } +} \ No newline at end of file