consp1racy / android-support-preference

Android Preferences according to Material design specs
Apache License 2.0
331 stars 49 forks source link

MultiSelectListPreference: un-/select all #89

Closed rala72 closed 7 months ago

rala72 commented 6 years ago

It would be nice if there is a neutral button to un-/select all entries.

consp1racy commented 6 years ago

It could be controlled by app:showSelectAllButton="true" XML attribute.

Do you have a graphic design in mind?

rala72 commented 6 years ago

not really for me a neutral button (on left) is enough which toggles all

consp1racy commented 6 years ago

Until then you can do this in your project.

  1. Subclass XpMultiSelectListPreferecnceDialogFragment and override onPrepareDialogBuilder. Set the neutral button text and listener on the builder parameter.

  2. Have your fragment/activity implement OnPreferenceDisplayDialogCallback.

@Override
public boolean onPreferenceDisplayDialog(@NonNull final PreferenceFragmentCompat caller, @NonNull final Preference pref) {
    if (pref instanceof net.xpece.android.support.preference.MultiSelectListPreference) {
        final FragmentManager fm = getSupportFragmentManager(); // Or getFragmentManager() in Fragment.
        if (fm.findFragmentByTag("android.support.v7.preference.PreferenceFragment.DIALOG") == null) {
            // Only show a dialog if we're not already showing any dialog.

            final Fragment f = new YourModifiedDialogFragmentFromStep1(); // Replace the name.

            final Bundle b = new Bundle(1);
            b.putString("key", pref.getKey());
            fragment.setArguments(b);

            f.setTargetFragment(caller, 0);
            f.show(fm, "android.support.v7.preference.PreferenceFragment.DIALOG");
            return true;
        }
    }
    return false;
}
rala72 commented 6 years ago

I searched a bit why f.show isn't working until I noticed it should be final DialogFragment f.

update: fragment has to be f

now I get this log:

FATAL EXCEPTION: main
Process: at.my.package, PID: 21722
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.os.Bundle.getString(java.lang.String)' on a null object reference
    at android.support.v7.preference.PreferenceDialogFragmentCompat.onCreate(PreferenceDialogFragmentCompat.java:87)
    at net.xpece.android.support.preference.XpMultiSelectListPreferenceDialogFragment.onCreate(XpMultiSelectListPreferenceDialogFragment.java:103)
    at android.support.v4.app.Fragment.performCreate(Fragment.java:2236)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1285)
    at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1569)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1636)
    at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:758)
    at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2415)
    at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2201)
    at android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(FragmentManager.java:2155)
    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2064)
    at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:718)
    at android.os.Handler.handleCallback(Handler.java:789)
    at android.os.Handler.dispatchMessage(Handler.java:98)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6809)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
consp1racy commented 6 years ago

Sorry, forgot about the preference key, check out the updated code

rala72 commented 6 years ago

It works! =D Thank you very much ;)

Now I've only to figure out how to prevent dismissing the dialog on clicking this button...

Maybe I'll figure it out with sth like this from Stackoverflow

consp1racy commented 6 years ago

Oh yeah, that seems useful :D You can do that in onCreateDialog.

And how to select/deselect the items is also missing. You'll have to

  1. Update tracking variables inside the dialog fragment
boolean mPreferenceChanged;
HashSet<String> mNewValues = new HashSet();
boolean[] mSelectedItems = new boolean[0];

These variables are package-private and you can access them without reflection if your subclass is in the same package.

The logic is best (and only) available in the source code to XpMultiSelectListPreferenceDialogFragment.

  1. Update the list

For that you need to get the list and call setItemChecked with [0..mSelectedItems.length -1].

How you'll get the list? Old text removed. Turns out AlertDialog has a getListView() method. So just cast the dialog and get it.

rala72 commented 6 years ago

to un/-/select all entries I've already this code in my custom MyXpMultiSelectListPreferenceDialogFragment (I use retro-lambda):

@Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
    super.onPrepareDialogBuilder(builder);
    builder.setNeutralButton(R.string.pref_ignoredSubjects_toggleAll, (dialog, which) -> {
        MultiSelectListPreference preference = getMultiSelectListPreference();
        boolean allSelected = true;
        for (CharSequence charSequence : preference.getEntryValues()) {
            if (!preference.getValues().contains(String.valueOf(charSequence))) {
                allSelected = false;
                break;
            }
        }
        if (!allSelected) {
            Set<String> values = Stream.of(preference.getEntryValues()).map(String::valueOf).collect(Collectors.toSet());
            preference.setValues(values);
        } else preference.setValues(new TreeSet<>());
    });
}
consp1racy commented 6 years ago

Here's my current WIP:

https://github.com/consp1racy/android-support-preference/blob/ep-toggle-all/support-preference/src/main/java/net/xpece/android/support/preference/XpMultiSelectListPreferenceDialogFragment.java

What's missing:

rala72 commented 7 months ago

closed because of inactivity