Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import app.k9mail.core.ui.legacy.designsystem.atom.icon.Icons;
import app.k9mail.legacy.mailstore.MessageStoreManager;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.fsck.k9.activity.compose.MessageComposeInAppNotificationFragment;
Expand Down Expand Up @@ -186,6 +187,8 @@ public class MessageCompose extends BaseActivity implements OnClickListener,
private static final String STATE_KEY_SOURCE_MESSAGE_PROCED =
"com.fsck.k9.activity.MessageCompose.stateKeySourceMessageProced";
private static final String STATE_KEY_DRAFT_ID = "com.fsck.k9.activity.MessageCompose.draftId";
private static final String STATE_KEY_RESTORE_FROM_DRAFT =
"com.fsck.k9.activity.MessageCompose.restoreFromDraft";
private static final String STATE_IDENTITY_CHANGED =
"com.fsck.k9.activity.MessageCompose.identityChanged";
private static final String STATE_IDENTITY =
Expand Down Expand Up @@ -224,6 +227,7 @@ public class MessageCompose extends BaseActivity implements OnClickListener,
private final MessageLoaderHelperFactory messageLoaderHelperFactory = DI.get(MessageLoaderHelperFactory.class);
private final DefaultFolderProvider defaultFolderProvider = DI.get(DefaultFolderProvider.class);
private final MessagingController messagingController = DI.get(MessagingController.class);
private final MessageStoreManager messageStoreManager = DI.get(MessageStoreManager.class);
private final Preferences preferences = DI.get(Preferences.class);
private final GeneralSettingsManager generalSettingsManager = DI.get(GeneralSettingsManager.class);

Expand Down Expand Up @@ -286,6 +290,7 @@ public class MessageCompose extends BaseActivity implements OnClickListener,
private EditText signatureView;
private EditText messageContentView;
private LinearLayout attachmentsView;
private View composerContent;

private String referencedMessageIds;
private String repliedToMessageId;
Expand All @@ -299,6 +304,8 @@ public class MessageCompose extends BaseActivity implements OnClickListener,

private boolean sendMessageHasBeenTriggered = false;
private boolean ignoreSentFolderNotAssigned = false;
private Integer pendingAttachmentPickerRequestCode;
private boolean restoringFromDraft;

