Add post editing capability (#2828)

* Add post editing capability

* Don't try to reprocess already uploaded attachments.
Fixes editing posts with existing media

* Don't mark post edits as modified until editing occurs

* Disable UI for things that can't be edited when editing a post

* Finally convert SFragment to kotlin

* Use api endpoint for fetching status source for editing

* Apply review feedback
This commit is contained in:
Levi Bard 2022-12-08 10:18:12 +01:00 committed by GitHub
commit a6b6a40ba6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 676 additions and 527 deletions

View file

@ -238,15 +238,14 @@ class ComposeActivity :
binding.composeMediaPreviewBar.adapter = mediaAdapter
binding.composeMediaPreviewBar.itemAnimator = null
setupButtons()
subscribeToUpdates(mediaAdapter)
/* If the composer is started up as a reply to another post, override the "starting" state
* based on what the intent from the reply request passes. */
val composeOptions: ComposeOptions? = intent.getParcelableExtra(COMPOSE_OPTIONS_EXTRA)
viewModel.setup(composeOptions)
setupButtons()
subscribeToUpdates(mediaAdapter)
if (accountManager.shouldDisplaySelfUsername(this)) {
binding.composeUsernameView.text = getString(
R.string.compose_active_account_description,
@ -708,20 +707,25 @@ class ComposeActivity :
}
private fun updateScheduleButton() {
@ColorInt val color = if (binding.composeScheduleView.time == null) {
ThemeUtils.getColor(this, android.R.attr.textColorTertiary)
if (viewModel.editing) {
// Can't reschedule a published status
enableButton(binding.composeScheduleButton, clickable = false, colorActive = false)
} else {
getColor(R.color.tusky_blue)
@ColorInt val color = if (binding.composeScheduleView.time == null) {
ThemeUtils.getColor(this, android.R.attr.textColorTertiary)
} else {
getColor(R.color.tusky_blue)
}
binding.composeScheduleButton.drawable.colorFilter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)
}
binding.composeScheduleButton.drawable.colorFilter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)
}
private fun enableButtons(enable: Boolean) {
private fun enableButtons(enable: Boolean, editing: Boolean) {
binding.composeAddMediaButton.isClickable = enable
binding.composeToggleVisibilityButton.isClickable = enable
binding.composeToggleVisibilityButton.isClickable = enable && !editing
binding.composeEmojiButton.isClickable = enable
binding.composeHideMediaButton.isClickable = enable
binding.composeScheduleButton.isClickable = enable
binding.composeScheduleButton.isClickable = enable && !editing
binding.composeTootButton.isEnabled = enable
}
@ -737,6 +741,10 @@ class ComposeActivity :
else -> R.drawable.ic_lock_open_24dp
}
binding.composeToggleVisibilityButton.setImageResource(iconRes)
if (viewModel.editing) {
// Can't update visibility on published status
enableButton(binding.composeToggleVisibilityButton, clickable = false, colorActive = false)
}
}
private fun showComposeOptions() {
@ -938,7 +946,7 @@ class ComposeActivity :
}
private fun sendStatus() {
enableButtons(false)
enableButtons(false, viewModel.editing)
val contentText = binding.composeEditField.text.toString()
var spoilerText = ""
if (viewModel.showContentWarning.value) {
@ -947,7 +955,7 @@ class ComposeActivity :
val characterCount = calculateTextLength()
if ((characterCount <= 0 || contentText.isBlank()) && viewModel.media.value.isEmpty()) {
binding.composeEditField.error = getString(R.string.error_empty)
enableButtons(true)
enableButtons(true, viewModel.editing)
} else if (characterCount <= maximumTootCharacters) {
if (viewModel.media.value.isNotEmpty()) {
finishingUploadDialog = ProgressDialog.show(
@ -963,7 +971,7 @@ class ComposeActivity :
}
} else {
binding.composeEditField.error = getString(R.string.error_compose_character_limit)
enableButtons(true)
enableButtons(true, viewModel.editing)
}
}
@ -1179,7 +1187,8 @@ class ComposeActivity :
val uploadPercent: Int = 0,
val id: String? = null,
val description: String? = null,
val focus: Attachment.Focus? = null
val focus: Attachment.Focus? = null,
val processed: Boolean = false,
) {
enum class Type {
IMAGE, VIDEO, AUDIO;
@ -1230,6 +1239,7 @@ class ComposeActivity :
var poll: NewPoll? = null,
var modifiedInitialState: Boolean? = null,
var language: String? = null,
var statusId: String? = null,
) : Parcelable
companion object {

View file

@ -73,6 +73,7 @@ class ComposeViewModel @Inject constructor(
private var scheduledTootId: String? = null
private var startingContentWarning: String = ""
private var inReplyToId: String? = null
private var originalStatusId: String? = null
private var startingVisibility: Status.Visibility = Status.Visibility.UNKNOWN
private var contentWarningStateChanged: Boolean = false
@ -193,7 +194,8 @@ class ComposeViewModel @Inject constructor(
uploadPercent = -1,
id = id,
description = description,
focus = focus
focus = focus,
processed = true,
)
mediaValue + mediaItem
}
@ -270,6 +272,7 @@ class ComposeViewModel @Inject constructor(
failedToSend = false,
scheduledAt = scheduledAt.value,
language = postLanguage,
statusId = originalStatusId,
)
}
@ -299,7 +302,7 @@ class ComposeViewModel @Inject constructor(
mediaUris.add(item.uri)
mediaDescriptions.add(item.description ?: "")
mediaFocus.add(item.focus)
mediaProcessed.add(false)
mediaProcessed.add(item.processed)
}
val tootToSend = StatusToSend(
text = content,
@ -321,6 +324,7 @@ class ComposeViewModel @Inject constructor(
retries = 0,
mediaProcessed = mediaProcessed,
language = postLanguage,
statusId = originalStatusId,
)
serviceClient.sendToot(tootToSend)
@ -452,6 +456,7 @@ class ComposeViewModel @Inject constructor(
draftId = composeOptions?.draftId ?: 0
scheduledTootId = composeOptions?.scheduledTootId
originalStatusId = composeOptions?.statusId
startingText = composeOptions?.content
postLanguage = composeOptions?.language
@ -497,6 +502,9 @@ class ComposeViewModel @Inject constructor(
scheduledAt.value = newScheduledAt
}
val editing: Boolean
get() = !originalStatusId.isNullOrEmpty()
private companion object {
const val TAG = "ComposeViewModel"
}

View file

@ -48,10 +48,13 @@ class MediaPreviewAdapter(
val addFocusId = 2
val editImageId = 3
val removeId = 4
popup.menu.add(0, addCaptionId, 0, R.string.action_set_caption)
if (item.type == ComposeActivity.QueuedMedia.Type.IMAGE) {
popup.menu.add(0, addFocusId, 0, R.string.action_set_focus)
popup.menu.add(0, editImageId, 0, R.string.action_edit_image)
if (!item.processed) {
// Already-published items can't have their metadata edited
popup.menu.add(0, addCaptionId, 0, R.string.action_set_caption)
if (item.type == ComposeActivity.QueuedMedia.Type.IMAGE) {
popup.menu.add(0, addFocusId, 0, R.string.action_set_focus)
popup.menu.add(0, editImageId, 0, R.string.action_edit_image)
}
}
popup.menu.add(0, removeId, 0, R.string.action_remove)
popup.setOnMenuItemClickListener { menuItem ->