Browse Source

Added built in input dialog

Aidan Follestad 10 years ago
parent
commit
1ccca94bd0

+ 31 - 2
README.md

@@ -250,7 +250,7 @@ every time the user selects an item.
 Like action buttons and many other elements of the Material dialog, you can customize the color of a 
  dialog's radio buttons. The `Builder` class contains a `widgetColor()`, `widgetColorRes()`,
  and `widgetColorAttr()` method. Their names and parameter annotations make them self explanatory.
- Note that by default, check boxes will be colored with the color held in `colorAccent` (for AppCompat)
+ Note that by default, radio buttons will be colored with the color held in `colorAccent` (for AppCompat)
  or `android:colorAccent` (for the Material theme) in your Activity's theme.
  
 There's also a global theming attribute as shown in the Global Theming section of this README: `md_widget_color`.
@@ -708,6 +708,35 @@ new MaterialDialog.Builder(this)
 
 ---
 
+### Input Dialogs
+
+An input dialog is pretty self explanatory, it retrieves input from the user of your application with
+an input field (EditText). You can also display content above the EditText if you desire.
+
+```java
+new MaterialDialog.Builder(this)
+        .title(R.string.input)
+        .content(R.string.input_content)
+        .input(R.string.input_hint, R.string.input_prefill, new MaterialDialog.InputCallback() {
+            @Override
+            public void onInput(MaterialDialog dialog, CharSequence input) {
+                // Do something
+            }
+        }).show();
+```
+
+###### Coloring the EditText
+
+Like action buttons and many other elements of the Material dialog, you can customize the color of a
+ input dialog's `EditText`. The `Builder` class contains a `widgetColor()`, `widgetColorRes()`,
+ and `widgetColorAttr()` method. Their names and parameter annotations make them self explanatory.
+ Note that by default, EditTexts will be colored with the color held in `colorAccent` (for AppCompat)
+ or `android:colorAccent` (for the Material theme) in your Activity's theme.
+
+There's also a global theming attribute as shown in the Global Theming section of this README: `md_widget_color`.
+
+---
+
 ### Progress Dialogs
 
 This library allows you to display progress dialogs with Material design that even use your app's
@@ -765,7 +794,7 @@ See the sample project for this dialog in action, with the addition of threading
 Like action buttons and many other elements of the Material dialog, you can customize the color of a 
  progress dialog's progress bar. The `Builder` class contains a `widgetColor()`, `widgetColorRes()`,
  and `widgetColorAttr()` method. Their names and parameter annotations make them self explanatory.
- Note that by default, check boxes will be colored with the color held in `colorAccent` (for AppCompat)
+ Note that by default, progress bars will be colored with the color held in `colorAccent` (for AppCompat)
  or `android:colorAccent` (for the Material theme) in your Activity's theme.
  
 There's also a global theming attribute as shown in the Global Theming section of this README: `md_widget_color`.

+ 84 - 8
library/src/main/java/com/afollestad/materialdialogs/DialogInit.java

@@ -1,16 +1,19 @@
 package com.afollestad.materialdialogs;
 
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Color;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.text.method.LinkMovementMethod;
 import android.view.ContextThemeWrapper;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
 import android.widget.EditText;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
@@ -53,10 +56,12 @@ class DialogInit {
             return R.layout.md_dialog_custom;
         } else if (builder.items != null && builder.items.length > 0 || builder.adapter != null) {
             return R.layout.md_dialog_list;
-        } else if (builder.mProgress > -2) {
+        } else if (builder.progress > -2) {
             return R.layout.md_dialog_progress;
-        } else if (builder.mIndeterminateProgress) {
+        } else if (builder.indeterminateProgress) {
             return R.layout.md_dialog_progress_indeterminate;
+        } else if (builder.inputCallback != null) {
+            return R.layout.md_dialog_input;
         } else {
             return R.layout.md_dialog_basic;
         }
