Skip to content

Commit

Permalink
Fix AI messages not being taken into account when saving a draft in s…
Browse files Browse the repository at this point in the history
…ome cases

The bug would happen in this situation:

* When generating a message with AI, as AiPropositionFragment is navigated to, NewMessageFragment would export his body in the `subjectAndBodyChannel`.
* When inserting the AI proposition, we would navigate back to NewMessageFragment.
* When we want to now save or send the draft we will receive values through the channel but the channel's value was never consumed and the previous body is still there even though we want to wait for the new body.

This commit introduces a `channelExpirationIdTarget` that will let us know if a message is too old and needs to be discarded while we wait for the correct message to get through the channel
  • Loading branch information
LunarX committed Jul 12, 2024
1 parent d38278b commit 8d09a68
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,11 @@ class NewMessageFragment : Fragment() {
}
}

override fun onStart() {
super.onStart()
newMessageViewModel.discardOldBodyAndSubjectChannelMessages()
}

override fun onStop() {
/**
* When the Activity is being stopped, we save the Draft.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,13 @@ class NewMessageViewModel @Inject constructor(

val editorBodyLoader = SingleLiveEvent<BodyContentPayload>()

private val _subjectAndBodyChannel: Channel<Pair<String, String>> = Channel(capacity = CONFLATED)
private val subjectAndBodyChannel: ReceiveChannel<Pair<String, String>> = _subjectAndBodyChannel
// 1. Navigating to AiPropositionFragment causes NewMessageFragment to export its body to `subjectAndBodyChannel`.
// 2. Inserting the AI proposition navigates back to NewMessageFragment.
// 3. When saving or sending the draft now, the channel still holds the previous body as it wasn't consumed.
// channelExpirationIdTarget lets us identify and discard outdated messages, ensuring the correct message is processed.
private var channelExpirationIdTarget = 0
private val _subjectAndBodyChannel: Channel<Triple<String, String, Int>> = Channel(capacity = CONFLATED)
private val subjectAndBodyChannel: ReceiveChannel<Triple<String, String, Int>> = _subjectAndBodyChannel
private var subjectAndBodyJob: Job? = null

var isAutoCompletionOpened = false
Expand Down Expand Up @@ -754,14 +759,28 @@ class NewMessageViewModel @Inject constructor(

fun saveBodyAndSubject(subject: String, html: String) {
globalCoroutineScope.launch {
_subjectAndBodyChannel.send(subject to html)
_subjectAndBodyChannel.send(Triple(subject, html, channelExpirationIdTarget))
}
}

fun discardOldBodyAndSubjectChannelMessages() {
channelExpirationIdTarget++
}

fun waitForBodyAndSubjectToExecuteDraftAction(draftSaveConfiguration: DraftSaveConfiguration) {
subjectAndBodyJob?.cancel()
subjectAndBodyJob = globalCoroutineScope.launch {
val (subject, body) = subjectAndBodyChannel.receive()
val subject: String
val body: String
while (true) {
val (receivedSubject, receivedBody, expirationId) = subjectAndBodyChannel.receive()
if (expirationId == channelExpirationIdTarget) {
subject = receivedSubject
body = receivedBody
break
}
}

draftSaveConfiguration.addSubjectAndBody(subject, body)
executeDraftAction(draftSaveConfiguration)
}
Expand Down

0 comments on commit 8d09a68

Please sign in to comment.