fix: Correctly handle setting / editing a status' language (#780)

Previous code set the initial status text, and then set up the callbacks
which meant that the status' length was initially 0, even when editing a
status.

This meant that, e.g., editing a status to change its language would
erroneously report the status body was empty. It also meant that editing
a status and changing just the language would not prompt to save or
discard the changes if moving back.

Fix this.

First, only set the status content after the callbacks that compute the
status length.

Second, provide a function that sets the status' language, and update
the close confirmation state when the language changes. Modify isDirty()
to compare the original and current language when determining if the
status is dirty.

Fixes #701
This commit is contained in:
Nik Clayton 2024-06-25 13:39:14 +02:00 committed by GitHub
parent ce1cf67292
commit 04b7ce47a2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 26 additions and 14 deletions

View File

@ -413,6 +413,13 @@ class ComposeActivity :
)
binding.composeEditField.setTokenizer(ComposeTokenizer())
val mentionColour = binding.composeEditField.linkTextColors.defaultColor
highlightSpans(binding.composeEditField.text, mentionColour)
binding.composeEditField.doAfterTextChanged { editable ->
highlightSpans(editable!!, mentionColour)
viewModel.onContentChanged(editable)
}
binding.composeEditField.setText(startingText)
when (composeOptions?.initialCursorPosition ?: InitialCursorPosition.END) {
@ -422,13 +429,6 @@ class ComposeActivity :
)
}
val mentionColour = binding.composeEditField.linkTextColors.defaultColor
highlightSpans(binding.composeEditField.text, mentionColour)
binding.composeEditField.doAfterTextChanged { editable ->
highlightSpans(editable!!, mentionColour)
viewModel.onContentChanged(editable)
}
// work around Android platform bug -> https://issuetracker.google.com/issues/67102093
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O ||
Build.VERSION.SDK_INT == Build.VERSION_CODES.O_MR1
@ -594,7 +594,7 @@ class ComposeActivity :
private fun setupLanguageSpinner(initialLanguages: List<String>) {
binding.composePostLanguageButton.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>, view: View?, position: Int, id: Long) {
viewModel.postLanguage = (parent.adapter.getItem(position) as Locale).modernLanguageCode
viewModel.onLanguageChanged((parent.adapter.getItem(position) as Locale).modernLanguageCode)
}
override fun onNothingSelected(parent: AdapterView<*>) {
@ -927,7 +927,7 @@ class ComposeActivity :
@VisibleForTesting
val selectedLanguage: String?
get() = viewModel.postLanguage
get() = viewModel.language
private fun updateVisibleCharactersLeft(textLength: Int) {
val remainingLength = maximumTootCharacters - textLength

View File

@ -89,7 +89,11 @@ class ComposeViewModel @Inject constructor(
/** The initial content warning for this status, before any edits */
private var initialContentWarning: String = ""
internal var postLanguage: String? = null
/** The initial language for this status, before any changes */
private var initialLanguage: String? = null
/** The current language for this status. */
internal var language: String? = null
/** If editing a draft then the ID of the draft, otherwise 0 */
private var draftId: Int = 0
@ -279,6 +283,12 @@ class ComposeViewModel @Inject constructor(
_statusVisibility.value = newVisibility
}
/** Call this to change the status' language */
fun onLanguageChanged(newLanguage: String) {
language = newLanguage
updateCloseConfirmation()
}
@VisibleForTesting
fun updateStatusLength() {
_statusLength.value = statusLength(content, effectiveContentWarning, instanceInfo.value.charactersReservedPerUrl)
@ -317,8 +327,9 @@ class ComposeViewModel @Inject constructor(
val contentWarningChanged = effectiveContentWarning != initialContentWarning
val mediaChanged = media.value.isNotEmpty()
val pollChanged = poll.value != null
val languageChanged = initialLanguage != language
return modifiedInitialState || contentChanged || contentWarningChanged || mediaChanged || pollChanged || scheduledTimeChanged
return modifiedInitialState || contentChanged || contentWarningChanged || mediaChanged || pollChanged || languageChanged || scheduledTimeChanged
}
private fun isEmpty(content: CharSequence, contentWarning: CharSequence): Boolean {
@ -375,7 +386,7 @@ class ComposeViewModel @Inject constructor(
failedToSend = false,
failedToSendAlert = false,
scheduledAt = scheduledAt.value,
language = postLanguage,
language = language,
statusId = originalStatusId,
)
}
@ -418,7 +429,7 @@ class ComposeViewModel @Inject constructor(
draftId = draftId,
idempotencyKey = randomAlphanumericString(16),
retries = 0,
language = postLanguage,
language = language,
statusId = originalStatusId,
)
@ -538,7 +549,8 @@ class ComposeViewModel @Inject constructor(
scheduledTootId = composeOptions?.scheduledTootId
originalStatusId = composeOptions?.statusId
initialContent = composeOptions?.content ?: ""
postLanguage = composeOptions?.language
initialLanguage = composeOptions?.language
language = initialLanguage
val tootVisibility = composeOptions?.visibility ?: Status.Visibility.UNKNOWN
if (tootVisibility != Status.Visibility.UNKNOWN) {