Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 677d6c92 authored by cketti's avatar cketti
Browse files

Don't stop the activity before attachments have been fetched

Display a progress dialog when the user tries to send the message or
save a draft and the attachments haven't been fetched completely.
parent 62aa1b87
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -1149,4 +1149,7 @@ Please submit bug reports, contribute new features and ask questions at
    <string name="mark_all_as_read">Mark all as read</string>

    <string name="loading_attachment">Loading attachment…</string>
    <string name="fetching_attachment_dialog_title_send">Sending message</string>
    <string name="fetching_attachment_dialog_title_save">Saving draft</string>
    <string name="fetching_attachment_dialog_message">Fetching attachment…</string>
</resources>
+145 −2
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.controller.MessagingListener;
import com.fsck.k9.crypto.CryptoProvider;
import com.fsck.k9.crypto.PgpData;
import com.fsck.k9.fragment.ProgressDialogFragment;
import com.fsck.k9.helper.ContactItem;
import com.fsck.k9.helper.Contacts;
import com.fsck.k9.helper.HtmlConverter;
@@ -94,7 +95,6 @@ import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -103,7 +103,9 @@ import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MessageCompose extends K9Activity implements OnClickListener {
public class MessageCompose extends K9Activity implements OnClickListener,
        ProgressDialogFragment.CancelListener {

    private static final int DIALOG_SAVE_OR_DISCARD_DRAFT_MESSAGE = 1;
    private static final int DIALOG_REFUSE_TO_SAVE_DRAFT_MARKED_ENCRYPTED = 2;
    private static final int DIALOG_CONTINUE_WITHOUT_PUBLIC_KEY = 3;
@@ -147,14 +149,19 @@ public class MessageCompose extends K9Activity implements OnClickListener {
            "com.fsck.k9.activity.MessageCompose.forcePlainText";
    private static final String STATE_KEY_QUOTED_TEXT_FORMAT =
            "com.fsck.k9.activity.MessageCompose.quotedTextFormat";
    private static final String STATE_KEY_NUM_ATTACHMENTS_LOADING = "numAttachmentsLoading";
    private static final String STATE_KEY_WAITING_FOR_ATTACHMENTS = "waitingForAttachments";

    private static final String LOADER_ARG_ATTACHMENT = "attachment";

    private static final String FRAGMENT_WAITING_FOR_ATTACHMENT = "waitingForAttachment";

    private static final int MSG_PROGRESS_ON = 1;
    private static final int MSG_PROGRESS_OFF = 2;
    private static final int MSG_SKIPPED_ATTACHMENTS = 3;
    private static final int MSG_SAVED_DRAFT = 4;
    private static final int MSG_DISCARDED_DRAFT = 5;
    private static final int MSG_PERFORM_STALLED_ACTION = 6;

    private static final int ACTIVITY_REQUEST_PICK_ATTACHMENT = 1;
    private static final int CONTACT_PICKER_TO = 4;
@@ -326,6 +333,23 @@ public class MessageCompose extends K9Activity implements OnClickListener {
     */
    private long mDraftId = INVALID_DRAFT_ID;

    /**
     * Number of attachments currently being fetched.
     */
    private int mNumAttachmentsLoading = 0;

    private enum WaitingAction {
        NONE,
        SEND,
        SAVE
    }

    /**
     * Specifies what action to perform once attachments have been fetched.
     */
    private WaitingAction mWaitingForAttachments = WaitingAction.NONE;


    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(android.os.Message msg) {
@@ -354,6 +378,9 @@ public class MessageCompose extends K9Activity implements OnClickListener {
                    getString(R.string.message_discarded_toast),
                    Toast.LENGTH_LONG).show();
                break;
            case MSG_PERFORM_STALLED_ACTION:
                performStalledAction();
                break;
            default:
                super.handleMessage(msg);
                break;
@@ -1080,6 +1107,8 @@ public class MessageCompose extends K9Activity implements OnClickListener {
            attachments.add(attachment);
        }

        outState.putInt(STATE_KEY_NUM_ATTACHMENTS_LOADING, mNumAttachmentsLoading);
        outState.putString(STATE_KEY_WAITING_FOR_ATTACHMENTS, mWaitingForAttachments.name());
        outState.putParcelableArrayList(STATE_KEY_ATTACHMENTS, attachments);
        outState.putBoolean(STATE_KEY_CC_SHOWN, mCcWrapper.getVisibility() == View.VISIBLE);
        outState.putBoolean(STATE_KEY_BCC_SHOWN, mBccWrapper.getVisibility() == View.VISIBLE);
@@ -1105,6 +1134,16 @@ public class MessageCompose extends K9Activity implements OnClickListener {
        mAttachments.removeAllViews();
        mMaxLoaderId = 0;

        mNumAttachmentsLoading = savedInstanceState.getInt(STATE_KEY_NUM_ATTACHMENTS_LOADING);
        mWaitingForAttachments = WaitingAction.NONE;
        try {
            String waitingFor = savedInstanceState.getString(STATE_KEY_WAITING_FOR_ATTACHMENTS);
            mWaitingForAttachments = WaitingAction.valueOf(waitingFor);
        } catch (Exception e) {
            Log.w(K9.LOG_TAG, "Couldn't read value \" + STATE_KEY_WAITING_FOR_ATTACHMENTS +" +
                    "\" from saved instance state", e);
        }

        ArrayList<Attachment> attachments = savedInstanceState.getParcelableArrayList(STATE_KEY_ATTACHMENTS);
        for (Attachment attachment : attachments) {
            addAttachmentView(attachment);
@@ -1784,6 +1823,20 @@ public class MessageCompose extends K9Activity implements OnClickListener {
            Toast.makeText(this, getString(R.string.message_compose_error_no_recipients), Toast.LENGTH_LONG).show();
            return;
        }

        if (mWaitingForAttachments != WaitingAction.NONE) {
            return;
        }

        if (mNumAttachmentsLoading > 0) {
            mWaitingForAttachments = WaitingAction.SEND;
            showWaitingForAttachmentDialog();
        } else {
            performSend();
        }
    }

    private void performSend() {
        final CryptoProvider crypto = mAccount.getCryptoProvider();
        if (mEncryptCheckbox.isChecked() && !mPgpData.hasEncryptionKeys()) {
            // key selection before encryption
@@ -1847,6 +1900,19 @@ public class MessageCompose extends K9Activity implements OnClickListener {
    }

    private void onSave() {
        if (mWaitingForAttachments != WaitingAction.NONE) {
            return;
        }

        if (mNumAttachmentsLoading > 0) {
            mWaitingForAttachments = WaitingAction.SAVE;
            showWaitingForAttachmentDialog();
        } else {
            performSend();
        }
    }

    private void performSave() {
        saveIfNeeded();
        finish();
    }
@@ -1987,6 +2053,7 @@ public class MessageCompose extends K9Activity implements OnClickListener {
            new LoaderManager.LoaderCallbacks<Attachment>() {
        @Override
        public Loader<Attachment> onCreateLoader(int id, Bundle args) {
            onFetchAttachmentStarted();
            Attachment attachment = args.getParcelable(LOADER_ARG_ATTACHMENT);
            return new AttachmentInfoLoader(MessageCompose.this, attachment);
        }
@@ -2004,6 +2071,8 @@ public class MessageCompose extends K9Activity implements OnClickListener {

                attachment.loaderId = ++mMaxLoaderId;
                initAttachmentContentLoader(attachment);
            } else {
                onFetchAttachmentFinished();
            }

            getSupportLoaderManager().destroyLoader(loaderId);
@@ -2011,6 +2080,7 @@ public class MessageCompose extends K9Activity implements OnClickListener {

        @Override
        public void onLoaderReset(Loader<Attachment> loader) {
            onFetchAttachmentFinished();
        }
    };

@@ -2038,14 +2108,48 @@ public class MessageCompose extends K9Activity implements OnClickListener {
                }
            }

            onFetchAttachmentFinished();

            getSupportLoaderManager().destroyLoader(loaderId);
        }

        @Override
        public void onLoaderReset(Loader<Attachment> loader) {
            onFetchAttachmentFinished();
        }
    };

    private void onFetchAttachmentStarted() {
        mNumAttachmentsLoading += 1;
    }

    private void onFetchAttachmentFinished() {
        // We're not allowed to perform fragment transactions when called from onLoadFinished().
        // So we use the Handler to call performStalledAction().
        mHandler.sendEmptyMessage(MSG_PERFORM_STALLED_ACTION);
    }

    private void performStalledAction() {
        mNumAttachmentsLoading -= 1;

        WaitingAction waitingFor = mWaitingForAttachments;
        mWaitingForAttachments = WaitingAction.NONE;

        if (waitingFor != WaitingAction.NONE) {
            dismissWaitingForAttachmentDialog();
        }

        switch (waitingFor) {
            case SEND: {
                performSend();
                break;
            }
            case SAVE: {
                performSave();
                break;
            }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
@@ -2380,6 +2484,45 @@ public class MessageCompose extends K9Activity implements OnClickListener {
        }
    }

    private void showWaitingForAttachmentDialog() {
        String title;

        switch (mWaitingForAttachments) {
            case SEND: {
                title = getString(R.string.fetching_attachment_dialog_title_send);
                break;
            }
            case SAVE: {
                title = getString(R.string.fetching_attachment_dialog_title_save);
                break;
            }
            default: {
                return;
            }
        }

        ProgressDialogFragment fragment = ProgressDialogFragment.newInstance(title,
                getString(R.string.fetching_attachment_dialog_message));
        fragment.show(getSupportFragmentManager(), FRAGMENT_WAITING_FOR_ATTACHMENT);
    }

    public void onCancel(ProgressDialogFragment fragment) {
        attachmentProgressDialogCancelled();
    }

    void attachmentProgressDialogCancelled() {
        mWaitingForAttachments = WaitingAction.NONE;
    }

    private void dismissWaitingForAttachmentDialog() {
        ProgressDialogFragment fragment = (ProgressDialogFragment)
                getSupportFragmentManager().findFragmentByTag(FRAGMENT_WAITING_FOR_ATTACHMENT);

        if (fragment != null) {
            fragment.dismiss();
        }
    }

    @Override
    public Dialog onCreateDialog(int id) {
        switch (id) {
+2 −2
Original line number Diff line number Diff line
@@ -752,8 +752,8 @@ public class MessageViewFragment extends SherlockFragment implements OnClickList
                break;
            }
            case R.id.dialog_attachment_progress: {
                String title = getString(R.string.dialog_attachment_progress_title);
                fragment = ProgressDialogFragment.newInstance(title);
                String message = getString(R.string.dialog_attachment_progress_title);
                fragment = ProgressDialogFragment.newInstance(null, message);
                break;
            }
            default: {
+22 −2
Original line number Diff line number Diff line
@@ -2,19 +2,22 @@ package com.fsck.k9.fragment;

import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.Bundle;

import com.actionbarsherlock.app.SherlockDialogFragment;


public class ProgressDialogFragment extends SherlockDialogFragment {
    private static final String ARG_TITLE = "title";
    protected static final String ARG_TITLE = "title";
    protected static final String ARG_MESSAGE = "message";

    public static ProgressDialogFragment newInstance(String title) {
    public static ProgressDialogFragment newInstance(String title, String message) {
        ProgressDialogFragment fragment = new ProgressDialogFragment();

        Bundle args = new Bundle();
        args.putString(ARG_TITLE, title);
        args.putString(ARG_MESSAGE, message);
        fragment.setArguments(args);

        return fragment;
@@ -25,11 +28,28 @@ public class ProgressDialogFragment extends SherlockDialogFragment {
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Bundle args = getArguments();
        String title = args.getString(ARG_TITLE);
        String message = args.getString(ARG_MESSAGE);

        ProgressDialog dialog = new ProgressDialog(getActivity());
        dialog.setIndeterminate(true);
        dialog.setTitle(title);
        dialog.setMessage(message);

        return dialog;
    }

    @Override
    public void onCancel(DialogInterface dialog) {
        CancelListener listener = (CancelListener) getActivity();
        if (listener != null && listener instanceof CancelListener) {
            listener.onCancel(this);
        }

        super.onCancel(dialog);
    }


    public interface CancelListener {
        void onCancel(ProgressDialogFragment fragment);
    }
}