diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java index 8d78c01c5..0741b241a 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java @@ -27,7 +27,6 @@ import android.text.Layout; import android.text.Spanned; import android.text.TextUtils; import android.text.TextWatcher; -import android.text.format.DateUtils; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; @@ -196,19 +195,12 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr private boolean attachmentsErrorShowing; private Status editingStatus; + private boolean redraftStatus; private boolean pollChanged; private boolean creatingView; private boolean ignoreSelectionChanges=false; private Runnable updateUploadEtaRunnable; - public static DraftMediaAttachment redraftAttachment(Attachment att) { - DraftMediaAttachment draft=new DraftMediaAttachment(); - draft.serverAttachment=att; - draft.description=att.description; - draft.uri=Uri.parse(att.url); - return draft; - } - @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); @@ -222,6 +214,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr instance=AccountSessionManager.getInstance().getInstanceInfo(instanceDomain); if(getArguments().containsKey("editStatus")){ editingStatus=Parcels.unwrap(getArguments().getParcelable("editStatus")); + redraftStatus=getArguments().getBoolean("redraftStatus"); } if(instance==null){ Nav.finish(this); @@ -328,18 +321,11 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr pollDurationView.setOnClickListener(v->showPollDurationMenu()); pollOptions.clear(); - ArrayList restoredPollOptions=(savedInstanceState!=null ? savedInstanceState : getArguments()) - .getStringArrayList("pollOptions"); - if(restoredPollOptions!=null){ - if(savedInstanceState==null){ - // restoring from arguments - pollDuration=getArguments().getInt("pollDuration"); - pollDurationStr=DateUtils.formatElapsedTime(pollDuration); // getResources().getQuantityString(R.plurals.x_hours, pollDuration/3600); - } + if(savedInstanceState!=null && savedInstanceState.containsKey("pollOptions")){ pollBtn.setSelected(true); mediaBtn.setEnabled(false); pollWrap.setVisibility(View.VISIBLE); - for(String oldText:restoredPollOptions){ + for(String oldText:savedInstanceState.getStringArrayList("pollOptions")){ DraftPollOption opt=createDraftPollOption(); opt.edit.setText(oldText); } @@ -374,13 +360,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr spoilerBtn.setSelected(true); } - sensitive = editingStatus != null ? editingStatus.sensitive - : (savedInstanceState != null && savedInstanceState.getBoolean("sensitive", false)); - sensitiveIcon.setSelected(sensitive); - - ArrayList serializedAttachments=(savedInstanceState!=null ? savedInstanceState : getArguments()) - .getParcelableArrayList("attachments"); - if(serializedAttachments!=null){ + if(savedInstanceState!=null && savedInstanceState.containsKey("attachments")){ + ArrayList serializedAttachments=savedInstanceState.getParcelableArrayList("attachments"); for(Parcelable a:serializedAttachments){ DraftMediaAttachment att=Parcels.unwrap(a); attachmentsView.addView(createMediaAttachmentView(att)); @@ -540,7 +521,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr spoilerBtn.setSelected(true); } } - }else{ + }else if (editingStatus==null || editingStatus.inReplyToId==null){ + // TODO: remove workaround after https://github.com/mastodon/mastodon-android/issues/341 gets fixed replyText.setVisibility(View.GONE); } if(savedInstanceState==null){ @@ -592,7 +574,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){ publishButton=new Button(getActivity()); - publishButton.setText(editingStatus==null ? R.string.publish : R.string.save); + publishButton.setText(editingStatus==null || redraftStatus ? R.string.publish : R.string.save); publishButton.setOnClickListener(this::onPublishClick); LinearLayout wrap=new LinearLayout(getActivity()); wrap.setOrientation(LinearLayout.HORIZONTAL); @@ -697,8 +679,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr if(!attachments.isEmpty()){ req.mediaIds=attachments.stream().map(a->a.serverAttachment.id).collect(Collectors.toList()); } - if(replyTo!=null){ - req.inReplyToId=replyTo.id; + if(replyTo!=null || editingStatus.inReplyToId!=null){ + req.inReplyToId=editingStatus!=null ? editingStatus.inReplyToId : replyTo.id; } if(!pollOptions.isEmpty()){ req.poll=new CreateStatus.Request.Poll(); @@ -741,6 +723,13 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr E.post(new StatusUpdatedEvent(result)); } Nav.finish(ComposeFragment.this); + if (getArguments().getBoolean("navigateToStatus", false)) { + Bundle args=new Bundle(); + args.putString("account", accountID); + args.putParcelable("status", Parcels.wrap(result)); + if(replyTo!=null) args.putParcelable("inReplyToAccount", Parcels.wrap(replyTo)); + Nav.go(getActivity(), ThreadFragment.class, args); + } } @Override @@ -754,7 +743,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr } }; - if(editingStatus!=null){ + if(editingStatus!=null && !redraftStatus){ new EditStatus(req, editingStatus.id) .setCallback(resCallback) .exec(accountID); diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java index 0939acc0e..bd89691fc 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java @@ -26,6 +26,7 @@ import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.fragments.BaseStatusListFragment; import org.joinmastodon.android.fragments.ComposeFragment; import org.joinmastodon.android.fragments.ProfileFragment; +import org.joinmastodon.android.fragments.ThreadFragment; import org.joinmastodon.android.fragments.report.ReportReasonChoiceFragment; import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Attachment; @@ -137,10 +138,18 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ optionsMenu.setOnMenuItemClickListener(menuItem->{ Account account=item.user; int id=menuItem.getItemId(); - if(id==R.id.edit){ + if(id==R.id.edit || id==R.id.delete_and_redraft) { final Bundle args=new Bundle(); args.putString("account", item.parentFragment.getAccountID()); args.putParcelable("editStatus", Parcels.wrap(item.status)); + if (id==R.id.delete_and_redraft) { + args.putBoolean("redraftStatus", true); + if (item.parentFragment instanceof ThreadFragment thread && !thread.isItemEnabled(item.status.id)) { + // ("enabled" = clickable; opened status is not clickable) + // request navigation to the re-drafted status if status is currently opened + args.putBoolean("navigateToStatus", true); + } + } if(TextUtils.isEmpty(item.status.content) && TextUtils.isEmpty(item.status.spoilerText)){ Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args); }else{ @@ -150,7 +159,13 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ public void onSuccess(GetStatusSourceText.Response result){ args.putString("sourceText", result.text); args.putString("sourceSpoiler", result.spoilerText); - Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args); + if (id==R.id.delete_and_redraft) { + UiUtils.confirmDeletePost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, s->{ + Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args); + }, true); + } else { + Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args); + } } @Override @@ -163,8 +178,6 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ } }else if(id==R.id.delete){ UiUtils.confirmDeletePost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, s->{}); - }else if(id==R.id.delete_and_redraft) { - UiUtils.confirmDeleteAndRedraftPost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, s->{}); }else if(id==R.id.pin || id==R.id.unpin){ UiUtils.confirmPinPost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, !item.status.pinned, s->{}); }else if(id==R.id.mute){ diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java index f7aa0ab4c..bd7e657f1 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java @@ -19,7 +19,6 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; -import android.os.Parcelable; import android.provider.OpenableColumns; import android.text.SpannableStringBuilder; import android.text.Spanned; @@ -58,10 +57,8 @@ import org.joinmastodon.android.model.Emoji; import org.joinmastodon.android.model.ListTimeline; import org.joinmastodon.android.model.Relationship; import org.joinmastodon.android.model.Status; -import org.joinmastodon.android.model.StatusPrivacy; import org.joinmastodon.android.ui.M3AlertDialogBuilder; import org.joinmastodon.android.ui.text.CustomEmojiSpan; -import org.joinmastodon.android.ui.text.HtmlParser; import org.joinmastodon.android.ui.text.SpacerSpan; import org.parceler.Parcels; @@ -72,8 +69,6 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.FormatStyle; -import java.time.temporal.ChronoUnit; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -87,10 +82,6 @@ import androidx.annotation.StringRes; import androidx.browser.customtabs.CustomTabsIntent; import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.RecyclerView; - -import com.google.gson.Gson; -import com.google.gson.annotations.SerializedName; - import me.grishka.appkit.Nav; import me.grishka.appkit.api.Callback; import me.grishka.appkit.api.ErrorResponse; @@ -403,9 +394,12 @@ public class UiUtils{ .exec(accountID); }); } - public static void confirmDeletePost(Activity activity, String accountID, Status status, Consumer resultCallback){ - showConfirmationAlert(activity, R.string.confirm_delete_title, R.string.confirm_delete, R.string.delete, ()->{ + confirmDeletePost(activity, accountID, status, resultCallback, false); + } + + public static void confirmDeletePost(Activity activity, String accountID, Status status, Consumer resultCallback, boolean forRedraft){ + showConfirmationAlert(activity, forRedraft ? R.string.confirm_delete_and_redraft_title : R.string.confirm_delete_title, forRedraft ? R.string.confirm_delete_and_redraft : R.string.confirm_delete, forRedraft ? R.string.delete_and_redraft : R.string.delete, ()->{ new DeleteStatus(status.id) .setCallback(new Callback<>(){ @Override @@ -452,61 +446,6 @@ public class UiUtils{ ); } - public static void confirmDeleteAndRedraftPost(Activity activity, String accountID, Status status, Consumer resultCallback){ - showConfirmationAlert(activity, R.string.confirm_delete_and_redraft_title, R.string.confirm_delete_and_redraft, R.string.delete_and_redraft, ()->{ - new DeleteStatus(status.id) - .setCallback(new Callback<>(){ - @Override - public void onSuccess(Status result){ - resultCallback.accept(result); - AccountSessionManager.getInstance().getAccount(accountID).getCacheController().deleteStatus(status.id); - E.post(new StatusDeletedEvent(status.id, accountID)); - UiUtils.redraftStatus(status, accountID, activity); - } - - @Override - public void onError(ErrorResponse error){ - error.showToast(activity); - } - }) - .wrapProgress(activity, R.string.deleting, false) - .exec(accountID); - }); - } - - public static void redraftStatus(Status status, String accountID, Activity activity) { - Bundle args=new Bundle(); - args.putString("account", accountID); - args.putBoolean("hasDraft", true); - args.putString("prefilledText", HtmlParser.parse(status.content, status.emojis, status.mentions, status.tags, accountID).toString()); - args.putString("spoilerText", status.spoilerText); - args.putSerializable("visibility", status.visibility); - if(status.poll!=null){ - args.putInt("pollDuration", (int)status.poll.expiresAt.minus(status.createdAt.getEpochSecond(), ChronoUnit.SECONDS).getEpochSecond()); - ArrayList opts=status.poll.options.stream().map(o -> o.title).collect(Collectors.toCollection(ArrayList::new)); - args.putStringArrayList("pollOptions", opts); - } - if(!status.mediaAttachments.isEmpty()){ - ArrayList serializedAttachments=status.mediaAttachments.stream() - .map(att -> Parcels.wrap(ComposeFragment.redraftAttachment(att))) - .collect(Collectors.toCollection(ArrayList::new)); - args.putParcelableArrayList("attachments", serializedAttachments); - } - Callback cb=new Callback<>(){ - @Override public void onError(ErrorResponse error) { - onSuccess(null); - error.showToast(activity); - } - @Override public void onSuccess(Status status) { - if (status!=null) args.putParcelable("replyTo", Parcels.wrap(status)); - Nav.go(activity, ComposeFragment.class, args); - } - }; - - if(status.inReplyToId!=null) new GetStatusByID(status.inReplyToId).setCallback(cb).exec(accountID); - else cb.onSuccess(null); - } - public static void setRelationshipToActionButton(Relationship relationship, Button button){ setRelationshipToActionButton(relationship, button, false); }