BarInsta/app/src/main/java/awais/instagrabber/dialogs/MultiOptionDialogFragment.java

264 lines
11 KiB
Java

package awais.instagrabber.dialogs;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.util.SparseBooleanArray;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.common.primitives.Booleans;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class MultiOptionDialogFragment<T extends Serializable> extends DialogFragment {
private static final String TAG = MultiOptionDialogFragment.class.getSimpleName();
public enum Type {
MULTIPLE,
SINGLE_CHECKED,
SINGLE
}
private Context context;
private Type type;
private MultiOptionDialogCallback<T> callback;
private MultiOptionDialogSingleCallback<T> singleCallback;
private List<Option<?>> options;
@NonNull
public static <E extends Serializable> MultiOptionDialogFragment<E> newInstance(final int requestCode,
@StringRes final int title,
@NonNull final ArrayList<Option<E>> options) {
return newInstance(requestCode, title, 0, 0, options, Type.SINGLE);
}
@NonNull
public static <E extends Serializable> MultiOptionDialogFragment<E> newInstance(final int requestCode,
@StringRes final int title,
@StringRes final int positiveButtonText,
@StringRes final int negativeButtonText,
@NonNull final ArrayList<Option<E>> options,
@NonNull final Type type) {
Bundle args = new Bundle();
args.putInt("requestCode", requestCode);
args.putInt("title", title);
args.putInt("positiveButtonText", positiveButtonText);
args.putInt("negativeButtonText", negativeButtonText);
args.putSerializable("options", options);
args.putSerializable("type", type);
MultiOptionDialogFragment<E> fragment = new MultiOptionDialogFragment<>();
fragment.setArguments(args);
return fragment;
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public void onAttach(@NonNull final Context context) {
super.onAttach(context);
this.context = context;
final Fragment parentFragment = getParentFragment();
if (parentFragment != null) {
if (parentFragment instanceof MultiOptionDialogCallback) {
callback = (MultiOptionDialogCallback) parentFragment;
}
if (parentFragment instanceof MultiOptionDialogSingleCallback) {
singleCallback = (MultiOptionDialogSingleCallback) parentFragment;
}
return;
}
final FragmentActivity fragmentActivity = getActivity();
if (fragmentActivity instanceof MultiOptionDialogCallback) {
callback = (MultiOptionDialogCallback) fragmentActivity;
}
if (fragmentActivity instanceof MultiOptionDialogSingleCallback) {
singleCallback = (MultiOptionDialogSingleCallback) fragmentActivity;
}
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Bundle arguments = getArguments();
int title = 0;
int rc = 0;
if (arguments != null) {
rc = arguments.getInt("requestCode");
title = arguments.getInt("title");
type = (Type) arguments.getSerializable("type");
}
final int requestCode = rc;
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context);
if (title != 0) {
builder.setTitle(title);
}
try {
//noinspection unchecked
options = arguments != null ? (List<Option<?>>) arguments.getSerializable("options")
: Collections.emptyList();
} catch (Exception e) {
Log.e(TAG, "onCreateDialog: ", e);
options = Collections.emptyList();
}
final int negativeButtonText = arguments != null ? arguments.getInt("negativeButtonText", -1) : -1;
if (negativeButtonText > 0) {
builder.setNegativeButton(negativeButtonText, (dialog, which) -> {
if (callback != null) {
callback.onCancel(requestCode);
return;
}
if (singleCallback != null) {
singleCallback.onCancel(requestCode);
}
});
}
if (type == Type.MULTIPLE || type == Type.SINGLE_CHECKED) {
final int positiveButtonText = arguments != null ? arguments.getInt("positiveButtonText", -1) : -1;
if (positiveButtonText > 0) {
builder.setPositiveButton(positiveButtonText, (dialog, which) -> {
if (callback == null || options == null || options.isEmpty()) return;
try {
final List<T> selected = new ArrayList<>();
final SparseBooleanArray checkedItemPositions = ((AlertDialog) dialog).getListView().getCheckedItemPositions();
for (int i = 0; i < checkedItemPositions.size(); i++) {
final int position = checkedItemPositions.keyAt(i);
final boolean checked = checkedItemPositions.get(position);
if (!checked) continue;
//noinspection unchecked
final Option<T> option = (Option<T>) options.get(position);
selected.add(option.value);
}
callback.onMultipleSelect(requestCode, selected);
} catch (Exception e) {
Log.e(TAG, "onCreateDialog: ", e);
}
});
}
}
if (type == Type.MULTIPLE) {
if (options != null && !options.isEmpty()) {
final String[] items = options.stream()
.map(option -> option.label)
.toArray(String[]::new);
final boolean[] checkedItems = Booleans.toArray(options.stream()
.map(option -> option.checked)
.collect(Collectors.toList()));
builder.setMultiChoiceItems(items, checkedItems, (dialog, which, isChecked) -> {
if (callback == null) return;
try {
final Option<?> option = options.get(which);
//noinspection unchecked
callback.onCheckChange(requestCode, (T) option.value, isChecked);
} catch (Exception e) {
Log.e(TAG, "onCreateDialog: ", e);
}
});
}
} else {
if (options != null && !options.isEmpty()) {
final String[] items = options.stream()
.map(option -> option.label)
.toArray(String[]::new);
if (type == Type.SINGLE_CHECKED) {
int index = -1;
for (int i = 0; i < options.size(); i++) {
if (options.get(i).checked) {
index = i;
break;
}
}
builder.setSingleChoiceItems(items, index, (dialog, which) -> {
if (callback == null) return;
try {
final Option<?> option = options.get(which);
//noinspection unchecked
callback.onCheckChange(requestCode, (T) option.value, true);
} catch (Exception e) {
Log.e(TAG, "onCreateDialog: ", e);
}
});
} else if (type == Type.SINGLE) {
builder.setItems(items, (dialog, which) -> {
if (singleCallback == null) return;
try {
final Option<?> option = options.get(which);
//noinspection unchecked
singleCallback.onSelect(requestCode, (T) option.value);
} catch (Exception e) {
Log.e(TAG, "onCreateDialog: ", e);
}
});
}
}
}
return builder.create();
}
public void setCallback(final MultiOptionDialogCallback<T> callback) {
if (callback == null) return;
this.callback = callback;
}
public void setSingleCallback(final MultiOptionDialogSingleCallback<T> callback) {
if (callback == null) return;
this.singleCallback = callback;
}
public interface MultiOptionDialogCallback<T> {
void onSelect(int requestCode, T result);
void onMultipleSelect(int requestCode, List<T> result);
void onCheckChange(int requestCode, T item, boolean isChecked);
void onCancel(int requestCode);
}
public interface MultiOptionDialogSingleCallback<T> {
void onSelect(int requestCode, T result);
void onCancel(int requestCode);
}
public static class Option<T extends Serializable> implements Serializable {
private final String label;
private final T value;
private final boolean checked;
public Option(final String label, final T value) {
this.label = label;
this.value = value;
this.checked = false;
}
public Option(final String label, final T value, final boolean checked) {
this.label = label;
this.value = value;
this.checked = checked;
}
public String getLabel() {
return label;
}
public T getValue() {
return value;
}
public boolean isChecked() {
return checked;
}
}
}