package com.vaguehope.onosendai.util; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnMultiChoiceClickListener; import android.text.InputType; import android.view.WindowManager.BadTokenException; import android.view.inputmethod.EditorInfo; import android.widget.EditText; import com.vaguehope.onosendai.R; import com.vaguehope.onosendai.util.CollectionHelper.Function; public final class DialogHelper { public interface Listener<T> { void onAnswer (T answer); } public interface Question<T> { boolean ask (T arg); } private DialogHelper () { throw new AssertionError(); } public static void alert (final Context context, final Throwable t) { alert(context, context.getString(R.string.dialog_general_error), t); } public static void alert (final Context context, final String msg, final Throwable t) { alert(context, msg + "\n" + ExcpetionHelper.causeTrace(t)); } public static void alertIfPossible (final Context context, final String msg, final Exception e) { try { alert(context, msg, e); } catch (BadTokenException ignored) {/* If the UI context is no longer valid. */} // NOSONAR exception intentionally ignored. } public static void alert (final Context context, final String msg) { alertAndRun(context, msg, null); } public static void alertAndRun (final Context context, final String msg, final Runnable run) { new AlertDialog.Builder(context) .setMessage(msg) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick (final DialogInterface dialog, final int which) { dialog.dismiss(); if (run != null) run.run(); } }) .show(); } public static void alertAndClose (final Activity activity, final Exception e) { alertAndClose(activity, "Error:", e); } public static void alertAndClose (final Activity activity, final String msg, final Exception e) { alertAndClose(activity, msg + "\n" + ExcpetionHelper.causeTrace(e)); } public static void alertAndClose (final Activity activity, final String msg) { alertAndRun(activity, msg, new Runnable() { @Override public void run () { activity.finish(); } }); } public static void askYesNo (final Context context, final String msg, final Runnable onYes) { askYesNo(context, msg, context.getString(R.string.dialog_general_btn_yes), context.getString(R.string.dialog_general_btn_no), onYes); } public static void askYesNo (final Context context, final String msg, final String yesLbl, final String noLbl, final Runnable onYes) { askYesNo(context, msg, yesLbl, noLbl, onYes, null); } public static void askYesNo (final Context context, final String msg, final String yesLbl, final String noLbl, final Runnable onYes, final Runnable onNo) { final AlertDialog.Builder dlgBld = new AlertDialog.Builder(context); dlgBld.setMessage(msg); dlgBld.setPositiveButton(yesLbl, new DialogInterface.OnClickListener() { @Override public void onClick (final DialogInterface dialog, final int which) { dialog.dismiss(); onYes.run(); } }); if (onNo != null) { dlgBld.setNegativeButton(noLbl, new DialogInterface.OnClickListener() { @Override public void onClick (final DialogInterface dialog, final int which) { dialog.cancel(); onNo.run(); } }); } else { dlgBld.setNegativeButton(noLbl, DLG_CANCEL_CLICK_LISTENER); } dlgBld.show(); } public static void askString (final Context context, final String msg, final Listener<String> onString) { askString(context, msg, null, false, true, onString); } // FIXME tidy this method signature. public static void askString (final Context context, final String msg, final String oldValue, final boolean multiLine, final boolean spellCheck, final Listener<String> onString) { final AlertDialog.Builder dlgBld = new AlertDialog.Builder(context); dlgBld.setMessage(msg); final EditText editText = new EditText(context); editText.setSelectAllOnFocus(true); if (oldValue != null) editText.setText(oldValue); if (!multiLine) editText.setSingleLine(); if (!spellCheck) editText.setInputType(editText.getInputType() | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); editText.setImeOptions(EditorInfo.IME_ACTION_DONE); dlgBld.setView(editText); dlgBld.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick (final DialogInterface dialog, final int which) { dialog.dismiss(); onString.onAnswer(editText.getText().toString().trim()); } }); dlgBld.setNegativeButton(android.R.string.cancel, DLG_CANCEL_CLICK_LISTENER); dlgBld.show(); } public static void askStringItem (final Context context, final String title, final List<String> list, final Listener<String> onItem) { askItem(context, title, list, list.toArray(new String[] {}), onItem); } public static <T extends Titleable> void askItem (final Context context, final String title, final T[] arr, final Listener<T> onItem) { askItem(context, title, Arrays.asList(arr), onItem); } public static <T extends Titleable> void askItem (final Context context, final String title, final List<T> list, final Listener<T> onItem) { final List<String> titles = titlesList(list); askItem(context, title, list, titles.toArray(new String[] {}), onItem); } public static <T> void askItem (final Context context, final String title, final T[] arr, final Function<T, String> titler, final Listener<T> onItem) { askItem(context, title, Arrays.asList(arr), titler, onItem); } public static <T> void askItem (final Context context, final String title, final List<T> list, final Function<T, String> titler, final Listener<T> onItem) { final List<String> titles = titlesList(list, titler); askItem(context, title, list, titles.toArray(new String[] {}), onItem); } private static <T> void askItem (final Context context, final String title, final List<T> list, final String[] labels, final Listener<T> onItem) { final AlertDialog.Builder bld = new AlertDialog.Builder(context); bld.setTitle(title); bld.setNegativeButton(android.R.string.cancel, DialogHelper.DLG_CANCEL_CLICK_LISTENER); bld.setItems(labels, new SimpleAnswerListener<T>(list, onItem)); bld.show(); } public static <T extends Titleable> void askItems (final Context context, final String title, final List<T> list, final Listener<Set<T>> onItem) { askItems(context, title, list, null, onItem); } public static <T extends Titleable> void askItems (final Context context, final String title, final List<T> list, final Question<T> isChecked, final Listener<Set<T>> onItem) { final List<String> titles = new ArrayList<String>(); for (final T item : list) { titles.add(item.getUiTitle()); } boolean[] arrChecked = null; if (isChecked != null) { arrChecked = new boolean[list.size()]; for (int i = 0; i < list.size(); i++) { arrChecked[i] = isChecked.ask(list.get(i)); } } askItems(context, title, list, titles.toArray(new String[] {}), arrChecked, onItem); } private static <T> void askItems (final Context context, final String title, final List<T> list, final String[] labels, final boolean[] checked, final Listener<Set<T>> onItems) { if (labels.length != list.size()) throw new IllegalArgumentException("List and titles array must be same length."); if (checked != null && checked.length != list.size()) throw new IllegalArgumentException("List and checed array must be same length."); final AlertDialog.Builder bld = new AlertDialog.Builder(context); bld.setTitle(title); bld.setNegativeButton(android.R.string.cancel, DialogHelper.DLG_CANCEL_CLICK_LISTENER); final Set<T> selectedItems = new HashSet<T>(); if (checked != null) { for (int i = 0; i < list.size(); i++) { if (checked[i]) selectedItems.add(list.get(i)); } } bld.setMultiChoiceItems(labels, checked, new OnMultiChoiceClickListener() { @Override public void onClick (final DialogInterface dialog, final int which, final boolean isChecked) { final T item = list.get(which); if (isChecked) { selectedItems.add(item); } else { selectedItems.remove(item); } } }); bld.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick (final DialogInterface dialog, final int which) { dialog.dismiss(); onItems.onAnswer(selectedItems); } }); bld.show(); } public static final DialogInterface.OnClickListener DLG_CANCEL_CLICK_LISTENER = new DialogInterface.OnClickListener() { @Override public void onClick (final DialogInterface dialog, final int whichButton) { dialog.cancel(); } }; public static class SimpleAnswerListener<T> implements DialogInterface.OnClickListener { private final List<T> items; private final Listener<T> onAnswer; public SimpleAnswerListener (final List<T> items, final Listener<T> onAnswer) { this.items = items; this.onAnswer = onAnswer; } @Override public void onClick (final DialogInterface dialog, final int which) { dialog.dismiss(); this.onAnswer.onAnswer(this.items.get(which)); } } private static <T extends Titleable> List<String> titlesList (final List<T> list) { final List<String> titles = new ArrayList<String>(); for (final T item : list) { titles.add(item.getUiTitle()); } return titles; } private static <T> List<String> titlesList (final List<T> list, final Function<T, String> titler) { final List<String> titles = new ArrayList<String>(); for (final T item : list) { titles.add(titler.exec(item)); } return titles; } }