1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-06-19 11:30:44 +02:00
Gadgetbridge/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsUtils.java
2024-01-10 19:01:48 +01:00

213 lines
8.0 KiB
Java

/* Copyright (C) 2023-2024 José Rebelo
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.activities.devicesettings;
import android.text.InputFilter;
import android.text.InputType;
import android.text.Spanned;
import androidx.preference.EditTextPreference;
import androidx.preference.ListPreference;
import androidx.preference.MultiSelectListPreference;
import androidx.preference.Preference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public final class DeviceSettingsUtils {
private static final Logger LOG = LoggerFactory.getLogger(DeviceSettingsUtils.class);
private DeviceSettingsUtils() {
// utility class
}
/**
* Returns the preference key where to save the list of possible value for a preference, comma-separated.
*/
public static String getPrefPossibleValuesKey(final String key) {
return String.format(Locale.ROOT, "%s_possible_values", key);
}
/**
* Returns the preference key where to save the list of entry labels for a preference, comma-separated.
*/
public static String getPrefPossibleValueLabelsKey(final String key) {
return String.format(Locale.ROOT, "%s_possible_value_labels", key);
}
/**
* Returns the preference key where to that a config was reported as supported (boolean).
*/
public static String getPrefKnownConfig(final String key) {
return String.format(Locale.ROOT, "%s_is_known", key);
}
/**
* Populates a list preference, or hides it if no known supported values are known.
*/
public static void populateOrHideListPreference(final String prefKey,
final DeviceSpecificSettingsHandler handler,
final Prefs prefs) {
final Preference pref = handler.findPreference(prefKey);
if (pref == null) {
return;
}
// Get the list of possible values for this preference, as reported by the band
final List<String> possibleValues = prefs.getList(getPrefPossibleValuesKey(prefKey), null);
if (possibleValues == null || possibleValues.isEmpty()) {
// The band hasn't reported this setting, so we don't know the possible values.
// Hide it
pref.setVisible(false);
return;
}
final CharSequence[] originalEntries;
final CharSequence[] originalValues;
if (pref instanceof ListPreference) {
originalEntries = ((ListPreference) pref).getEntries();
originalValues = ((ListPreference) pref).getEntryValues();
} else if (pref instanceof MultiSelectListPreference) {
originalEntries = ((MultiSelectListPreference) pref).getEntries();
originalValues = ((MultiSelectListPreference) pref).getEntryValues();
} else {
LOG.error("Unknown list pref class {}", pref.getClass().getName());
return;
}
final Map<CharSequence, CharSequence> entryNames = new HashMap<>();
final List<String> knownLabels = prefs.getList(getPrefPossibleValueLabelsKey(prefKey), null);
if (knownLabels != null) {
// We got some known labels from the watch
if (knownLabels.size() != possibleValues.size()) {
LOG.warn(
"Number of possible values ({}) and labels ({}) for {} differs - this should never happen",
possibleValues.size(),
knownLabels.size(),
prefKey
);
// Abort and hide preference - we can't safely recover from this
pref.setVisible(false);
return;
}
for (int i = 0; i < knownLabels.size(); i++) {
entryNames.put(possibleValues.get(i), knownLabels.get(i));
}
} else {
for (int i = 0; i < originalEntries.length; i++) {
entryNames.put(originalValues[i], originalEntries[i]);
}
}
final CharSequence[] entries = new CharSequence[possibleValues.size()];
final CharSequence[] values = new CharSequence[possibleValues.size()];
for (int i = 0; i < possibleValues.size(); i++) {
final String possibleValue = possibleValues.get(i);
final CharSequence knownLabel = entryNames.get(possibleValue);
if (knownLabel != null) {
entries[i] = knownLabel;
} else {
entries[i] = handler.getContext().getString(R.string.menuitem_unknown_app, possibleValue);
}
values[i] = possibleValue;
}
if (pref instanceof ListPreference) {
((ListPreference) pref).setEntries(entries);
((ListPreference) pref).setEntryValues(values);
} else if (pref instanceof MultiSelectListPreference) {
((MultiSelectListPreference) pref).setEntries(entries);
((MultiSelectListPreference) pref).setEntryValues(values);
}
}
/**
* Hides the the prefToHide preference if none of the preferences in the preferences list are
* visible.
*/
public static void hidePrefIfNoneVisible(final DeviceSpecificSettingsHandler handler,
final String prefToHide,
final List<String> subPrefs) {
final Preference pref = handler.findPreference(prefToHide);
if (pref == null) {
return;
}
for (final String subPrefKey : subPrefs) {
final Preference subPref = handler.findPreference(subPrefKey);
if (subPref == null) {
continue;
}
if (subPref.isVisible()) {
// At least one preference is visible
return;
}
}
// No preference was visible, hide
pref.setVisible(false);
}
public static void enforceMinMax(final EditTextPreference pref, final int minValue, final int maxValue) {
if (minValue >= maxValue) {
LOG.warn("Invalid min/max values for {}: {}/{}", pref.getKey(), minValue, maxValue);
return;
}
pref.setOnBindEditTextListener(p -> {
p.setInputType(InputType.TYPE_CLASS_NUMBER);
p.setFilters(new InputFilter[]{new MinMaxInputFilter(minValue, maxValue)});
p.setSelection(p.getText().length());
});
}
public static final class MinMaxInputFilter implements InputFilter {
private final int min;
private final int max;
public MinMaxInputFilter(final int min, final int max) {
this.min = min;
this.max = max;
}
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
try {
final int input = Integer.parseInt(dest.toString() + source.toString());
if (input >= min && input <= max) {
return null;
}
} catch (final NumberFormatException ignored) {
}
return "";
}
}
}