Merge pull request #8697 from osmandapp/RecalculateWhenDeviation

Change Settings UI -> Distance to recalculate
This commit is contained in:
max-klaus 2020-03-20 17:55:29 +03:00 committed by GitHub
commit 33ff88e66e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 384 additions and 47 deletions

View file

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<net.osmand.plus.widgets.TextViewEx
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
osmand:typeface="@string/font_roboto_regular"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
tools:text="title"/>
<net.osmand.plus.widgets.TextViewEx
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
osmand:typeface="@string/font_roboto_medium"
android:textColor="?attr/active_color_basic"
android:textSize="@dimen/default_list_text_size"
tools:text="summary"/>
</FrameLayout>
<com.google.android.material.slider.Slider
android:id="@+id/slider"
style="@style/Widget.MaterialComponents.Slider"
android:theme="@style/Theme.MaterialComponents"
android:layout_width="match_parent"
android:layout_height="wrap_content"
osmand:labelBehavior="gone" />
</LinearLayout>

View file

@ -11,6 +11,9 @@
Thx - Hardy
-->
<string name="recalculate_route_distance_promo">The route will be recalculated if the distance from the route to the current location is more than selected value.</string>
<string name="select_distance_route_will_recalc">Select the distance after which the route will be recalculated.</string>
<string name="recalculate_route_in_deviation">Recalculate route in case of deviation</string>
<string name="clear_recorded_data_warning">Are you sure you want to clear recorded data?</string>
<string name="restore_all_profile_settings_descr">All profile settings will be restored to their original state after creating/importing this profile.</string>
<string name="restore_all_profile_settings">Restore all profile settings?</string>

View file

