content: /*
   * Copyright (C) 2007 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.lb.material_preferences_library.custom_preferences;
  
  import android.app.Dialog;
  import android.content.Context;
  import android.content.DialogInterface;
  import android.content.SharedPreferences;
  import android.content.res.TypedArray;
  import android.graphics.drawable.Drawable;
  import android.os.Bundle;
  import android.os.Parcel;
  import android.os.Parcelable;
  import android.preference.PreferenceManager;
  import androidx.core.content.res.ResourcesCompat;
  import androidx.appcompat.app.AlertDialog;
  import android.text.TextUtils;
  import android.util.AttributeSet;
  import android.view.LayoutInflater;
  import android.view.View;
  import android.view.Window;
  import android.view.WindowManager;
  import android.widget.TextView;
  
  import com.lb.material_preferences_library.R;
  
  /**
   * A base class for {@link Preference} objects that are
   * dialog-based. These preferences will, when clicked, open a dialog showing the
   * actual preference controls.
   *
   * @attr ref android.R.styleable#DialogPreference_dialogTitle
   * @attr ref android.R.styleable#DialogPreference_dialogMessage
   * @attr ref android.R.styleable#DialogPreference_dialogIcon
   * @attr ref android.R.styleable#DialogPreference_dialogLayout
   * @attr ref android.R.styleable#DialogPreference_positiveButtonText
   * @attr ref android.R.styleable#DialogPreference_negativeButtonText
   */
  public abstract class DialogPreference extends Preference implements
          DialogInterface.OnClickListener, DialogInterface.OnDismissListener,
          PreferenceManager.OnActivityDestroyListener {
      private AlertDialog.Builder mBuilder;
  
      private CharSequence mDialogTitle;
      private CharSequence mDialogMessage;
      private Drawable mDialogIcon;
      private CharSequence mPositiveButtonText;
      private CharSequence mNegativeButtonText;
      private int mDialogLayoutResId;
  
      /**
       * The dialog, if it is showing.
       */
      private Dialog mDialog;
  
      /**
       * Which button was clicked.
       */
      private int mWhichButtonClicked;
  
      public DialogPreference(
              Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
          super(context, attrs, defStyleAttr, defStyleRes);
      }
  
      public DialogPreference(Context context, AttributeSet attrs, int defStyleAttr) {
          super(context, attrs, defStyleAttr);
      }
  
      public DialogPreference(Context context, AttributeSet attrs) {
          this(context, attrs, R.attr.dialogPreferenceStyle);
      }
  
      public DialogPreference(Context context) {
          this(context, null);
      }
  
      @Override
      protected void init(final Context context, final AttributeSet attrs, final int defStyleAttr, final int defStyleRes) {
          super.init(context, attrs, defStyleAttr, defStyleRes);
          final TypedArray a = context.obtainStyledAttributes(attrs,
                  R.styleable.DialogPreference, defStyleAttr, defStyleRes);
          mDialogTitle = a.getString(R.styleable.DialogPreference_dialogTitle);
          if (mDialogTitle == null) {
  // Fallback on the regular title of the preference
  // (the one that is seen in the list)
              mDialogTitle = getTitle();
          }
  
          mDialogMessage = a.getString(R.styleable.DialogPreference_dialogMessage);
          mDialogIcon = a.getDrawable(R.styleable.DialogPreference_dialogIcon);
          mPositiveButtonText = a.getString(R.styleable.DialogPreference_positiveButtonText);
          mNegativeButtonText = a.getString(R.styleable.DialogPreference_negativeButtonText);
          mDialogLayoutResId = a.getResourceId(R.styleable.DialogPreference_dialogLayout, mDialogLayoutResId);
          a.recycle();
      }
  
      /**
       * Sets the title of the dialog. This will be shown on subsequent dialogs.
       *
       * @param dialogTitle The title.
       */
      public void setDialogTitle(CharSequence dialogTitle) {
          mDialogTitle = dialogTitle;
      }
  
      /**
       * Returns the title to be shown on subsequent dialogs.
       *
       * @return The title.
       */
      public CharSequence getDialogTitle() {
          return mDialogTitle;
      }
  
      /**
       * @param dialogTitleResId The dialog title as a resource.
       * @see #setDialogTitle(CharSequence)
       */
      public void setDialogTitle(int dialogTitleResId) {
          setDialogTitle(getContext().getString(dialogTitleResId));
      }
  
      /**
       * Sets the message of the dialog. This will be shown on subsequent dialogs.
       * <p/>
       * This message forms the content View of the dialog and conflicts with
       * list-based dialogs, for example. If setting a custom View on a dialog via
       * {@link #setDialogLayoutResource(int)}, include a text View with ID
       * {@link android.R.id#message} and it will be populated with this message.
       *
       * @param dialogMessage The message.
       */
      public void setDialogMessage(CharSequence dialogMessage) {
          mDialogMessage = dialogMessage;
      }
  
      /**
       * Returns the message to be shown on subsequent dialogs.
       *
       * @return The message.
       */
      public CharSequence getDialogMessage() {
          return mDialogMessage;
      }
  
      /**
       * @param dialogMessageResId The dialog message as a resource.
       * @see #setDialogMessage(CharSequence)
       */
      public void setDialogMessage(int dialogMessageResId) {
          setDialogMessage(getContext().getString(dialogMessageResId));
      }
  
      /**
       * Sets the icon of the dialog. This will be shown on subsequent dialogs.
       *
       * @param dialogIcon The icon, as a {@link Drawable}.
       */
      public void setDialogIcon(Drawable dialogIcon) {
          mDialogIcon = dialogIcon;
      }
  
      /**
       * Returns the icon to be shown on subsequent dialogs.
       *
       * @return The icon, as a {@link Drawable}.
       */
      public Drawable getDialogIcon() {
          return mDialogIcon;
      }
  
      /**
       * Sets the icon (resource ID) of the dialog. This will be shown on
       * subsequent dialogs.
       *
       * @param dialogIconRes The icon, as a resource ID.
       */
      public void setDialogIcon(int dialogIconRes) {
          mDialogIcon = ResourcesCompat.getDrawable(getContext().getResources(), dialogIconRes, null);
      }
  
      /**
       * Sets the text of the positive button of the dialog. This will be shown on
       * subsequent dialogs.
       *
       * @param positiveButtonText The text of the positive button.
       */
      public void setPositiveButtonText(CharSequence positiveButtonText) {
          mPositiveButtonText = positiveButtonText;
      }
  
      /**
       * Returns the text of the positive button to be shown on subsequent
       * dialogs.
       *
       * @return The text of the positive button.
       */
      public CharSequence getPositiveButtonText() {
          return mPositiveButtonText;
      }
  
      /**
       * @param positiveButtonTextResId The positive button text as a resource.
       * @see #setPositiveButtonText(CharSequence)
       */
      public void setPositiveButtonText(int positiveButtonTextResId) {
          setPositiveButtonText(getContext().getString(positiveButtonTextResId));
      }
  
      /**
       * Sets the text of the negative button of the dialog. This will be shown on
       * subsequent dialogs.
       *
       * @param negativeButtonText The text of the negative button.
       */
      public void setNegativeButtonText(CharSequence negativeButtonText) {
          mNegativeButtonText = negativeButtonText;
      }
  
      /**
       * Returns the text of the negative button to be shown on subsequent
       * dialogs.
       *
       * @return The text of the negative button.
       */
      public CharSequence getNegativeButtonText() {
          return mNegativeButtonText;
      }
  
      /**
       * @param negativeButtonTextResId The negative button text as a resource.
       * @see #setNegativeButtonText(CharSequence)
       */
      public void setNegativeButtonText(int negativeButtonTextResId) {
          setNegativeButtonText(getContext().getString(negativeButtonTextResId));
      }
  
      /**
       * Returns the layout resource that is used as the content View for
       * subsequent dialogs.
       *
       * @return The layout resource.
       */
      public int getDialogLayoutResource() {
          return mDialogLayoutResId;
      }
  
      /**
       * Sets the layout resource that is inflated as the {@link View} to be shown
       * as the content View of subsequent dialogs.
       *
       * @param dialogLayoutResId The layout resource ID to be inflated.
       * @see #setDialogMessage(CharSequence)
       */
      public void setDialogLayoutResource(int dialogLayoutResId) {
          mDialogLayoutResId = dialogLayoutResId;
      }
  
      /**
       * Prepares the dialog builder to be shown when the preference is clicked.
       * Use this to set custom properties on the dialog.
       * <p/>
       * Do not {@link AlertDialog.Builder#create()} or
       * {@link AlertDialog.Builder#show()}.
       */
      protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
      }
  
      @Override
      protected void onClick() {
          if (mDialog != null && mDialog.isShowing()) return;
  
          showDialog(null);
      }
  
      /**
       * Shows the dialog associated with this Preference. This is normally initiated
       * automatically on clicking on the preference. Call this method if you need to
       * show the dialog on some other event.
       *
       * @param state Optional instance state to restore on the dialog
       */
      protected void showDialog(Bundle state) {
          Context context = getContext();
  
          mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE;
          mBuilder = new AlertDialog.Builder(context)
                  .setTitle(mDialogTitle)
                  .setIcon(mDialogIcon)
                  .setPositiveButton(mPositiveButtonText, this)
                  .setNegativeButton(mNegativeButtonText, this);
          View contentView = onCreateDialogView();
          if (contentView != null) {
              onBindDialogView(contentView);
              mBuilder.setView(contentView);
          } else {
              mBuilder.setMessage(mDialogMessage);
          }
  
          onPrepareDialogBuilder(mBuilder);
          PreferenceManagerEx.getInstance().registerOnActivityDestroyListener(getPreferenceManager(), this);
  
  // Create the dialog
          final Dialog dialog = mDialog = mBuilder.create();
          if (state != null) {
              dialog.onRestoreInstanceState(state);
          }
          if (needInputMethod()) {
              requestInputMethod(dialog);
          }
          dialog.setOnDismissListener(this);
          dialog.show();
      }
  
      /**
       * Returns whether the preference needs to display a soft input method when the dialog
       * is displayed. Default is false. Subclasses should override this method if they need
       * the soft input method brought up automatically.
       *
       * @hide
       */
      protected boolean needInputMethod() {
          return false;
      }
  
      /**
       * Sets the required flags on the dialog window to enable input method window to show up.
       */
      private void requestInputMethod(Dialog dialog) {
          Window window = dialog.getWindow();
          window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
      }
  
      /**
       * Creates the content view for the dialog (if a custom content view is
       * required). By default, it inflates the dialog layout resource if it is
       * set.
       *
       * @return The content View for the dialog.
       * @see #setLayoutResource(int)
       */
      protected View onCreateDialogView() {
          if (mDialogLayoutResId == 0) {
              return null;
          }
  
          LayoutInflater inflater = LayoutInflater.from(mBuilder.getContext());
          return inflater.inflate(mDialogLayoutResId, null);
      }
  
      /**
       * Binds views in the content View of the dialog to data.
       * <p/>
       * Make sure to call through to the superclass implementation.
       *
       * @param view The content View of the dialog, if it is custom.
       */
      protected void onBindDialogView(View view) {
          View dialogMessageView = view.findViewById(android.R.id.message);
  
          if (dialogMessageView != null) {
              final CharSequence message = getDialogMessage();
              int newVisibility = View.GONE;
  
              if (!TextUtils.isEmpty(message)) {
                  if (dialogMessageView instanceof TextView) {
                      ((TextView) dialogMessageView).setText(message);
                  }
  
                  newVisibility = View.VISIBLE;
              }
  
              if (dialogMessageView.getVisibility() != newVisibility) {
                  dialogMessageView.setVisibility(newVisibility);
              }
          }
      }
  
      public void onClick(DialogInterface dialog, int which) {
          mWhichButtonClicked = which;
      }
  
      public void onDismiss(DialogInterface dialog) {
          PreferenceManagerEx.getInstance().unregisterOnActivityDestroyListener(getPreferenceManager(), this);
  
          mDialog = null;
          onDialogClosed(mWhichButtonClicked == DialogInterface.BUTTON_POSITIVE);
      }
  
      /**
       * Called when the dialog is dismissed and should be used to save data to
       * the {@link SharedPreferences}.
       *
       * @param positiveResult Whether the positive button was clicked (true), or
       *                       the negative button was clicked or the dialog was canceled (false).
       */
      protected void onDialogClosed(boolean positiveResult) {
      }
  
      /**
       * Gets the dialog that is shown by this preference.
       *
       * @return The dialog, or null if a dialog is not being shown.
       */
      public Dialog getDialog() {
          return mDialog;
      }
  
      /**
       * {@inheritDoc}
       */
      public void onActivityDestroy() {
  
          if (mDialog == null || !mDialog.isShowing()) {
              return;
          }
  
          mDialog.dismiss();
      }
  
      @Override
      protected Parcelable onSaveInstanceState() {
          final Parcelable superState = super.onSaveInstanceState();
          if (mDialog == null || !mDialog.isShowing()) {
              return superState;
          }
  
          final SavedState myState = new SavedState(superState);
          myState.isDialogShowing = true;
          myState.dialogBundle = mDialog.onSaveInstanceState();
          return myState;
      }
  
      @Override
      protected void onRestoreInstanceState(Parcelable state) {
          if (state == null || !state.getClass().equals(SavedState.class)) {
  // Didn't save state for us in onSaveInstanceState
              super.onRestoreInstanceState(state);
              return;
          }
  
          SavedState myState = (SavedState) state;
          super.onRestoreInstanceState(myState.getSuperState());
          if (myState.isDialogShowing) {
              showDialog(myState.dialogBundle);
          }
      }
  
      private static class SavedState extends BaseSavedState {
          public static final Parcelable.Creator<SavedState> CREATOR =
                  new Parcelable.Creator<SavedState>() {
                      public SavedState createFromParcel(Parcel in) {
                          return new SavedState(in);
                      }
  
                      public SavedState[] newArray(int size) {
                          return new SavedState[size];
                      }
                  };
          boolean isDialogShowing;
          Bundle dialogBundle;
  
          public SavedState(Parcel source) {
              super(source);
              isDialogShowing = source.readInt() == 1;
              dialogBundle = source.readBundle();
          }
  
          public SavedState(Parcelable superState) {
              super(superState);
          }
  
          @Override
          public void writeToParcel(Parcel dest, int flags) {
              super.writeToParcel(dest, flags);
              dest.writeInt(isDialogShowing ? 1 : 0);
              dest.writeBundle(dialogBundle);
          }
      }
  
  }
  