feat(dm): explain the mutual-follow rule when the recipient list is empty (#86) - #95
Merged
Merged
Conversation
`GET /api/dm/recipients` returns only people the account may DM — mutual follows, per /help/direct-messages → "Who you can message". For a new account that set is empty and the picker rendered an empty list, which read as a broken screen rather than a rule being enforced. The picker now tells four surfaces apart via `NewMessageUiState.content`: loading (progress), error (message + Retry), loaded-but-empty (the rule, in the app's voice, plus a "Find people to follow" button), and a plain "no matches" note when a search filters every recipient out — so the rule copy is never shown for a query miss. The call to action routes to the existing user search destination (`Routes.USER_SEARCH`) through a new `onFindPeople` hook on `directMessagesGraph`; no new destination added. Empty-state wording is pinned in `RecipientRuleCopy` and asserted by tests so it cannot drift from the rule the server enforces. Tests: NewMessageViewModelTest covers the loading / loaded-empty / error / no-match / retry states; RecipientRuleCopyTest guards the copy; NewMessageScreenTest (Compose) asserts the empty state renders the explanation and the call to action, a non-empty list still renders rows, and an error renders the retryable error rather than the empty-state copy. Closes #86
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #86. Part of epic #84.
What changed
The DM recipient picker collapsed loading, empty and error into one blank list, so a new account's
normal state read as a broken screen. It now distinguishes four surfaces via a derived
NewMessageContentselector (the old ad-hocisEmptyflag is gone, so there is one source oftruth):
LoadingErrorNoRecipientsNoMatchesRecipientsThe search field only appears when there is something to search.
The rule is quoted from the help page, not invented
https://interlinedlist.com/help/direct-messages→ Who you can message: "You can only messagepeople you follow each other: you follow them and they follow you back (both follow
requests approved). You also cannot message someone if either of you has blocked the other… Once
you both follow each other, they'll appear in your recipient list." It also says of the picker:
"If the list is empty, it means no one who follows you also follows you back yet."
The shipped copy states the mutual-follow rule and is phrased so it stays true whichever reason
produced the empty set. The blocking caveat is deliberately left out of the empty state to keep it
short — for a new account the cause is virtually always "no mutuals yet", and the sentence is true
either way. Copy lives in
RecipientRuleCopy.ktwith the help-page citation in its KDoc.Route out of the dead end
directMessagesGraphgained anonFindPeoplehook; the NavHost wires it to the existingRoutes.USER_SEARCHdestination the Account hub already uses. No new destination, no new screen —4 lines in
InterlinedListNavHost.Verification
./gradlew :app:assembleDebug testDebugUnitTest→ BUILD SUCCESSFUL, 723 tests, 0 failures(aggregated from the JUnit XML). New JVM tests include
content is NoRecipients when the server returns an empty set,content is Error on failure, never the empty explanation,a query that matches no one is NoMatches, not the rule explanation, andretry reloads and clears the previous error.:feature:directmessages:compileDebugAndroidTestKotlinsucceeds.Reviewer notes
NoMatchesis a small addition beyond the literal issue text. It prevents a real bug: withoutit, typing a non-matching query against a non-empty recipient list would show the
mutual-follow explanation, which would be false.
repo has no Robolectric anywhere, so it follows the module's existing convention of Compose tests
living in
androidTest(InboxScreenTest,ThreadScreenTest). The state selection drivingthose renderings is fully covered by JVM tests that did run. Making the render assertions run in
CI means adding Robolectric — a new convention for the repo, so not done unilaterally.
init, so following someone andnavigating straight back still shows the empty state until the screen is recreated. Left as-is
because the mutual-follow rule means a newly-followed user would not appear until they follow
back anyway; refresh-on-resume is a reasonable follow-up.