@ -959,7 +959,7 @@ public class OsmandSettings {
}
}
private class FloatPreference extends CommonPreference<Float> {
public class FloatPreference extends CommonPreference<Float> {
private FloatPreference(String id, float defaultValue) {

View file

@ -26,7 +26,7 @@ public class DividerHalfItem extends DividerItem {
}
@Override
protected int getLeftMargin(Context context) {
protected int getStartMargin(Context context) {
return context.getResources().getDimensionPixelSize(R.dimen.bottom_sheet_divider_margin_start);
}
}

View file

@ -39,10 +39,10 @@ public class DividerItem extends BaseBottomSheetItem {
public void inflate(Context context, ViewGroup container, boolean nightMode) {
super.inflate(context, container, nightMode);
int height = AndroidUtils.dpToPx(context, 1);
int height = getHeight(context);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
params.setMargins(getLeftMargin(context), getTopMargin(context), 0, getBottomMargin(context));
AndroidUtils.setMargins(params, getStartMargin(context), getTopMargin(context), 0, getBottomMargin(context));
params.height = height;
view.setMinimumHeight(height);
@ -53,7 +53,7 @@ public class DividerItem extends BaseBottomSheetItem {
return context.getResources().getDimensionPixelSize(R.dimen.bottom_sheet_content_padding_small);
}
protected int getLeftMargin(Context context) {
protected int getStartMargin(Context context) {
return 0;
}
@ -61,8 +61,12 @@ public class DividerItem extends BaseBottomSheetItem {
return context.getResources().getDimensionPixelSize(R.dimen.bottom_sheet_content_padding_small);
}
protected int getHeight(Context ctx) {
return AndroidUtils.dpToPx(ctx, 1);
}
@ColorRes
private int getBgColorId(boolean nightMode) {
protected int getBgColorId(boolean nightMode) {
if (colorId != INVALID_ID) {
return colorId;
}

View file

@ -0,0 +1,33 @@
package net.osmand.plus.base.bottomsheetmenu.simpleitems;
import android.content.Context;
public class DividerSpaceItem extends DividerItem {
private int verticalSpacePx;
public DividerSpaceItem(Context context, int verticalSpacePx) {
super(context);
this.verticalSpacePx = verticalSpacePx;
}
@Override
protected int getTopMargin(Context context) {
return 0;
}
@Override
protected int getBottomMargin(Context context) {
return 0;
}
@Override
protected int getHeight(Context ctx) {
return verticalSpacePx;
}
@Override
protected int getBgColorId(boolean nightMode) {
return android.R.color.transparent;
}
}

View file

@ -26,7 +26,7 @@ public class DividerStartItem extends DividerItem {
}
@Override
protected int getLeftMargin(Context context) {
protected int getStartMargin(Context context) {
return context.getResources().getDimensionPixelSize(R.dimen.bottom_sheet_divider_margin_start);
}
}

View file

@ -26,7 +26,7 @@ public class SubtitmeListDividerItem extends DividerItem {
}
@Override
protected int getLeftMargin(Context context) {
protected int getStartMargin(Context context) {
return context.getResources().getDimensionPixelSize(R.dimen.list_content_padding);
}
}

View file

@ -14,6 +14,7 @@ import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentManager;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import androidx.preference.PreferenceViewHolder;
@ -30,6 +31,7 @@ import net.osmand.plus.activities.SettingsBaseActivity;
import net.osmand.plus.activities.SettingsNavigationActivity;
import net.osmand.plus.routing.RouteProvider;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.settings.bottomsheets.RecalculateRouteInDeviationBottomSheet;
import net.osmand.plus.settings.preferences.ListPreferenceEx;
import net.osmand.plus.settings.preferences.MultiSelectBooleanPreference;
import net.osmand.plus.settings.preferences.SwitchPreferenceEx;
@ -55,6 +57,10 @@ public class RouteParametersFragment extends BaseSettingsFragment implements OnP
private static final String ROUTE_PARAMETERS_INFO = "route_parameters_info";
private static final String ROUTE_PARAMETERS_IMAGE = "route_parameters_image";
private static final String RELIEF_SMOOTHNESS_FACTOR = "relief_smoothness_factor";
private static final String ROUTING_RECALC_DISTANCE= "routing_recalc_distance";
public static final float DISABLE_MODE = -1.0f;
public static final float DEFAULT_MODE = 0.0f;
private List<RoutingParameter> avoidParameters = new ArrayList<RoutingParameter>();
private List<RoutingParameter> preferParameters = new ArrayList<RoutingParameter>();
@ -147,9 +153,7 @@ public class RouteParametersFragment extends BaseSettingsFragment implements OnP
fastRoute.setSummaryOn(R.string.shared_string_on);
fastRoute.setSummaryOff(R.string.shared_string_off);
float defaultAllowedDeviation = RoutingHelper.getDefaultAllowedDeviation(settings, am,
RoutingHelper.getPosTolerance(0));
setupSelectRouteRecalcDistance(screen, defaultAllowedDeviation);
setupSelectRouteRecalcDistance(screen);
if (am.getRouteService() == RouteProvider.RouteService.OSMAND){
GeneralRouter router = app.getRouter(am);
@ -261,6 +265,18 @@ public class RouteParametersFragment extends BaseSettingsFragment implements OnP
return super.onPreferenceClick(preference);
}
@Override
public void onDisplayPreferenceDialog(Preference preference) {
if (preference.getKey().equals(settings.ROUTE_RECALCULATION_DISTANCE.getId())) {
FragmentManager fragmentManager = getFragmentManager();
if (fragmentManager != null) {
RecalculateRouteInDeviationBottomSheet.showInstance(getFragmentManager(), preference.getKey(), this, false, getSelectedAppMode());
}
} else {
super.onDisplayPreferenceDialog(preference);
}
}
private void showSeekbarSettingsDialog(Activity activity, final ApplicationMode mode) {
if (activity == null || mode == null) {
return;
@ -318,35 +334,30 @@ public class RouteParametersFragment extends BaseSettingsFragment implements OnP
UiUtilities.setupSeekBar(angleBar, activeColor, nightMode);
}
private void setupSelectRouteRecalcDistance(PreferenceScreen screen, float defaultAllowedDeviation) {
Float[] entryValues;
OsmandSettings settings = app.getSettings();
OsmandSettings.MetricsConstants mc = settings.METRIC_SYSTEM.get();
if (mc == OsmandSettings.MetricsConstants.KILOMETERS_AND_METERS) {
entryValues = new Float[] {-1.0f, 0.f, 10.f, 20.0f, 30.0f, 50.0f, 100.0f, 200.0f, 500.0f, 1000.0f, 1500.0f};
} else {
entryValues = new Float[] {-1.0f, 0.f, 9.1f, 18.3f, 30.5f, 45.7f, 91.5f, 183.0f, 482.0f, 965.0f, 1609.0f};
private void setupSelectRouteRecalcDistance(PreferenceScreen screen) {
final SwitchPreferenceEx switchPref = createSwitchPreferenceEx(ROUTING_RECALC_DISTANCE,
R.string.route_recalculation_dist_title, R.layout.preference_with_descr_dialog_and_switch);
switchPref.setIcon(getRoutingPrefIcon(ROUTING_RECALC_DISTANCE));
screen.addPreference(switchPref);
updateRouteRecalcDistancePref();
}
String[] entries = new String[entryValues.length];
entries[0] = getString(R.string.no_recalculation_setting);
String defaultDistance = defaultAllowedDeviation < 0 ? getString(R.string.no_recalculation_setting) :
OsmAndFormatter.getFormattedDistance(defaultAllowedDeviation , app, false);
entries[1] = String.format(getString(R.string.shared_string_app_default_w_val), defaultDistance);
for (int i = 2; i < entryValues.length; i++) {
entries[i] = OsmAndFormatter.getFormattedDistance(entryValues[i], app, false);
private void updateRouteRecalcDistancePref() {
SwitchPreferenceEx switchPref = (SwitchPreferenceEx) findPreference(ROUTING_RECALC_DISTANCE);
if (switchPref == null) {
return;
}
ListPreferenceEx routeRecalculationDist = createListPreferenceEx(settings.ROUTE_RECALCULATION_DISTANCE.getId(),
entries, entryValues, R.string.route_recalculation_dist_title, R.layout.preference_with_descr);
routeRecalculationDist.setEntries(entries);
routeRecalculationDist.setEntryValues(entryValues);
routeRecalculationDist.setDescription(getString(R.string.route_recalculation_dist_descr));
routeRecalculationDist.setIcon(getRoutingPrefIcon("routing_recalc_distance"));
screen.addPreference(routeRecalculationDist);
ApplicationMode appMode = getSelectedAppMode();
float allowedValue = settings.ROUTE_RECALCULATION_DISTANCE.getModeValue(appMode);
boolean enabled = allowedValue != DISABLE_MODE;
if (allowedValue <= 0) {
allowedValue = RoutingHelper.getDefaultAllowedDeviation(settings, appMode, RoutingHelper.getPosTolerance(0));
}
String summary = String.format(getString(R.string.ltr_or_rtl_combine_via_bold_point),
enabled ? getString(R.string.shared_string_enabled) : getString(R.string.shared_string_disabled),
OsmAndFormatter.getFormattedDistance(allowedValue, app, false));
switchPref.setSummary(summary);
switchPref.setChecked(enabled);
}
@Override
@ -414,12 +425,12 @@ public class RouteParametersFragment extends BaseSettingsFragment implements OnP
return true;
} else if ("prouting_short_way".equals(key) && newValue instanceof Boolean) {
return app.getSettings().FAST_ROUTE_MODE.setModeValue(getSelectedAppMode(), !(Boolean) newValue);
} else if (settings.ROUTE_RECALCULATION_DISTANCE.getId().equals(key) && newValue instanceof Float) {
if ((float) newValue == -1.f) {
settings.DISABLE_OFFROUTE_RECALC.setModeValue(getSelectedAppMode(), true);
} else {
settings.DISABLE_OFFROUTE_RECALC.setModeValue(getSelectedAppMode(), false);
}
} else if (ROUTING_RECALC_DISTANCE.equals(key) && newValue instanceof Boolean) {
boolean enabled = (Boolean) newValue;
settings.ROUTE_RECALCULATION_DISTANCE.setModeValue(getSelectedAppMode(),
enabled ? DEFAULT_MODE : DISABLE_MODE);
settings.DISABLE_OFFROUTE_RECALC.setModeValue(getSelectedAppMode(), !enabled);
updateRouteRecalcDistancePref();
}
return super.onPreferenceChange(preference, newValue);
@ -429,6 +440,8 @@ public class RouteParametersFragment extends BaseSettingsFragment implements OnP
public void onPreferenceChanged(String prefId) {
if (AVOID_ROUTING_PARAMETER_PREFIX.equals(prefId) || PREFER_ROUTING_PARAMETER_PREFIX.equals(prefId)) {
recalculateRoute();
} else if (ROUTING_RECALC_DISTANCE.equals(prefId)) {
updateRouteRecalcDistancePref();
}
}
@ -529,7 +542,7 @@ public class RouteParametersFragment extends BaseSettingsFragment implements OnP
return getPersistentPrefIcon(R.drawable.ic_action_fastest_route);
case "enable_time_conditional_routing":
return getPersistentPrefIcon(R.drawable.ic_action_road_works_dark);
case "routing_recalc_distance":
case ROUTING_RECALC_DISTANCE:
return getPersistentPrefIcon(R.drawable.ic_action_minimal_distance);
default:

View file

@ -109,14 +109,14 @@ public class BooleanPreferenceBottomSheet extends BasePreferenceBottomSheet {
return R.string.shared_string_cancel;
}
private View getCustomButtonView(boolean checked) {
protected View getCustomButtonView(boolean checked) {
View customView = UiUtilities.getInflater(getContext(), nightMode).inflate(R.layout.bottom_sheet_item_preference_switch, null);
updateCustomButtonView(customView, checked);
return customView;
}
private void updateCustomButtonView(View customView, boolean checked) {
protected void updateCustomButtonView(View customView, boolean checked) {
OsmandApplication app = requiredMyApplication();
View buttonView = customView.findViewById(R.id.button_container);

View file

@ -0,0 +1,239 @@
package net.osmand.plus.settings.bottomsheets;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import com.google.android.material.slider.Slider;
import net.osmand.AndroidUtils;
import net.osmand.plus.ApplicationMode;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithCompoundButton;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.LongDescriptionItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerSpaceItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.SubtitmeListDividerItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.settings.OnPreferenceChanged;
import net.osmand.plus.settings.preferences.SwitchPreferenceEx;
import static net.osmand.plus.settings.RouteParametersFragment.DEFAULT_MODE;
import static net.osmand.plus.settings.RouteParametersFragment.DISABLE_MODE;
public class RecalculateRouteInDeviationBottomSheet extends BooleanPreferenceBottomSheet {
public static final String TAG = RecalculateRouteInDeviationBottomSheet.class.getSimpleName();
private static final String CURRENT_VALUE = "current_value";
private OsmandApplication app;
private OsmandSettings settings;
private ApplicationMode appMode;
private OsmandSettings.CommonPreference<Float> preference;
private Slider slider;
private TextView tvSliderTitle;
private TextView tvSliderSummary;
private Float[] entryValues;
private float currentValue;
private boolean enabled = false;
private boolean sliderPositionChanged = false;
@Override
public void createMenuItems(Bundle savedInstanceState) {
app = requiredMyApplication();
settings = app.getSettings();
appMode = getAppMode();
preference = settings.ROUTE_RECALCULATION_DISTANCE;
getPreferenceStateAndValue();
final SwitchPreferenceEx switchPref = (SwitchPreferenceEx) getPreference();
if (switchPref == null) {
return;
}
if (savedInstanceState != null && savedInstanceState.containsKey(CURRENT_VALUE)) {
currentValue = savedInstanceState.getFloat(CURRENT_VALUE);
}
int contentPaddingSmall = app.getResources().getDimensionPixelSize(R.dimen.content_padding_small);
int dialogContentMargin = app.getResources().getDimensionPixelSize(R.dimen.dialog_content_margin);
OsmandSettings.MetricsConstants mc = settings.METRIC_SYSTEM.get();
if (mc == OsmandSettings.MetricsConstants.KILOMETERS_AND_METERS) {
entryValues = new Float[]{10.f, 20.0f, 30.0f, 50.0f, 100.0f, 200.0f, 500.0f, 1000.0f, 1500.0f};
} else {
entryValues = new Float[]{9.1f, 18.3f, 30.5f, 45.7f, 91.5f, 183.0f, 482.0f, 965.0f, 1609.0f};
}
final int appModeColor = appMode.getIconColorInfo().getColor(nightMode);
final int activeColor = AndroidUtils.resolveAttribute(app, R.attr.active_color_basic);
final int disabledColor = AndroidUtils.resolveAttribute(app, android.R.attr.textColorSecondary);
String title = getString(R.string.recalculate_route_in_deviation);
items.add(new TitleItem(title));
final View sliderView = UiUtilities.getInflater(getContext(), nightMode).inflate(R.layout.bottom_sheet_item_slider_with_two_text, null);
slider = sliderView.findViewById(R.id.slider);
tvSliderTitle = sliderView.findViewById(android.R.id.title);
tvSliderTitle.setText(getString(R.string.distance));
tvSliderSummary = sliderView.findViewById(android.R.id.summary);
slider.setValueFrom(0);
slider.setValueTo(entryValues.length - 1);
slider.setStepSize(1);
updateSliderView();
final String on = getString(R.string.shared_string_enabled);
final String off = getString(R.string.shared_string_disabled);
final BottomSheetItemWithCompoundButton[] preferenceBtn = new BottomSheetItemWithCompoundButton[1];
preferenceBtn[0] = (BottomSheetItemWithCompoundButton) new BottomSheetItemWithCompoundButton.Builder()
.setChecked(enabled)
.setCompoundButtonColorId(appModeColor)
.setTitle(enabled ? on : off)
.setTitleColorId(enabled ? activeColor : disabledColor)
.setCustomView(getCustomButtonView(enabled))
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
enabled = !enabled;
if (switchPref.callChangeListener(enabled)) {
sliderPositionChanged = false;
switchPref.setChecked(enabled);
preferenceBtn[0].setTitle(enabled ? on : off);
preferenceBtn[0].setTitleColorId(enabled ? activeColor : disabledColor);
preferenceBtn[0].setChecked(enabled);
getDefaultValue();
updateSliderView();
updateCustomButtonView(v, enabled);
Fragment target = getTargetFragment();
if (target instanceof OnPreferenceChanged) {
((OnPreferenceChanged) target).onPreferenceChanged(switchPref.getKey());
}
}
}
})
.create();
items.add(preferenceBtn[0]);
items.add(new DividerSpaceItem(app, contentPaddingSmall));
items.add(new LongDescriptionItem(getString(R.string.select_distance_route_will_recalc)));
items.add(new DividerSpaceItem(app, dialogContentMargin));
slider.addOnChangeListener(new Slider.OnChangeListener() {
@Override
public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) {
sliderPositionChanged = true;
if (fromUser) {
currentValue = entryValues[(int) slider.getValue()];
tvSliderSummary.setText(getFormattedDistance(app, currentValue));
}
}
});
items.add(new BaseBottomSheetItem.Builder()
.setCustomView(sliderView)
.create());
items.add(new SubtitmeListDividerItem(getContext()));
items.add(new DividerSpaceItem(app, contentPaddingSmall));
items.add(new LongDescriptionItem(getString(R.string.recalculate_route_distance_promo)));
}
@Override
protected void onRightBottomButtonClick() {
if (enabled && sliderPositionChanged) {
preference.setModeValue(getAppMode(), currentValue);
}
Fragment target = getTargetFragment();
if (target instanceof OnPreferenceChanged) {
((OnPreferenceChanged) target).onPreferenceChanged(preference.getId());
}
dismiss();
}
@Override
protected int getRightBottomButtonTextId() {
return R.string.shared_string_apply;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putFloat(CURRENT_VALUE, currentValue);
}
private void updateSliderView() {
int activeColor = AndroidUtils.resolveAttribute(app, R.attr.active_color_basic);
int disabledColor = AndroidUtils.resolveAttribute(app, android.R.attr.textColorSecondary);
int textColorPrimary = AndroidUtils.resolveAttribute(app, android.R.attr.textColorPrimary);
tvSliderTitle.setTextColor(ContextCompat.getColor(app, enabled ? textColorPrimary : disabledColor));
tvSliderSummary.setTextColor(ContextCompat.getColor(app, enabled ? activeColor : disabledColor));
tvSliderSummary.setText(getFormattedDistance(app, currentValue));
slider.setValue(findIndexOfValue(currentValue));
slider.setEnabled(enabled);
}
private void getPreferenceStateAndValue() {
float allowedValue = preference.getModeValue(appMode);
if (allowedValue == DISABLE_MODE) {
enabled = false;
getDefaultValue();
} else {
enabled = true;
if (allowedValue == DEFAULT_MODE) {
getDefaultValue();
} else {
currentValue = allowedValue;
}
}
}
private void getDefaultValue() {
currentValue = RoutingHelper.getDefaultAllowedDeviation(settings, appMode,
RoutingHelper.getPosTolerance(0));
}
private int findIndexOfValue(float allowedValue) {
for (int i = 0; i < entryValues.length; i++) {
float value = entryValues[i];
if (allowedValue == value) {
return i;
} else if (value > allowedValue) {
return i > 0 ? --i : i;
}
}
return 0;
}
private static String getFormattedDistance(@NonNull OsmandApplication app, float value) {
return OsmAndFormatter.getFormattedDistance(value, app, false);
}
public static boolean showInstance(@NonNull FragmentManager fragmentManager, String key, Fragment target,
boolean usedOnMap, @Nullable ApplicationMode appMode) {
try {
Bundle args = new Bundle();
args.putString(PREFERENCE_ID, key);
RecalculateRouteInDeviationBottomSheet fragment = new RecalculateRouteInDeviationBottomSheet();
fragment.setArguments(args);
fragment.setUsedOnMap(usedOnMap);
fragment.setAppMode(appMode);
fragment.setTargetFragment(target, 0);
fragment.show(fragmentManager, TAG);
return true;
} catch (RuntimeException e) {
return false;
}
}
}