package com.douban.ui.dialog;

import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;

/**
 * Indeterminate progress dialog wrapped up in a DialogFragment to work even when the device
 * orientation is changed. Currently, only supports adding a title and/or message to the progress
 * dialog.  There is an additional parameter of the minimum amount of time to display the progress
 * dialog even after a call to dismiss the dialog {@link #dismiss()} or
 * {@link #dismissAllowingStateLoss()}.
 */
public class ProgressDialogFragment extends DialogFragment {
    private static final String TAG = ProgressDialogFragment.class.getSimpleName();

    private CharSequence mTitle;
    private CharSequence mMessage;
    private boolean mActivityReady = false;
    private Dialog mOldDialog;
    private final Handler mHandler = new Handler();
    private boolean mCalledSuperDismiss = false;
    private boolean mAllowStateLoss;
    private final Runnable mDismisser = new Runnable() {
        @Override
        public void run() {
            superDismiss();
        }
    };

    /**
     * Creates and shows an indeterminate progress dialog.  Once the progress dialog is shown, it
     * will be shown for at least the minDisplayTime (in milliseconds), so that the progress dialog
     * does not flash in and out to quickly.
     */
    public static ProgressDialogFragment show(FragmentManager fragmentManager,
                                              CharSequence title, CharSequence message, boolean cancelable) {
        ProgressDialogFragment dialogFragment = new ProgressDialogFragment();
        dialogFragment.mTitle = title;
        dialogFragment.mMessage = message;
        dialogFragment.setCancelable(cancelable);
        dialogFragment.show(fragmentManager, TAG);
        return dialogFragment;
    }

    public static ProgressDialogFragment show(FragmentManager fragmentManager,
                                              CharSequence title, CharSequence message) {
        return show(fragmentManager, title, message, false);
    }

    /**
     * Creates and shows an indeterminate progress dialog.  Once the progress dialog is shown, it
     * will be shown for at least the minDisplayTime (in milliseconds), so that the progress dialog
     * does not flash in and out to quickly.
     */
    public static ProgressDialogFragment create(CharSequence title, CharSequence message, boolean cancelable) {
        ProgressDialogFragment dialogFragment = new ProgressDialogFragment();
        dialogFragment.mTitle = title;
        dialogFragment.mMessage = message;
        dialogFragment.setCancelable(cancelable);
        return dialogFragment;
    }

    public static ProgressDialogFragment create(CharSequence title, CharSequence message) {
        return create(title, message, false);
    }

    public void show(FragmentManager manager) {
        show(manager, TAG);
    }

    @Override
    public void show(FragmentManager manager, String tag) {
        super.show(manager, tag);
    }

    @Override
    public int show(FragmentTransaction transaction, String tag) {
        return super.show(transaction, tag);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
        setStyle(STYLE_NO_FRAME, 0);
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // Create the progress dialog and set its properties
        final ProgressDialog dialog = new ProgressDialog(getActivity());
        dialog.setIndeterminate(true);
        dialog.setIndeterminateDrawable(null);
        dialog.setTitle(mTitle);
        dialog.setMessage(mMessage);

        return dialog;
    }

    @Override
    public void onStart() {
        super.onStart();
        mActivityReady = true;

        // Check if superDismiss() had been called before.  This can happen if in a long
        // running operation, the user hits the home button and closes this fragment's activity.
        // Upon returning, we want to dismiss this progress dialog fragment.
        if (mCalledSuperDismiss) {
            superDismiss();
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        mActivityReady = false;
    }

    /**
     * There is a race condition that is not handled properly by the DialogFragment class.
     * If we don't check that this onDismiss callback isn't for the old progress dialog from before
     * the device orientation change, then this will cause the newly created dialog after the
     * orientation change to be dismissed immediately.
     */
    @Override
    public void onDismiss(DialogInterface dialog) {
        if (mOldDialog != null && mOldDialog == dialog) {
            // This is the callback from the old progress dialog that was already dismissed before
            // the device orientation change, so just ignore it.
            return;
        }
        super.onDismiss(dialog);
    }

    /**
     * Save the old dialog that is about to get destroyed in case this is due to a change
     * in device orientation.  This will allow us to intercept the callback to
     * {@link #onDismiss(android.content.DialogInterface)} in case the callback happens after a new progress dialog
     * instance was created.
     */
    @Override
    public void onDestroyView() {
        mOldDialog = getDialog();
        super.onDestroyView();
    }

    @Override
    public void dismiss() {
        mAllowStateLoss = false;
        dismissWhenReady();
    }

    @Override
    public void dismissAllowingStateLoss() {
        mAllowStateLoss = true;
        dismissWhenReady();
    }

    private void dismissWhenReady() {
        // dismiss immediately
        mHandler.post(mDismisser);
    }

    private void superDismiss() {
        mCalledSuperDismiss = true;
        if (mActivityReady) {
            // The fragment is either in onStart or past it, but has not gotten to onStop yet.
            // It is safe to dismiss this dialog fragment.
            if (mAllowStateLoss) {
                super.dismissAllowingStateLoss();
            } else {
                super.dismiss();
            }
        }
        // If mActivityReady is false, then this dialog fragment has already passed the onStop
        // state. This can happen if the user hit the 'home' button before this dialog fragment was
        // dismissed or if there is a configuration change.
        // In the event that this dialog fragment is re-attached and reaches onStart (e.g.,
        // because the user returns to this fragment's activity or the device configuration change
        // has re-attached this dialog fragment), because the mCalledSuperDismiss flag was set to
        // true, this dialog fragment will be dismissed within onStart.  So, there's nothing else
        // that needs to be done.
    }
}

@@ -156,35 +156,8 @@
 le;%0A
-import android.os.Handler;%0A
 impo
@@ -1000,60 +1000,8 @@
 og;%0A
-    private final Handler mHandler = new Handler();%0A
     
@@ -1085,156 +1085,8 @@
 oss;
-%0A    private final Runnable mDismisser = new Runnable() %7B%0A        @Override%0A        public void run() %7B%0A            superDismiss();%0A        %7D%0A    %7D;
 %0A%0A  
@@ -5541,32 +5541,28 @@
         
-dismissWhenReady
+superDismiss
 ();%0A    
@@ -5667,136 +5667,21 @@
     
-dismissWhenReady();%0A    %7D%0A%0A    private void dismissWhenReady() %7B%0A        // dismiss immediately%0A        mHandler.post(m
+super
 Dismiss
-er
+(
 );%0A 
@@ -6085,32 +6085,32 @@
 ;%0A            %7D%0A
+
         %7D%0A      
@@ -6107,684 +6107,8 @@
   %7D%0A
-        // If mActivityReady is false, then this dialog fragment has already passed the onStop%0A        // state. This can happen if the user hit the 'home' button before this dialog fragment was%0A        // dismissed or if there is a configuration change.%0A        // In the event that this dialog fragment is re-attached and reaches onStart (e.g.,%0A        // because the user returns to this fragment's activity or the device configuration change%0A        // has re-attached this dialog fragment), because the mCalledSuperDismiss flag was set to%0A        // true, this dialog fragment will be dismissed within onStart.  So, there's nothing else%0A        // that needs to be done.%0A
     

optimize progress dialog fragment