Skip to content

feat(compose): derive reply and repost visibility from the account preference - #37

Merged
Adron merged 1 commit into
devfrom
feat/reply-repost-default-visibility
Sep 7, 2026
Merged

Adron merged 1 commit into
devfrom
feat/reply-repost-default-visibility

Conversation

@Adron

@Adron Adron commented Sep 7, 2026

Copy link
Copy Markdown
Member

Summary

Follow-through on #34, which shipped the composer half. That PR made a new message honour the account's "New posts are public by default" preference — but a repost and an inline reply both still hardcoded .public. So on dev today, an account set to private-by-default gets private new messages and public replies and reposts.

Both are message-creating surfaces, so both now seed from the same AppEnvironment.defaultComposeVisibility that #34 introduced.

Changes

  • RepostSheetViewModel takes initialVisibility, mirroring the composer. The sheet's existing picker still lets the user override it.
  • MessageDetailViewModel takes defaultVisibility, and postReply's visibility argument becomes Visibility?, falling back to it when nil. This is the one that matters most: the inline reply composer has no visibility control at all, so the preference is the only thing standing between a private-by-default account and a public reply. An explicit argument still wins, so callers and tests can pin a specific value.

The remaining .public literals are parameter fallbacks for the signed-out / unresolved-session case — the same fallback AppEnvironment applies when currentUser is nil, matching UserSettings.default.

Lists are deliberately untouched: NewListViewModel defaults to .private per the M3 brief, and this preference is scoped to posts.

Tests

Two BDD quartets, 8 new tests:

  • Repost seeding — private default seeds the picker, signed-out falls back to public, the seed reaches the wire, and an explicit pick beats the seed.
  • Reply visibility — the no-argument postReply(body:) call the view actually makes posts privately, signed-out falls back to public, an explicit argument overrides, and the empty-body guard still short-circuits before the preference is consulted.

Mutation-checked: restoring either hardcode fails exactly three assertions, confirming the tests are not vacuous.

Verification

Branch is cut from current dev (39fdea1). The cherry-pick conflicted with the message-actions rename in MessageDetailView/ViewModel; both conflicts were parameter-list unions, resolved by keeping both eventBus and defaultVisibility.

  • xcodebuild ... build → ** BUILD SUCCEEDED **
  • xcodebuild ... CODE_SIGNING_ALLOWED=NO test → Executed 752 tests, with 0 failures — ** TEST SUCCEEDED **
  • swift test --package-path Packages/InterlinedKit → Executed 398 tests, with 0 failures
  • swift test --package-path Packages/InterlinedDomain → Executed 772 tests, with 0 failures
  • swift test --package-path Packages/InterlinedPersistence → Executed 135 tests, with 0 failures
  • grep -rn "^import InterlinedKit" App/Features App/Navigation App/MenuCommands → 0

Note

The manual ⌘W → ⌘N window-state check flagged on #34 still stands, but it does not affect this PR: the repost sheet and message detail view models are built per-presentation, not once per app launch. Only the composer's single-instance Window is exposed to that.

🤖 Generated with Claude Code

https://claude.ai/code/session_015mnd3dkGEBgakL35cGujBR

…eference

Follow-through on the composer change: a repost and an inline reply both
create messages, but both still hardcoded `.public`, so an account set to
private-by-default had its new messages honour the preference while its
replies and reposts silently went public.

Both now seed from the same `AppEnvironment.defaultComposeVisibility`:

- `RepostSheetViewModel` takes `initialVisibility`, mirroring the composer.
  The sheet's existing picker still lets the user override it.
- `MessageDetailViewModel` takes `defaultVisibility` and `postReply`'s
  `visibility` argument becomes `Visibility?`, falling back to it when nil.
  This matters most here: the inline reply composer has no visibility
  control at all, so the preference is the only thing standing between a
  private-by-default account and a public reply. An explicit argument still
  wins, so callers and tests can pin a specific value.

The remaining `.public` literals are parameter fallbacks for the signed-out
or unresolved-session case, matching `UserSettings.default` — the same
fallback `AppEnvironment` applies when `currentUser` is nil.

Two more BDD quartets covering seeding, the signed-out fallback, an explicit
override, and the empty-body guard. Mutation-checked: restoring either
hardcode fails exactly three assertions.

Lists are deliberately untouched — `NewListViewModel` defaults to `.private`
per the M3 brief, and the preference is scoped to posts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015mnd3dkGEBgakL35cGujBR
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