From 9e827469eb5da70cf27ff9aba1a7d373d85f6bba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Guti=C3=A9rrez=20Alfaro?= Date: Fri, 2 Jan 2026 07:44:05 -0600 Subject: [PATCH] Feature: add button to restore default values for logging interval and logging distance (Closes #345) --- .../osmtracker/activity/PreferencesTest.java | 33 +++++++++ .../net/osmtracker/activity/Preferences.java | 71 ++++++++++++++++++- .../main/res/values/strings-preferences.xml | 1 + 3 files changed, 102 insertions(+), 3 deletions(-) diff --git a/app/src/androidTest/java/net/osmtracker/activity/PreferencesTest.java b/app/src/androidTest/java/net/osmtracker/activity/PreferencesTest.java index 796ace41..bef2a78b 100644 --- a/app/src/androidTest/java/net/osmtracker/activity/PreferencesTest.java +++ b/app/src/androidTest/java/net/osmtracker/activity/PreferencesTest.java @@ -122,6 +122,39 @@ public void testNumericInputLogic() { suffix)))))); } + /** + * Test that the Reset button in numeric preferences restores the default value. + */ + @Test + public void testResetButtonResetsValue() { + String title = context.getString(R.string.prefs_gps_logging_interval); + String suffix = context.getString(R.string.prefs_gps_logging_interval_seconds); + String defaultValue = OSMTracker.Preferences.VAL_GPS_LOGGING_INTERVAL; + + scrollToAndClick(title); + + // Set a custom value "50" + onView(withId(android.R.id.edit)).perform(clearText(), typeText("50")); + onView(withText(android.R.string.ok)).perform(click()); + + // Verify custom value is set + onView(ViewMatchers.isAssignableFrom(RecyclerView.class)) + .check(matches(hasDescendant(withText(stringContainsInOrder(Arrays.asList("50", + suffix)))))); + + // Reopen dialog + scrollToAndClick(title); + + // Click the Reset button (Neutral button) + onView(withText(R.string.prefs_reset_default_value)).perform(click()); + + // Verify value is back to default "0" + onView(ViewMatchers.isAssignableFrom(RecyclerView.class)) + .check(matches(hasDescendant(withText(stringContainsInOrder(Arrays.asList( + defaultValue, + suffix)))))); + } + /** * Test ListPreference custom summary logic (Screen Orientation) * Should show "Selected Value. \n ..." (don't check for the 2nd line of the summary) diff --git a/app/src/main/java/net/osmtracker/activity/Preferences.java b/app/src/main/java/net/osmtracker/activity/Preferences.java index 2b9fab0d..8ede5082 100644 --- a/app/src/main/java/net/osmtracker/activity/Preferences.java +++ b/app/src/main/java/net/osmtracker/activity/Preferences.java @@ -4,11 +4,15 @@ import android.content.SharedPreferences; import android.os.Bundle; import android.text.TextUtils; +import android.widget.Button; import android.widget.Toast; import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.FragmentManager; import androidx.preference.EditTextPreference; +import androidx.preference.EditTextPreferenceDialogFragmentCompat; import androidx.preference.ListPreference; import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; @@ -42,6 +46,9 @@ protected void onCreate(Bundle savedInstanceState) { } public static class SettingsFragment extends PreferenceFragmentCompat { + + private static final String EXTRA_DEFAULT_VALUE = "DEFAULT_VALUE"; + @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { setPreferencesFromResource(R.xml.preferences, rootKey); @@ -62,14 +69,16 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { OSMTracker.Preferences.KEY_GPS_LOGGING_INTERVAL, getString(R.string.prefs_gps_logging_interval_seconds), getString(R.string.prefs_gps_logging_interval_summary), - getString(R.string.prefs_gps_logging_interval_empty) + getString(R.string.prefs_gps_logging_interval_empty), + OSMTracker.Preferences.VAL_GPS_LOGGING_INTERVAL ); //GPS Logging Min Distance setupEditTextNum( OSMTracker.Preferences.KEY_GPS_LOGGING_MIN_DISTANCE, getString(R.string.prefs_gps_logging_min_distance_meters), getString(R.string.prefs_gps_logging_min_distance_summary), - getString(R.string.prefs_gps_logging_min_distance_empty) + getString(R.string.prefs_gps_logging_min_distance_empty), + OSMTracker.Preferences.VAL_GPS_LOGGING_MIN_DISTANCE ); @@ -231,12 +240,16 @@ private void setupPreferenceNavigation(String preferenceKey, Intent intent) { * @param valueSuffix appended to the end of the value, shown in the summary * @param summary static summary to be appended to the end of the summary * @param validationError in case of empty value + * @param defaultValue value to be used for the reset button */ private void setupEditTextNum(String preferenceKey, String valueSuffix, String summary, - String validationError) { + String validationError, String defaultValue) { EditTextPreference numInputPref = findPreference(preferenceKey); if (numInputPref == null) return; + // Store default value in Extras so it can be retrieved by the Reset Dialog + numInputPref.getExtras().putString(EXTRA_DEFAULT_VALUE, defaultValue); + // Set input type to number and move cursor to the end numInputPref.setOnBindEditTextListener(editText -> { editText.setInputType(android.text.InputType.TYPE_CLASS_NUMBER); @@ -259,6 +272,58 @@ private void setupEditTextNum(String preferenceKey, String valueSuffix, String s }); } + @SuppressWarnings("deprecation") // Required to link the dialog to the fragment + @Override + public void onDisplayPreferenceDialog(Preference preference) { + + // Retrieve the default value defined in extras. + // If null, it means this preference doesn't support the reset feature. + // Fallback to the default dialog behavior. + String defaultValue = preference.getExtras().getString(EXTRA_DEFAULT_VALUE); + if (defaultValue == null) { + super.onDisplayPreferenceDialog(preference); + return; + } + + // Create the standard dialog fragment + final EditTextPreferenceDialogFragmentCompat dialogFragment = + EditTextPreferenceDialogFragmentCompat.newInstance(preference.getKey()); + dialogFragment.setTargetFragment(this, 0); + dialogFragment.show( + getParentFragmentManager(), + "androidx.preference.PreferenceFragment.DIALOG"); + + // Inject the button after the dialog is shown + getParentFragmentManager().registerFragmentLifecycleCallbacks( + new FragmentManager.FragmentLifecycleCallbacks() { + @Override + public void onFragmentStarted( + @androidx.annotation.NonNull FragmentManager fm, + @androidx.annotation.NonNull androidx.fragment.app.Fragment f) { + if (f == dialogFragment) { + android.app.Dialog dialog = dialogFragment.getDialog(); + if (dialog instanceof androidx.appcompat.app.AlertDialog alertDialog) { + + // Configure the Neutral Button for reset default value + Button btnReset = alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL); + btnReset.setText(R.string.prefs_reset_default_value); + btnReset.setVisibility(android.view.View.VISIBLE); + + btnReset.setOnClickListener(v -> { + if (preference instanceof EditTextPreference) { + ((EditTextPreference) preference).setText(defaultValue); + alertDialog.dismiss(); + } + }); + } + // Cleanup + getParentFragmentManager().unregisterFragmentLifecycleCallbacks(this); + } + } + }, false); + } + + /** * Setup a ListPreference with a custom two lines summary, displays the selected entry * on the first line, and the static summary on the second line. diff --git a/app/src/main/res/values/strings-preferences.xml b/app/src/main/res/values/strings-preferences.xml index 729d97e9..1f68f547 100644 --- a/app/src/main/res/values/strings-preferences.xml +++ b/app/src/main/res/values/strings-preferences.xml @@ -124,4 +124,5 @@ Export compass heading Defines if and how the compass data should be exported to the GPX file + Reset default value