@@ -120,6 +125,9 @@ class DialogInit {
         dialog.neutralButton = (MDButton) dialog.view.findViewById(R.id.buttonDefaultNeutral);
         dialog.negativeButton = (MDButton) dialog.view.findViewById(R.id.buttonDefaultNegative);
 
+        if (builder.inputCallback != null && builder.positiveText == null)
+            builder.positiveText = builder.context.getString(android.R.string.ok);
+
         // Set up the initial visibility of action buttons based on whether or not text was set
         dialog.positiveButton.setVisibility(builder.positiveText != null ? View.VISIBLE : View.GONE);
         dialog.neutralButton.setVisibility(builder.neutralText != null ? View.VISIBLE : View.GONE);
@@ -204,6 +212,7 @@ class DialogInit {
         } else {
             textAllCaps = DialogUtils.resolveBoolean(builder.context, R.attr.textAllCaps, true);
         }
+
         if (dialog.positiveButton != null && builder.positiveText != null) {
             MDButton positiveTextView = dialog.positiveButton;
             dialog.setTypeface(positiveTextView, builder.mediumFont);
@@ -280,6 +289,10 @@ class DialogInit {
         // Setup progress dialog stuff if needed
         setupProgressDialog(dialog);
 
+        // Setup inputu dialog stuff if needed
+        setupInputDialog(dialog);
+
+        // Setup custom views
         if (builder.customView != null) {
             FrameLayout frame = (FrameLayout) dialog.view.findViewById(R.id.customViewFrame);
             dialog.customViewFrame = frame;
@@ -329,18 +342,19 @@ class DialogInit {
 
     private static void setupProgressDialog(final MaterialDialog dialog) {
         final MaterialDialog.Builder builder = dialog.mBuilder;
-        if (builder.mIndeterminateProgress || builder.mProgress > -2) {
+        if (builder.indeterminateProgress || builder.progress > -2) {
             dialog.mProgress = (MDProgressBar) dialog.view.findViewById(android.R.id.progress);
+            if (dialog.mProgress == null) return;
             dialog.mProgress.setColorFilter(builder.widgetColor);
 
-            if (!builder.mIndeterminateProgress) {
+            if (!builder.indeterminateProgress) {
                 dialog.mProgress.setProgress(0);
-                dialog.mProgress.setMax(builder.mProgressMax);
+                dialog.mProgress.setMax(builder.progressMax);
                 dialog.mProgressLabel = (TextView) dialog.view.findViewById(R.id.label);
                 dialog.mProgressMinMax = (TextView) dialog.view.findViewById(R.id.minMax);
-                if (builder.mShowMinMax) {
+                if (builder.showMinMax) {
                     dialog.mProgressMinMax.setVisibility(View.VISIBLE);
-                    dialog.mProgressMinMax.setText("0/" + builder.mProgressMax);
+                    dialog.mProgressMinMax.setText("0/" + builder.progressMax);
                     ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) dialog.mProgress.getLayoutParams();
                     lp.leftMargin = 0;
                     lp.rightMargin = 0;
@@ -349,10 +363,72 @@ class DialogInit {
                 }
                 dialog.mProgressLabel.setText("0%");
             }
-
         }
     }
 
+    private static void setupInputDialog(final MaterialDialog dialog) {
+        final MaterialDialog.Builder builder = dialog.mBuilder;
+        dialog.input = (EditText) dialog.view.findViewById(android.R.id.input);
+        if (dialog.input == null) return;
+        if (builder.inputPrefill != null)
+            dialog.input.append(builder.inputPrefill);
+        dialog.input.setHint(builder.inputHint);
+        dialog.input.setSingleLine();
+
+        dialog.setOnShowListener(new DialogInterface.OnShowListener() {
+            @Override
+            public void onShow(DialogInterface di) {
+                final MaterialDialog dialog = (MaterialDialog) di;
+                if (dialog.getInputEditText() == null) return;
+                dialog.getInputEditText().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        dialog.getInputEditText().requestFocus();
+                        InputMethodManager imm = (InputMethodManager) builder.context.getSystemService(Context.INPUT_METHOD_SERVICE);
+                        if (imm != null)
+                            imm.showSoftInput(dialog.getInputEditText(), InputMethodManager.SHOW_IMPLICIT);
+                    }
+                });
+            }
+        });
+        dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+            @Override
+            public void onCancel(DialogInterface di) {
+                final MaterialDialog dialog = (MaterialDialog) di;
+                if (dialog.getInputEditText() == null) return;
+                dialog.getInputEditText().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        dialog.getInputEditText().requestFocus();
+                        InputMethodManager imm = (InputMethodManager) builder.context.getSystemService(Context.INPUT_METHOD_SERVICE);
+                        imm.hideSoftInputFromWindow(dialog.getInputEditText().getWindowToken(), 0);
+                    }
+                });
+            }
+        });
+        dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
+            @Override
+            public void onDismiss(DialogInterface di) {
+                final MaterialDialog dialog = (MaterialDialog) di;
+                if (dialog.getInputEditText() == null) return;
+                dialog.getInputEditText().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        dialog.getInputEditText().requestFocus();
+                        InputMethodManager imm = (InputMethodManager) builder.context.getSystemService(Context.INPUT_METHOD_SERVICE);
+                        if (imm != null)
+                            imm.hideSoftInputFromWindow(dialog.getInputEditText().getWindowToken(), 0);
+                    }
+                });
+            }
+        });
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
+            dialog.input.setBackgroundTintList(ColorStateList.valueOf(builder.widgetColor));
+        else if (dialog.input.getBackground() != null)
+            dialog.input.getBackground().setColorFilter(builder.widgetColor, PorterDuff.Mode.SRC_IN);
+    }
+
     private static ColorStateList getActionTextStateList(Context context, int newPrimaryColor) {
         final int fallBackButtonColor = DialogUtils.resolveColor(context, android.R.attr.textColorPrimary);
         if (newPrimaryColor == 0) newPrimaryColor = fallBackButtonColor;

+ 42 - 14
library/src/main/java/com/afollestad/materialdialogs/MaterialDialog.java

@@ -27,6 +27,7 @@ import android.view.WindowManager;
 import android.widget.AdapterView;
 import android.widget.Button;
 import android.widget.CheckBox;
+import android.widget.EditText;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -63,6 +64,7 @@ public class MaterialDialog extends DialogBase implements
     protected TextView mProgressLabel;
     protected TextView mProgressMinMax;
     protected TextView content;
+    protected EditText input;
 
     protected MDButton positiveButton;
     protected MDButton neutralButton;
@@ -299,6 +301,8 @@ public class MaterialDialog extends DialogBase implements
                     sendSingleChoiceCallback(v);
                 if (mBuilder.listCallbackMultiChoice != null)
                     sendMultichoiceCallback();
+                if (mBuilder.inputCallback != null && input != null)
+                    mBuilder.inputCallback.onInput(this, input.getText());
                 if (mBuilder.autoDismiss) dismiss();
                 break;
             }
