Skip to content

Rewrite Conversation screen with Kotlin and Compose#109

Open
RankoR wants to merge 94 commits intoGrapheneOS:mainfrom
RankoR-GOS:task/conversation-compose-main
Open

Rewrite Conversation screen with Kotlin and Compose#109
RankoR wants to merge 94 commits intoGrapheneOS:mainfrom
RankoR-GOS:task/conversation-compose-main

Conversation

@RankoR
Copy link
Copy Markdown
Contributor

@RankoR RankoR commented May 1, 2026

First (of 3) PR with Conversation screen rewritten with Kotlin and Compose.

I've split it into 3 PRs:

  • This one, containing the main code changes
  • Compose @Previews
  • Tests

This split is required because it's a very large rewrite, so it makes it easier to review. I will create the remaining two after this one is merged.

For reference, all changes together are in https://github.com/RankoR-GOS/Messaging/commits/task/coversation-compose.

Here's a demo (the lags are coming from my emulator, not from the app itself):

messages.mp4

RankoR added 30 commits March 26, 2026 20:01
@RankoR RankoR requested review from inthewaves and muhomorr May 1, 2026 11:31
Copy link
Copy Markdown
Member

@inthewaves inthewaves left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good so far, haven't looked too deeply at the code yet. Some things from testing it:

  1. One bug I've noticed is that if a message contains a hyperlink, selecting the message makes the hyperlink invisible (videos below show this)

  2. I think we should hide the number/name on the incoming message bubbles if the conversation is a 1-1 thread

  3. Message details dialog popup looks untouched (e.g. doesn't follow dark theme)

  4. I didn't intentionally set it up this way, but my colors for Material You under OS Settings > Wallpaper & style > Colors were setup like this:
    Image

    With these colors, the contrast for selected outgoing messages is hard to see in dark mode. Also link color contrast issue makes links hard to see (link is https://example.com):

    messages-select-contrast.mp4
  5. I can't long press a message containing just a link. Generally, long presses don't select when the pointer is over a link. I think ideally long pressing a link should just select the message instead of opening the link as well; this matches the old Messages behavior

    messages-link-select.mp4
  6. Showing the phone number in the top app bar is debatable as the old Messages app doesn't do it. Google Messages and Signal also hides the number in the app bar. My preference is that we don't show it

    As a side note, Signal used to also show the number at the top, and this also used to be a talking point for many users e.g. https://community.signalusers.org/t/option-to-hide-contact-phone-number-on-the-top-of-the-chat/4455/7. Signal finally hid the number at the top in https://community.signalusers.org/t/option-to-hide-contact-phone-number-on-the-top-of-the-chat/4455/38

@thomasbuilds
Copy link
Copy Markdown

thomasbuilds commented May 3, 2026

I got interested in the PR and found a bug:

ConversationDraftStore.getSelfParticipantId() declares a nullable return, and every caller treats null as "no self available, bail out". But the implementation maps null"":

return conversation.selfId.orEmpty()

ConversationListItemData.selfId is genuinely null in real flows (newly‑created threads before any send, multi‑SIM before a SIM is picked, after SIM swap/removal). The empty string then defeats the null‑guards in ConversationDraftsRepository:

  • Load (loadConversationDraft, L112–L115): ?: return ConversationDraft() never fires; the DB is then queried with WHERE self_id = '', returns nothing, and any draft saved under the real self_id appears to vanish until current_self_id is populated.
  • Save (bindDraftParticipantsIfNeededbindMissingDraftParticipants, L215–L250): the mapper correctly produces message.selfId = null for a blank draft self id, but bindMissingDraftParticipants then overwrites it with "", persisting self_id = "" and participant_id = "" into the draft message row. That row will never match participant lookups on the next load.

Suggested fix

Honor the String? contract:

        return conversation.selfId?.takeIf { it.isNotBlank() }

Optional defence‑in‑depth in ConversationDraftsRepository.bindMissingDraftParticipants:

if (selfParticipantId.isBlank()) return message

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.

3 participants