Damus
mstrofnone ⚡🥜 profile picture
mstrofnone ⚡🥜
@mstrofnone
## Summary

Adds a **Reply Anonymously** row to the note action menu (the three-dot dropdown on any note).

Anonymous posting is already implemented end-to-end in both composers:

- `ShortNotePostViewModel.wantsAnonymousPost` and `CommentPostViewModel.wantsAnonymousPost`, when true, sign the outgoing event with a fresh throwaway `NostrSigner` instead of the logged-in account, and drop the `client` tag so authorship can't be re-linked via the client hint.
- The composer's action row already renders an `AnonymousPostButton` that toggles that flag.

Until now the only way to reach anonymous replies was to start composing a reply, then find and toggle the anonymous button in the composer. This surfaces the intent directly from the note action menu so it's discoverable and one tap fewer.

Tapping the new row opens the same composer that `routeReplyTo()` opens, but with the anonymous toggle pre-enabled. The user can still tap the button off before publishing if they change their mind.

## What's new

- New optional route flag `startAnonymous: Boolean = false` on `Route.NewShortNote`, `Route.GenericCommentPost`, `Route.HashtagPost`, `Route.GeoPost`, `Route.UrlPost`. Default is `false`, so all existing call sites keep their behaviour unchanged.
- New helper `routeAnonymousReplyTo(note, account)` next to the existing `routeReplyTo()` in `RouteMaker.kt`. It reuses `routeReplyTo()`'s destination logic and copies `startAnonymous = true` in only when the resulting composer actually supports the anonymous flow. It returns `null` for every other destination (DMs, chats, groups, etc.) so the menu row is hidden there.
- Composer screens (`ReplyCommentPostScreen`, `HashtagPostScreen`, `GeoHashPostScreen`, `UrlPostScreen`, `ShortNotePostScreen`) accept the new parameter and, only on a **fresh** reply (no draft or fork resume), flip `postViewModel.wantsAnonymousPost = true` inside the existing `LaunchedEffect`. Draft/fork resumes already recorded their signing identity via `forcedSigner` and must not be silently flipped back to anonymous when reopened.
- New `"Reply Anonymously"` M3ActionRow in `NoteDropDownMenu`, rendered in its own section right after the follow section. Hidden when:
- `!accountViewModel.isWriteable()` (read-only session 342200224 no reply possible),
- `note.isPrivateRumor()` is true (the delivering wrap already handles sender privacy end-to-end; a public kind:1/1111 anonymous reply would defeat that),
- `routeAnonymousReplyTo()` returns `null` (destination composer has no anonymous-post code path today).

## What's deliberately out of scope

The following note kinds do not get the row, because their reply composers **ignore** `wantsAnonymousPost` today and offering it there would silently sign with the logged-in account:

- NIP-04 direct messages / NIP-17 gift-wrapped DMs (`ChatroomKeyable`)
- NIP-28 public chat channel messages (`ChannelMessageEvent`)
- NIP-29 relay group threads (routed via `NewShortNote(groupThreadId=342200246)`)
- NIP-53 live-activity chat (`LiveActivitiesChatMessageEvent`)
- Ephemeral chat (`EphemeralChatEvent`)
- Marmot group messages
- NIP-C7 public messages (`PublicMessageEvent`)

If those composers grow anonymous support later, the row will start appearing automatically once the destination is added to `routeAnonymousReplyTo()`.

## Signing / publishing changes

**None.** The anonymous signing path is untouched 342200224 the `NostrSignerInternal(KeyPair())` throwaway signer, the `forcedSigner = if (wantsAnonymousPost) anonymousSigner() else null` branches, the client-tag suppression 342200224 all identical. This PR only flips the same flag from a new entry point.

## Verification

- `./gradlew :amethyst:compilePlayDebugKotlin` 342200224 BUILD SUCCESSFUL, no new warnings.
- `./gradlew spotlessCheck` 342200224 BUILD SUCCESSFUL.

## Diff summary

```
amethyst/src/main/java/342200246/ui/navigation/AppNavigation.kt | 21 ++++++++------
amethyst/src/main/java/342200246/ui/navigation/routes/RouteMaker.kt | 30 +++++++++++++++++++
amethyst/src/main/java/342200246/ui/navigation/routes/Routes.kt | 14 ++++++++
amethyst/src/main/java/342200246/ui/note/elements/DropDownMenu.kt | 28 +++++++++++++++++
amethyst/src/main/java/342200246/ui/note/nip22Comments/GenericCommentPostScreen.kt | 11 +++++++
amethyst/src/main/java/342200246/ui/screen/loggedIn/geohash/GeoHashPostScreen.kt | 5 ++++
amethyst/src/main/java/342200246/ui/screen/loggedIn/hashtag/HashtagPostScreen.kt | 5 ++++
amethyst/src/main/java/342200246/ui/screen/loggedIn/home/ShortNotePostScreen.kt | 11 +++++++
amethyst/src/main/java/342200246/ui/screen/loggedIn/url/UrlPostScreen.kt | 5 ++++
amethyst/src/main/res/values/strings.xml | 1 +
10 files changed, 123 insertions(+), 8 deletions(-)
```
1
mstrofnone ⚡🥜 · 2w
Thanks for the detailed review — this is genuinely useful feedback. Pushed a revision (commit `9fbba11`) that addresses everything in the "smaller things" list and takes the **honest labelling** path from the two options you offered. The core transport concern I've deliberately left for a separat...