@@ -370,10 +374,13 @@ public class MaterialDialog extends DialogBase implements
         protected int dividerColor;
         protected int backgroundColor;
         protected int itemColor;
-        protected boolean mIndeterminateProgress;
-        protected boolean mShowMinMax;
-        protected int mProgress = -2;
-        protected int mProgressMax = 0;
+        protected boolean indeterminateProgress;
+        protected boolean showMinMax;
+        protected int progress = -2;
+        protected int progressMax = 0;
+        protected CharSequence inputPrefill;
+        protected CharSequence inputHint;
+        protected InputCallback inputCallback;
 
         protected boolean titleColorSet = false;
         protected boolean contentColorSet = false;
@@ -821,12 +828,12 @@ public class MaterialDialog extends DialogBase implements
          */
         public Builder progress(boolean indeterminate, int max) {
             if (indeterminate) {
-                this.mIndeterminateProgress = true;
-                this.mProgress = -2;
+                this.indeterminateProgress = true;
+                this.progress = -2;
             } else {
-                this.mIndeterminateProgress = false;
-                this.mProgress = -1;
-                this.mProgressMax = max;
+                this.indeterminateProgress = false;
+                this.progress = -1;
+                this.progressMax = max;
             }
             return this;
         }
@@ -840,7 +847,7 @@ public class MaterialDialog extends DialogBase implements
          * @return An instance of the Builder so calls can be chained.
          */
         public Builder progress(boolean indeterminate, int max, boolean showMinMax) {
-            this.mShowMinMax = showMinMax;
+            this.showMinMax = showMinMax;
             return progress(indeterminate, max);
         }
 
