Skip to content

Let marking unread, favoriting and archiving survive being offline or killed - #6719

Draft
AndyScherzinger wants to merge 1 commit into
feat/noid/optimisticRemindersfrom
feat/noid/durableConversationActions
Draft

AndyScherzinger wants to merge 1 commit into
feat/noid/optimisticRemindersfrom
feat/noid/durableConversationActions

Conversation

@AndyScherzinger

Copy link
Copy Markdown
Member

Stacked on #6717, which is stacked on #6715 and #6694 — review those first. This branch targets feat/noid/optimisticReminders and will be retargeted as the stack merges.

Marking a conversation unread, favoriting it and archiving it were optimistic but not durable. The local entry changed at once, then the request had two attempts in the view model's scope, and anything that stopped it there reverted the change. Two cases that made worse:

  • Offline. The tap applied, both attempts failed within about a second, and the row flipped back — the app knew it had no connection and still threw the change away.
  • The process going away. Archiving a conversation and immediately swiping the app off the recents list left the change in the local database with its in-memory guard gone, so the next room list sync quietly put the old value back.

feat(conversation list): let unread, favorite and archive outlive the app — the three actions now hand the request to a new ConversationActionWorker, the way the read marker already goes through ReadMarkerSyncWorker. The worker carries a NetworkType.CONNECTED constraint, so a change made offline waits for a connection instead of being discarded, and it retries with exponential backoff across process death. Work is unique per conversation and action with REPLACE, so favoriting and unfavoriting in quick succession sends only the last intent, while archiving and marking unread on the same conversation stay independent.

This is only safe because each of these sets a value rather than moving one. Verified against a Nextcloud 36 dev instance running Talk main: POST …/favorite, POST …/archive and DELETE …/chat/{token}/read each answer 200 twice in a row and leave the same state, so a retry can never overshoot. That is the opposite of the note-to-self share in #6717, which has no such guarantee and therefore reads back before retrying.

Failure handling keeps both halves. While the list is still on screen it observes the work and, when the worker has used up its attempts, puts the conversation back and shows the error snackbar exactly as before. When the list is gone the worker releases the pending guard instead, and the next room list sync restores the server state.

Known limitation, deliberately not solved here. The pending guard lives in memory in ConversationListUpdater. If the process dies before the worker runs, the guard is gone, so a room list sync between the restart and the worker finishing can show the old value for a moment before the worker's success brings it back. Making the guard durable means persisting it next to the conversation entry, which is a schema change and its own review.

🖼️ Screenshots

No UI was added or changed. The archive snackbar now appears when the row moves rather than when the server answers.

🏁 Checklist

  • ⛑️ Tests (unit and/or integration) are included or not needed — five tests cover what the work is named, which decides what replaces what, and the action round trip through the work input; both are silent to break
  • 🔖 Capability is checked or not needed
  • 🔙 Backport requests are created or not needed — not backported, this goes into 25.1.0
  • 📅 Milestone is set
  • 🌸 PR title is meaningful (if it should be in the changelog: is it meaningful to users?)

🤖 AI (if applicable)

  • The content of this PR was partly or fully generated using AI

… app

All three reverted themselves when the request did not come back, so a tap
taken offline flickered and a tap taken just before the app was killed was
lost. They now go to a worker, the way the read marker does, which waits for
a connection and survives the process.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
@AndyScherzinger AndyScherzinger added this to the 25.1.0 milestone Sep 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant