feat(private-replies): hide noisy actions and chain privacy
- ActionBar gates React / Repost / Quote / Zap behind !isPrivate, leaving Reply and Bookmark on private replies. Avoids leaking the rumor id via a public e-tag on kind 7 / 6 / 9735 attached to the rumor. - ComposeViewModel auto-enables and locks the private toggle when the parent being replied to is itself a private reply. Sending publicly would attach an e-tag to the rumor id on public relays and leak the thread structure, so the toggle is forced on and ignores clicks.
This commit is contained in:
@@ -84,6 +84,7 @@ fun ActionBar(
|
||||
resolvedEmojis: Map<String, String> = emptyMap(),
|
||||
unicodeEmojis: List<String> = emptyList(),
|
||||
onOpenEmojiLibrary: (() -> Unit)? = null,
|
||||
isPrivate: Boolean = false,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val context = androidx.compose.ui.platform.LocalContext.current
|
||||
@@ -107,6 +108,9 @@ fun ActionBar(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
maxLines = 1
|
||||
)
|
||||
// Private replies hide React / Repost / Quote / Zap to avoid leaking the rumor id
|
||||
// on public relays. Reply (above) and Bookmark (below) remain available.
|
||||
if (!isPrivate) {
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Box {
|
||||
Box(
|
||||
@@ -243,6 +247,7 @@ fun ActionBar(
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
} // end !isPrivate
|
||||
Spacer(Modifier.width(8.dp))
|
||||
IconButton(onClick = onAddToList) {
|
||||
Icon(
|
||||
|
||||
@@ -806,6 +806,7 @@ fun PostCard(
|
||||
resolvedEmojis = resolvedEmojis,
|
||||
unicodeEmojis = unicodeEmojis,
|
||||
onOpenEmojiLibrary = onOpenEmojiLibrary,
|
||||
isPrivate = isPrivate,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Icon(
|
||||
|
||||
@@ -182,6 +182,11 @@ fun ComposeScreen(
|
||||
val scheduleEnabled by viewModel.scheduleEnabled.collectAsState()
|
||||
val scheduleTimestamp by viewModel.scheduleTimestamp.collectAsState()
|
||||
val privateReply by viewModel.privateReply.collectAsState()
|
||||
val privateReplyLocked by viewModel.privateReplyLocked.collectAsState()
|
||||
|
||||
LaunchedEffect(replyTo) {
|
||||
viewModel.configureForReply(replyTo)
|
||||
}
|
||||
val powStatus = powManager?.status?.collectAsState()?.value ?: PowStatus.Idle
|
||||
val isMiningBusy = powStatus is PowStatus.Mining
|
||||
val context = LocalContext.current
|
||||
|
||||
@@ -123,10 +123,24 @@ class ComposeViewModel(app: Application, private val savedStateHandle: SavedStat
|
||||
private val _privateReply = MutableStateFlow(false)
|
||||
val privateReply: StateFlow<Boolean> = _privateReply
|
||||
|
||||
// Locked = the user is replying to a private reply, so the new reply must also be private
|
||||
// (sending publicly would attach an e-tag to the rumor id on public relays, leaking metadata).
|
||||
private val _privateReplyLocked = MutableStateFlow(false)
|
||||
val privateReplyLocked: StateFlow<Boolean> = _privateReplyLocked
|
||||
|
||||
fun togglePrivateReply() {
|
||||
if (_privateReplyLocked.value) return
|
||||
_privateReply.value = !_privateReply.value
|
||||
}
|
||||
|
||||
/** Called by ComposeScreen when the screen mounts with [replyTo]; auto-enables
|
||||
* + locks the private toggle if [replyTo] is itself a private reply we received. */
|
||||
fun configureForReply(replyTo: NostrEvent?) {
|
||||
val isReplyingToPrivate = replyTo != null && eventRepo?.isPrivateReply(replyTo.id) == true
|
||||
_privateReplyLocked.value = isReplyingToPrivate
|
||||
if (isReplyingToPrivate) _privateReply.value = true
|
||||
}
|
||||
|
||||
private val _powEnabled = MutableStateFlow(false)
|
||||
val powEnabled: StateFlow<Boolean> = _powEnabled
|
||||
|
||||
@@ -1203,6 +1217,7 @@ class ComposeViewModel(app: Application, private val savedStateHandle: SavedStat
|
||||
_hashtags.value = emptyList()
|
||||
_powEnabled.value = false
|
||||
_privateReply.value = false
|
||||
_privateReplyLocked.value = false
|
||||
_galleryMode.value = false
|
||||
_galleryHasVideo.value = false
|
||||
_uploadedMediaMeta.clear()
|
||||
|
||||
Reference in New Issue
Block a user