package cgeo.geocaching.ui.dialog;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.ImageUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.Nullable;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.graphics.drawable.Drawable;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.view.ContextThemeWrapper;
import android.view.WindowManager;
import android.widget.EditText;
/**
* Wrapper for {@link AlertDialog}. If you want to show a simple text, use one of the
* {@link #message(Activity, String, String)} variants. If you want the user to confirm using Okay/Cancel or
* Yes/No, select one of the {@link #confirm(Activity, String, String, String, OnClickListener)} or
* {@link #confirmYesNo(Activity, String, String, OnClickListener)} variants.
*
*/
public final class Dialogs {
private Dialogs() {
// utility class
}
/**
* Confirm using two buttons "yourText" and "Cancel", where "Cancel" just closes the dialog.
*
* @param context
* activity hosting the dialog
* @param title
* dialog title
* @param msg
* dialog message
* @param positiveButton
* text of the positive button (which would typically be the OK button)
* @param okayListener
* listener of the positive button
*/
public static AlertDialog.Builder confirm(final Activity context, final String title, final String msg, final String positiveButton, final OnClickListener okayListener) {
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
final AlertDialog dialog = builder.setTitle(title)
.setCancelable(true)
.setMessage(msg)
.setPositiveButton(positiveButton, okayListener)
.setNegativeButton(android.R.string.cancel, null)
.create();
dialog.setOwnerActivity(context);
dialog.show();
return builder;
}
/**
* Confirm using two buttons "yourText" and "Cancel", where "Cancel" just closes the dialog.
*
* @param context
* activity hosting the dialog
* @param title
* dialog title
* @param msg
* dialog message
* @param positiveButton
* text of the positive button (which would typically be the OK button)
* @param okayListener
* listener of the positive button
*/
public static AlertDialog.Builder confirm(final Activity context, final int title, final int msg, final int positiveButton, final OnClickListener okayListener) {
return confirm(context, getString(title), getString(msg), getString(positiveButton), okayListener);
}
/**
* Confirm using two buttons "Yes" and "No", where "No" just closes the dialog.
*
* @param context
* activity hosting the dialog
* @param title
* dialog title
* @param msg
* dialog message
* @param yesListener
* listener of the positive button
*/
public static AlertDialog.Builder confirmYesNo(final Activity context, final String title, final String msg, final OnClickListener yesListener) {
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
final AlertDialog dialog = builder.setTitle(title)
.setCancelable(true)
.setMessage(msg)
.setPositiveButton(android.R.string.yes, yesListener)
.setNegativeButton(android.R.string.no, null)
.create();
dialog.setOwnerActivity(context);
dialog.show();
return builder;
}
/**
* Confirm using two buttons "Yes" and "No", where "No" just closes the dialog.
*
* @param context
* activity hosting the dialog
* @param title
* dialog title
* @param msg
* dialog message
* @param yesListener
* listener of the positive button
*/
public static AlertDialog.Builder confirmYesNo(final Activity context, final String title, final int msg, final OnClickListener yesListener) {
return confirmYesNo(context, title, getString(msg), yesListener);
}
/**
* Confirm using two buttons "Yes" and "No", where "No" just closes the dialog.
*
* @param context
* activity hosting the dialog
* @param title
* dialog title
* @param msg
* dialog message
* @param yesListener
* listener of the positive button
*/
public static AlertDialog.Builder confirmYesNo(final Activity context, final int title, final String msg, final OnClickListener yesListener) {
return confirmYesNo(context, getString(title), msg, yesListener);
}
/**
* Confirm using two buttons "Yes" and "No", where "No" just closes the dialog.
*
* @param context
* activity hosting the dialog
* @param title
* dialog title
* @param msg
* dialog message
* @param yesListener
* listener of the positive button
*/
public static AlertDialog.Builder confirmYesNo(final Activity context, final int title, final int msg, final OnClickListener yesListener) {
return confirmYesNo(context, getString(title), getString(msg), yesListener);
}
/**
* Confirm using two buttons "OK" and "Cancel", where "Cancel" just closes the dialog.
*
* @param context
* activity hosting the dialog
* @param title
* dialog title
* @param msg
* dialog message
* @param okayListener
* listener of the positive button
*/
public static AlertDialog.Builder confirm(final Activity context, final String title, final String msg, final OnClickListener okayListener) {
return confirm(context, title, msg, getString(android.R.string.ok), okayListener);
}
/**
* Confirm using two buttons "OK" and "Cancel", where "Cancel" just closes the dialog.
*
* @param context
* activity hosting the dialog
* @param title
* dialog title
* @param msg
* dialog message
* @param okayListener
* listener of the positive button
*/
public static AlertDialog.Builder confirm(final Activity context, final int title, final String msg, final OnClickListener okayListener) {
return confirm(context, getString(title), msg, okayListener);
}
/**
* Confirm using two buttons "OK" and "Cancel", where "Cancel" just closes the dialog.
*
* @param context
* activity hosting the dialog
* @param title
* dialog title
* @param msg
* dialog message
* @param okayListener
* listener of the positive button
*/
public static AlertDialog.Builder confirm(final Activity context, final int title, final int msg, final OnClickListener okayListener) {
return confirm(context, getString(title), getString(msg), okayListener);
}
private static String getString(final int resourceId) {
return CgeoApplication.getInstance().getString(resourceId);
}
/**
* Show a message dialog with a single "OK" button.
*
* @param context
* activity owning the dialog
* @param message
* message dialog content
*/
public static void message(final Activity context, final String message) {
message(context, null, message);
}
/**
* Show a message dialog with a single "OK" button.
*
* @param context
* activity owning the dialog
* @param message
* message dialog content
*/
public static void message(final Activity context, final int message) {
message(context, null, getString(message));
}
/**
* Show a message dialog with a single "OK" button.
*
* @param context
* activity owning the dialog
* @param title
* message dialog title
* @param message
* message dialog content
*/
public static void message(final Activity context, final @Nullable String title, final String message) {
message(context, title, message, null);
}
/**
* Show a message dialog with a single "OK" button and an eventual icon.
*
* @param context
* activity owning the dialog
* @param title
* message dialog title
* @param message
* message dialog content
* @param iconObservable
* observable (may be null) containing the icon(s) to set
*/
public static void message(final Activity context, final @Nullable String title, final String message, final @Nullable Observable iconObservable) {
final Builder builder = new AlertDialog.Builder(context)
.setMessage(message)
.setCancelable(true)
.setPositiveButton(getString(android.R.string.ok), null);
if (title != null) {
builder.setTitle(title);
}
builder.setIcon(ImageUtils.getTransparent1x1Drawable(context.getResources()));
final AlertDialog dialog = builder.create();
if (iconObservable != null) {
iconObservable.observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1() {
@Override
public void call(final Drawable drawable) {
dialog.setIcon(drawable);
}
});
}
dialog.show();
}
/**
* Show a message dialog with a single "OK" button and an icon.
*
* @param context
* activity owning the dialog
* @param title
* message dialog title
* @param message
* message dialog content
*/
public static void message(final Activity context, final int title, final String message) {
message(context, getString(title), message);
}
/**
* Show a message dialog with a single "OK" button and an icon.
*
* @param context
* activity owning the dialog
* @param title
* message dialog title
* @param message
* message dialog content
*/
public static void message(final Activity context, final int title, final int message) {
message(context, getString(title), getString(message));
}
/**
* Show a message dialog with a single "OK" button and an icon.
*
* @param context
* activity owning the dialog
* @param title
* message dialog title
* @param message
* message dialog content
* @param iconObservable
* message dialog title icon
*/
public static void message(final Activity context, final int title, final int message, final Observable iconObservable) {
message(context, getString(title), getString(message), iconObservable);
}
/**
* Show a message dialog for input from the user. The okay button is only enabled on non empty input.
*
* @param context
* activity owning the dialog
* @param title
* message dialog title
* @param defaultValue
* default input value
* @param buttonTitle
* title of the okay button
* @param okayListener
* listener to be run on okay
*/
public static void input(final Activity context, final int title, final String defaultValue, final int buttonTitle, final Action1 okayListener) {
final Context themedContext;
if (Settings.isLightSkin() && VERSION.SDK_INT < VERSION_CODES.HONEYCOMB) {
themedContext = new ContextThemeWrapper(context, R.style.dark);
} else {
themedContext = context;
}
final EditText input = new EditText(themedContext);
input.setInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_CLASS_TEXT);
input.setText(defaultValue);
final AlertDialog.Builder builder = new AlertDialog.Builder(themedContext);
builder.setTitle(title);
builder.setView(input);
builder.setPositiveButton(buttonTitle, new OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int which) {
okayListener.call(input.getText().toString());
}
});
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int whichButton) {
dialog.dismiss();
}
});
final AlertDialog dialog = builder.create();
input.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
// empty
}
@Override
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
// empty
}
@Override
public void afterTextChanged(final Editable editable) {
enableDialogButtonIfNotEmpty(dialog, editable.toString());
}
});
// force keyboard
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
// disable button
dialog.show();
enableDialogButtonIfNotEmpty(dialog, defaultValue);
moveCursorToEnd(input);
}
/**
* Move the cursor to the end of the input field.
*
* @param input
*/
public static void moveCursorToEnd(final EditText input) {
input.setSelection(input.getText().length(), input.getText().length());
}
private static void enableDialogButtonIfNotEmpty(final AlertDialog dialog, final String input) {
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(StringUtils.isNotBlank(input));
}
}