@Override
public void onCreate(Bundle savedInstanceState) {
Expand All @@ -320,7 +327,7 @@ public void onCreate(Bundle savedInstanceState) {

LayoutInflater themedLayoutInflater = LayoutInflater.from(themeContext);
contentContainer.setLayoutInflater(themedLayoutInflater);
contentContainer.inflate();
composerContent = contentContainer.inflate();

initializeActionBar();

Expand All @@ -346,6 +353,11 @@ public void onCreate(Bundle savedInstanceState) {
return;
}

restoringFromDraft = restoreDraftReference(savedInstanceState);
if (restoringFromDraft) {
composerContent.setSaveFromParentEnabled(false);
}

initializeInAppNotificationFragment();

chooseIdentityView = findViewById(R.id.identity);
Expand Down Expand Up @@ -419,7 +431,7 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {
subjectView.setOnFocusChangeListener(this);
messageContentView.setOnFocusChangeListener(this);

if (savedInstanceState != null) {
if (savedInstanceState != null && !restoringFromDraft) {
/*
* This data gets used in onCreate, so grab it here instead of onRestoreInstanceState
*/
Expand Down Expand Up @@ -462,7 +474,9 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {
recipientPresenter.initFromTrustIdAction(intentData.getTrustId());
}

if (intentData.getStartedByExternalIntent()) {
if (restoringFromDraft) {
action = Action.EDIT_DRAFT;
} else if (intentData.getStartedByExternalIntent()) {
action = Action.COMPOSE;
changesMadeSinceLastSave = true;
} else {
Expand Down Expand Up @@ -556,7 +570,11 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {

setTitle();

currentMessageBuilder = (MessageBuilder) getLastCustomNonConfigurationInstance();
RetainedState retainedState = (RetainedState) getLastCustomNonConfigurationInstance();
currentMessageBuilder = retainedState != null ? retainedState.messageBuilder : null;
if (retainedState != null) {
quotedMessagePresenter.restoreState(retainedState.quotedMessageState);
}
if (currentMessageBuilder != null) {
setProgressBarIndeterminateVisibility(true);
currentMessageBuilder.reattachCallback(this);
Expand Down Expand Up @@ -613,6 +631,26 @@ private void fetchAccount(Intent intent) {
}
}

private boolean restoreDraftReference(Bundle savedInstanceState) {
if (savedInstanceState == null || !savedInstanceState.getBoolean(STATE_KEY_RESTORE_FROM_DRAFT)) {
return false;
}

draftMessageId = savedInstanceState.getLong(STATE_KEY_DRAFT_ID);
Long draftsFolderId = account.getDraftsFolderId();
if (draftsFolderId == null) {
return false;
}

String messageServerId = messageStoreManager.getMessageStore(account).getMessageServerId(draftMessageId);
if (messageServerId == null) {
return false;
}

relatedMessageReference = new MessageReference(account.getUuid(), draftsFolderId, messageServerId);
return true;
}

@Override
protected void onResume() {
super.onResume();
Expand Down Expand Up @@ -700,31 +738,35 @@ public void onPause() {
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);

boolean canRestoreFromDraft = draftMessageId != null && !changesMadeSinceLastSave;
outState.putBoolean(STATE_KEY_SOURCE_MESSAGE_PROCED, relatedMessageProcessed);
if (draftMessageId != null) {
outState.putLong(STATE_KEY_DRAFT_ID, draftMessageId);
}
outState.putParcelable(STATE_IDENTITY, identity);
outState.putBoolean(STATE_IDENTITY_CHANGED, identityChanged);
outState.putString(STATE_IN_REPLY_TO, repliedToMessageId);
outState.putString(STATE_REFERENCES, referencedMessageIds);
outState.putBoolean(STATE_KEY_RESTORE_FROM_DRAFT, canRestoreFromDraft);
outState.putBoolean(STATE_KEY_READ_RECEIPT, requestReadReceipt);
outState.putBoolean(STATE_KEY_CHANGES_MADE_SINCE_LAST_SAVE, changesMadeSinceLastSave);
outState.putBoolean(STATE_ALREADY_NOTIFIED_USER_OF_EMPTY_SUBJECT, alreadyNotifiedUserOfEmptySubject);
outState.putIntegerArrayList(STATE_ACTIVE_IN_APP_NOTIFICATIONS, new ArrayList<>(activeInAppNotifications));

replyToPresenter.onSaveInstanceState(outState);
recipientPresenter.onSaveInstanceState(outState);
quotedMessagePresenter.onSaveInstanceState(outState);
attachmentPresenter.onSaveInstanceState(outState);
if (!canRestoreFromDraft) {
outState.putParcelable(STATE_IDENTITY, identity);
outState.putBoolean(STATE_IDENTITY_CHANGED, identityChanged);
outState.putString(STATE_IN_REPLY_TO, repliedToMessageId);
outState.putString(STATE_REFERENCES, referencedMessageIds);
outState.putBoolean(STATE_KEY_CHANGES_MADE_SINCE_LAST_SAVE, changesMadeSinceLastSave);
replyToPresenter.onSaveInstanceState(outState);
recipientPresenter.onSaveInstanceState(outState);
quotedMessagePresenter.onSaveInstanceState(outState);
attachmentPresenter.onSaveInstanceState(outState);
}
}

@Override
public Object onRetainCustomNonConfigurationInstance() {
if (currentMessageBuilder != null) {
currentMessageBuilder.detachCallback();
}
return currentMessageBuilder;
return new RetainedState(currentMessageBuilder, quotedMessagePresenter.retainState());
}

@Override
Expand All @@ -735,31 +777,31 @@ protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {

requestReadReceipt = savedInstanceState.getBoolean(STATE_KEY_READ_RECEIPT);

replyToPresenter.onRestoreInstanceState(savedInstanceState);
recipientPresenter.onRestoreInstanceState(savedInstanceState);
quotedMessagePresenter.onRestoreInstanceState(savedInstanceState);
attachmentPresenter.onRestoreInstanceState(savedInstanceState);
if (!restoringFromDraft) {
replyToPresenter.onRestoreInstanceState(savedInstanceState);
recipientPresenter.onRestoreInstanceState(savedInstanceState);
quotedMessagePresenter.onRestoreInstanceState(savedInstanceState);
attachmentPresenter.onRestoreInstanceState(savedInstanceState);
}

if (!restoringFromDraft) {
draftMessageId = savedInstanceState.containsKey(STATE_KEY_DRAFT_ID) ?
savedInstanceState.getLong(STATE_KEY_DRAFT_ID) : null;
identity = BundleCompat.getParcelable(savedInstanceState, STATE_IDENTITY, Identity.class);
identityChanged = savedInstanceState.getBoolean(STATE_IDENTITY_CHANGED);
repliedToMessageId = savedInstanceState.getString(STATE_IN_REPLY_TO);
referencedMessageIds = savedInstanceState.getString(STATE_REFERENCES);
changesMadeSinceLastSave = savedInstanceState.getBoolean(STATE_KEY_CHANGES_MADE_SINCE_LAST_SAVE);

if (savedInstanceState.containsKey(STATE_KEY_DRAFT_ID)) {
draftMessageId = savedInstanceState.getLong(STATE_KEY_DRAFT_ID);
} else {
draftMessageId = null;
updateFrom();
updateMessageFormat();
}
identity = BundleCompat.getParcelable(savedInstanceState, STATE_IDENTITY, Identity.class);
identityChanged = savedInstanceState.getBoolean(STATE_IDENTITY_CHANGED);
repliedToMessageId = savedInstanceState.getString(STATE_IN_REPLY_TO);
referencedMessageIds = savedInstanceState.getString(STATE_REFERENCES);
changesMadeSinceLastSave = savedInstanceState.getBoolean(STATE_KEY_CHANGES_MADE_SINCE_LAST_SAVE);
alreadyNotifiedUserOfEmptySubject = savedInstanceState.getBoolean(STATE_ALREADY_NOTIFIED_USER_OF_EMPTY_SUBJECT);
final List<Integer> activeInAppNotifications = savedInstanceState
.getIntegerArrayList(STATE_ACTIVE_IN_APP_NOTIFICATIONS);
if (activeInAppNotifications != null && !activeInAppNotifications.isEmpty()) {
this.activeInAppNotifications.addAll(activeInAppNotifications);
}

updateFrom();

updateMessageFormat();
}

private void setTitle() {
Expand Down Expand Up @@ -941,6 +983,7 @@ public void showContactPicker(int requestCode) {
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
isInSubActivity = false;
composerContent.setSaveFromParentEnabled(true);

// Only if none of the high 16 bits are set it might be one of our request codes
if ((requestCode & REQUEST_CODE_MASK) == 0) {
Expand Down Expand Up @@ -1744,6 +1787,18 @@ public void onMessageBuildSuccess(MimeMessage message, boolean isDraft) {
}
}

private static final class RetainedState {
private final MessageBuilder messageBuilder;
private final QuotedMessagePresenter.RetainedState quotedMessageState;

private RetainedState(
MessageBuilder messageBuilder,
QuotedMessagePresenter.RetainedState quotedMessageState) {
this.messageBuilder = messageBuilder;
this.quotedMessageState = quotedMessageState;
}
}

@Override
public void onMessageBuildCancel() {
sendMessageHasBeenTriggered = false;
Expand Down Expand Up @@ -1940,6 +1995,18 @@ public void messageUidChanged(LegacyAccountDto account, long folderId, String ol

};

private void launchAttachmentPicker(int requestCode) {
composerContent.setSaveFromParentEnabled(false);

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
isInSubActivity = true;

startActivityForResult(Intent.createChooser(intent, null), requestCode);
}

AttachmentMvpView attachmentMvpView = new AttachmentMvpView() {
private HashMap<Uri, View> attachmentViews = new HashMap<>();

Expand Down Expand Up @@ -1981,13 +2048,17 @@ public void dismissWaitingForAttachmentDialog() {
public void showPickAttachmentDialog(int requestCode) {
requestCode |= REQUEST_MASK_ATTACHMENT_PRESENTER;

Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
isInSubActivity = true;
if (account.hasDraftsFolder() && (draftMessageId == null || changesMadeSinceLastSave)) {
pendingAttachmentPickerRequestCode = requestCode;
performSaveAfterChecks();
if (currentMessageBuilder == null) {
pendingAttachmentPickerRequestCode = null;
MessageCompose.this.launchAttachmentPicker(requestCode);
}
return;
}

startActivityForResult(Intent.createChooser(i, null), requestCode);
MessageCompose.this.launchAttachmentPicker(requestCode);
}

@Override
Expand Down Expand Up @@ -2100,6 +2171,11 @@ public void handleMessage(android.os.Message msg) {
MessageCompose.this,
getString(R.string.message_saved_toast),
Toast.LENGTH_LONG).show();
if (pendingAttachmentPickerRequestCode != null) {
int requestCode = pendingAttachmentPickerRequestCode;
pendingAttachmentPickerRequestCode = null;
launchAttachmentPicker(requestCode);
}
break;
case MSG_DISCARDED_DRAFT:
Toast.makeText(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@


public class QuotedMessagePresenter {
private static final String STATE_KEY_HTML_QUOTE = "state:htmlQuote";
private static final String STATE_KEY_QUOTED_TEXT_MODE = "state:quotedTextShown";
private static final String STATE_KEY_QUOTED_TEXT_FORMAT = "state:quotedTextFormat";
private static final String STATE_KEY_FORCE_PLAIN_TEXT = "state:forcePlainText";
Expand Down Expand Up @@ -150,18 +149,10 @@ public void builderSetProperties(MessageBuilder builder) {
}

public void onSaveInstanceState(Bundle outState) {
outState.putSerializable(STATE_KEY_QUOTED_TEXT_MODE, quotedTextMode);
outState.putSerializable(STATE_KEY_HTML_QUOTE, quotedHtmlContent);
outState.putSerializable(STATE_KEY_QUOTED_TEXT_FORMAT, quotedTextFormat);
outState.putBoolean(STATE_KEY_FORCE_PLAIN_TEXT, forcePlainText);
saveState(outState, quotedTextMode, quotedTextFormat, forcePlainText);
}

public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
quotedHtmlContent = BundleCompat.INSTANCE.getSerializable(
savedInstanceState,
STATE_KEY_HTML_QUOTE,
InsertableHtmlContent.class
);
quotedTextFormat = BundleCompat.getSerializable(
savedInstanceState,
STATE_KEY_QUOTED_TEXT_FORMAT,
Expand All @@ -177,13 +168,52 @@ public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
QuotedTextMode.class
)
);
}

static void saveState(
Bundle outState,
QuotedTextMode quotedTextMode,
SimpleMessageFormat quotedTextFormat,
boolean forcePlainText) {
outState.putSerializable(STATE_KEY_QUOTED_TEXT_MODE, quotedTextMode);
outState.putSerializable(STATE_KEY_QUOTED_TEXT_FORMAT, quotedTextFormat);
outState.putBoolean(STATE_KEY_FORCE_PLAIN_TEXT, forcePlainText);
}

public RetainedState retainState() {
return new RetainedState(quotedTextMode, quotedTextFormat, quotedHtmlContent, forcePlainText);
}

public void restoreState(RetainedState state) {
quotedTextMode = state.quotedTextMode;
quotedTextFormat = state.quotedTextFormat;
quotedHtmlContent = state.quotedHtmlContent;
forcePlainText = state.forcePlainText;

showOrHideQuotedText(quotedTextMode);
if (quotedHtmlContent != null && quotedHtmlContent.getQuotedContent() != null) {
// we don't have the part here, but inline-displayed images are cached by the webview
view.setQuotedHtml(quotedHtmlContent.getQuotedContent(), null);
}
}

public static final class RetainedState {
private final QuotedTextMode quotedTextMode;
private final SimpleMessageFormat quotedTextFormat;
private final InsertableHtmlContent quotedHtmlContent;
private final boolean forcePlainText;

private RetainedState(
QuotedTextMode quotedTextMode,
SimpleMessageFormat quotedTextFormat,
InsertableHtmlContent quotedHtmlContent,
boolean forcePlainText) {
this.quotedTextMode = quotedTextMode;
this.quotedTextFormat = quotedTextFormat;
this.quotedHtmlContent = quotedHtmlContent;
this.forcePlainText = forcePlainText;
}
}

public void processMessageToForward(MessageViewInfo messageViewInfo) throws MessagingException {
quoteStyle = QuoteStyle.HEADER;
populateUIWithQuotedMessage(messageViewInfo, true, Action.FORWARD);
Expand Down
Loading
Loading