fixed spinner infinite loop in appointments

This commit is contained in:
Alex
2026-04-09 02:48:55 -06:00
parent 8fa74240bc
commit 4b8e0b2868
3 changed files with 69 additions and 19 deletions

View File

@@ -10,6 +10,7 @@ import com.example.petstoremobile.adapters.BlackTextArrayAdapter;
import com.example.petstoremobile.adapters.WhiteTextArrayAdapter; import com.example.petstoremobile.adapters.WhiteTextArrayAdapter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -51,6 +52,12 @@ public class SpinnerUtils {
names.add(nameExtractor.apply(item)); names.add(nameExtractor.apply(item));
} }
// Only update adapter if contents changed to remove infinite loop when spinner is opened
if (isAdapterDataSame(spinner, names)) {
setSelectedId(spinner, data, defaultText, preselectedId, idExtractor);
return;
}
ArrayAdapter<String> adapter; ArrayAdapter<String> adapter;
if (useWhiteText) { if (useWhiteText) {
adapter = new WhiteTextArrayAdapter<>(context, android.R.layout.simple_spinner_item, names); adapter = new WhiteTextArrayAdapter<>(context, android.R.layout.simple_spinner_item, names);
@@ -61,26 +68,41 @@ public class SpinnerUtils {
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter); spinner.setAdapter(adapter);
setSelectedId(spinner, data, defaultText, preselectedId, idExtractor);
}
private static <T> void setSelectedId(Spinner spinner, List<T> data, String defaultText, Long preselectedId, Function<T, Long> idExtractor) {
if (preselectedId != null && preselectedId != -1) { if (preselectedId != null && preselectedId != -1) {
int offset = (defaultText != null) ? 1 : 0; int offset = (defaultText != null) ? 1 : 0;
for (int i = 0; i < data.size(); i++) { for (int i = 0; i < data.size(); i++) {
Long currentId = idExtractor.apply(data.get(i)); Long currentId = idExtractor.apply(data.get(i));
if (Objects.equals(currentId, preselectedId)) { if (Objects.equals(currentId, preselectedId)) {
spinner.setSelection(i + offset); if (spinner.getSelectedItemPosition() != i + offset) {
spinner.setSelection(i + offset);
}
break; break;
} }
} }
} }
} }
/**
* Checks if the adapter data is the same as the new data.
*/
private static boolean isAdapterDataSame(Spinner spinner, List<String> newNames) {
if (spinner.getAdapter() == null) return false;
if (spinner.getAdapter().getCount() != newNames.size()) return false;
for (int i = 0; i < newNames.size(); i++) {
if (!Objects.equals(spinner.getAdapter().getItem(i), newNames.get(i))) return false;
}
return true;
}
/** /**
* Sets up a simple string spinner for filtering with a callback. * Sets up a simple string spinner for filtering with a callback.
*/ */
public static void setupStringFilterSpinner(Context context, Spinner spinner, String[] items, Runnable onSelectionChanged) { public static void setupStringFilterSpinner(Context context, Spinner spinner, String[] items, Runnable onSelectionChanged) {
WhiteTextArrayAdapter<String> adapter = new WhiteTextArrayAdapter<>(context, updateStringSpinnerIfChanged(context, spinner, items, true);
android.R.layout.simple_spinner_item, items);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
setupFilterSpinner(spinner, onSelectionChanged); setupFilterSpinner(spinner, onSelectionChanged);
} }
@@ -111,7 +133,7 @@ public class SpinnerUtils {
if (value == null || spinner.getAdapter() == null) return; if (value == null || spinner.getAdapter() == null) return;
ArrayAdapter<String> adapter = (ArrayAdapter<String>) spinner.getAdapter(); ArrayAdapter<String> adapter = (ArrayAdapter<String>) spinner.getAdapter();
int pos = adapter.getPosition(value); int pos = adapter.getPosition(value);
if (pos >= 0) { if (pos >= 0 && spinner.getSelectedItemPosition() != pos) {
spinner.setSelection(pos); spinner.setSelection(pos);
} }
} }
@@ -123,7 +145,9 @@ public class SpinnerUtils {
if (spinner == null || array == null || value == null) return; if (spinner == null || array == null || value == null) return;
for (int i = 0; i < array.length; i++) { for (int i = 0; i < array.length; i++) {
if (Objects.equals(array[i], value)) { if (Objects.equals(array[i], value)) {
spinner.setSelection(i); if (spinner.getSelectedItemPosition() != i) {
spinner.setSelection(i);
}
return; return;
} }
} }
@@ -133,8 +157,21 @@ public class SpinnerUtils {
* Configures a simple string array spinner. * Configures a simple string array spinner.
*/ */
public static void setupStringSpinner(Context context, Spinner spinner, String[] items) { public static void setupStringSpinner(Context context, Spinner spinner, String[] items) {
BlackTextArrayAdapter<String> adapter = new BlackTextArrayAdapter<>(context, updateStringSpinnerIfChanged(context, spinner, items, false);
android.R.layout.simple_spinner_item, items); }
/**
* Updates a string spinner only if the items have changed.
*/
public static void updateStringSpinnerIfChanged(Context context, Spinner spinner, String[] items, boolean useWhiteText) {
if (isAdapterDataSame(spinner, Arrays.asList(items))) return;
ArrayAdapter<String> adapter;
if (useWhiteText) {
adapter = new WhiteTextArrayAdapter<>(context, android.R.layout.simple_spinner_item, items);
} else {
adapter = new BlackTextArrayAdapter<>(context, android.R.layout.simple_spinner_item, items);
}
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter); spinner.setAdapter(adapter);
} }

View File

@@ -73,36 +73,49 @@ public class UIUtils {
} }
/** /**
* Sets the enabled state and alpha for multiple views. * Sets the enabled state and alpha for multiple views, only if changed.
*/ */
public static void setViewsEnabled(boolean enabled, View... views) { public static void setViewsEnabled(boolean enabled, View... views) {
for (View v : views) { for (View v : views) {
if (v != null) { if (v != null) {
v.setEnabled(enabled); if (v.isEnabled() != enabled) {
v.setAlpha(enabled ? 1.0f : 0.5f); v.setEnabled(enabled);
}
float targetAlpha = enabled ? 1.0f : 0.5f;
if (Math.abs(v.getAlpha() - targetAlpha) > 0.01f) {
v.setAlpha(targetAlpha);
}
} }
} }
} }
/** /**
* Sets enabled state for a field and updates alpha for both the field and its label. * Sets enabled state for a field and updates alpha for both the field and its label, only if changed.
*/ */
public static void setFieldEnabled(boolean enabled, View field, View label) { public static void setFieldEnabled(boolean enabled, View field, View label) {
if (field != null) { if (field != null) {
field.setEnabled(enabled); if (field.isEnabled() != enabled) {
field.setAlpha(enabled ? 1.0f : 0.5f); field.setEnabled(enabled);
}
float targetAlpha = enabled ? 1.0f : 0.5f;
if (Math.abs(field.getAlpha() - targetAlpha) > 0.01f) {
field.setAlpha(targetAlpha);
}
} }
if (label != null) { if (label != null) {
label.setAlpha(enabled ? 1.0f : 0.5f); float targetAlpha = enabled ? 1.0f : 0.5f;
if (Math.abs(label.getAlpha() - targetAlpha) > 0.01f) {
label.setAlpha(targetAlpha);
}
} }
} }
/** /**
* Sets the alpha for multiple views. * Sets the alpha for multiple views, only if changed.
*/ */
public static void setViewsAlpha(float alpha, View... views) { public static void setViewsAlpha(float alpha, View... views) {
for (View v : views) { for (View v : views) {
if (v != null) { if (v != null && Math.abs(v.getAlpha() - alpha) > 0.01f) {
v.setAlpha(alpha); v.setAlpha(alpha);
} }
} }