@@ -966,6 +973,17 @@ public class MaterialDialog extends DialogBase implements
             return this;
         }
 
+        public Builder input(CharSequence hint, CharSequence prefill, @NonNull InputCallback callback) {
+            this.inputCallback = callback;
+            this.inputHint = hint;
+            this.inputPrefill = prefill;
+            return this;
+        }
+
+        public Builder input(@StringRes int hint, @StringRes int prefill, @NonNull InputCallback callback) {
+            return input(hint == 0 ? null : context.getString(hint), prefill == 0 ? null : context.getString(prefill), callback);
+        }
+
         public MaterialDialog build() {
             return new MaterialDialog(this);
         }
@@ -1041,6 +1059,11 @@ public class MaterialDialog extends DialogBase implements
         return listView;
     }
 
+    @Nullable
+    public final EditText getInputEditText() {
+        return input;
+    }
+
     /**
      * Retrieves the TextView that contains the dialog title. If you want to update the
      * title, use #{@link #setTitle(CharSequence)} instead.
@@ -1189,7 +1212,7 @@ public class MaterialDialog extends DialogBase implements
     }
 
     public final void incrementProgress(int by) {
-        if (mBuilder.mProgress <= -2)
+        if (mBuilder.progress <= -2)
             throw new IllegalStateException("Cannot use incrementProgress() on this dialog.");
         setProgress(getCurrentProgress() + by);
     }
@@ -1197,7 +1220,7 @@ public class MaterialDialog extends DialogBase implements
     public final void setProgress(int progress) {
         if (Looper.myLooper() != Looper.getMainLooper())
             throw new IllegalStateException("You can only set the dialog's progress from the UI thread.");
-        else if (mBuilder.mProgress <= -2)
+        else if (mBuilder.progress <= -2)
             throw new IllegalStateException("Cannot use setProgress() on this dialog.");
         mProgress.setProgress(progress);
         int percentage = (int) (((float) getCurrentProgress() / (float) getMaxProgress()) * 100f);
@@ -1209,13 +1232,13 @@ public class MaterialDialog extends DialogBase implements
     public final void setMaxProgress(int max) {
         if (Looper.myLooper() != Looper.getMainLooper())
             throw new IllegalStateException("You can only set the dialog's progress from the UI thread.");
-        else if (mBuilder.mProgress <= -2)
+        else if (mBuilder.progress <= -2)
             throw new IllegalStateException("Cannot use setMaxProgress() on this dialog.");
         mProgress.setMax(max);
     }
 
     public final boolean isIndeterminateProgress() {
-        return mBuilder.mIndeterminateProgress;
+        return mBuilder.indeterminateProgress;
     }
 
     public final int getMaxProgress() {
@@ -1384,4 +1407,9 @@ public class MaterialDialog extends DialogBase implements
             return super.toString();
         }
     }
+
+    public interface InputCallback {
+
+        void onInput(MaterialDialog dialog, CharSequence input);
+    }
 }

+ 0 - 1
library/src/main/java/com/afollestad/materialdialogs/base/DialogBase.java

@@ -95,5 +95,4 @@ public class DialogBase extends AlertDialog implements DialogInterface.OnShowLis
         if (mShowListener != null)
             mShowListener.onShow(dialog);
     }
-
 }

+ 1 - 1
library/src/main/java/com/afollestad/materialdialogs/prefs/MaterialEditTextPreference.java

@@ -74,7 +74,7 @@ public class MaterialEditTextPreference extends EditTextPreference {
                 .dismissListener(this)
                 .content(getDialogMessage());
 
-        View layout = LayoutInflater.from(getContext()).inflate(R.layout.md_stub_input, null);
+        View layout = LayoutInflater.from(getContext()).inflate(R.layout.md_stub_inputpref, null);
         onBindDialogView(layout);
 
         if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP)

+ 42 - 0
library/src/main/res/layout/md_dialog_input.xml

@@ -0,0 +1,42 @@
+<com.afollestad.materialdialogs.internal.MDRootLayout xmlns:tools="http://schemas.android.com/tools"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <include layout="@layout/md_stub_titleframe" />
+
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:paddingLeft="@dimen/md_dialog_frame_margin"
+        android:paddingRight="@dimen/md_dialog_frame_margin"
+        android:paddingTop="@dimen/md_content_padding_top"
+        android:paddingBottom="@dimen/md_content_padding_bottom">
+
+        <TextView
+            android:id="@+id/content"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:fontFamily="sans-serif"
+            android:textSize="@dimen/md_content_textsize"
+            android:layout_marginTop="4dp"
+            android:layout_marginBottom="16dp"
+            tools:text="Message"
+            android:layout_gravity="center_horizontal"
+            tools:ignore="UnusedAttribute" />
+
+        <EditText
+            android:id="@android:id/input"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textSize="@dimen/md_content_textsize"
+            tools:ignore="TextFields" />
+
+    </LinearLayout>
+
+    <include layout="@layout/md_stub_actionbuttons" />
+
+</com.afollestad.materialdialogs.internal.MDRootLayout>

+ 0 - 0
library/src/main/res/layout/md_stub_input.xml → library/src/main/res/layout/md_stub_inputpref.xml


+ 20 - 1
sample/src/main/java/com/afollestad/materialdialogssample/MainActivity.java

@@ -196,6 +196,13 @@ public class MainActivity extends ActionBarActivity implements
             }
         });
 
+        findViewById(R.id.input).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                showInputDialog();
+            }
+        });
+
         findViewById(R.id.progress1).setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
@@ -542,7 +549,19 @@ public class MainActivity extends ActionBarActivity implements
                 .show();
     }
 
-    public void showProgressDialog(boolean indeterminate) {
+    private void showInputDialog() {
+        new MaterialDialog.Builder(this)
+                .title(R.string.input)
+                .content(R.string.input_content)
+                .input(R.string.input_hint, 0, new MaterialDialog.InputCallback() {
+                    @Override
+                    public void onInput(MaterialDialog dialog, CharSequence input) {
+                        showToast("Hello, " + input.toString() + "!");
+                    }
+                }).show();
+    }
+
+    private void showProgressDialog(boolean indeterminate) {
         if (indeterminate) {
             new MaterialDialog.Builder(this)
                     .title(R.string.progress_dialog)

+ 7 - 0
sample/src/main/res/layout/activity_main.xml

@@ -149,6 +149,13 @@
             android:text="@string/folder_chooser"
             android:layout_marginTop="@dimen/sample_button_spacing" />
 
+        <Button
+            android:id="@+id/input"
+            android:layout_width="match_parent"
+            android:layout_height="56dp"
+            android:text="@string/input"
+            android:layout_marginTop="@dimen/sample_button_spacing" />
+
         <Button
             android:id="@+id/progress1"
             android:layout_width="match_parent"

+ 3 - 0
sample/src/main/res/values/strings.xml

@@ -148,5 +148,8 @@
 
     <!-- Optional button to Skip a PreferenceActivity [CHAR LIMIT=20] -->
     <string name="skip_button_label">Skip</string>
+    <string name="input">Input</string>
+    <string name="input_hint">John Appleseed</string>
+    <string name="input_content">What\'s your name?</string>
 
 </resources>