feat(audio-rooms): zap participant via ZapCustomDialog (T2 #3)
Add a "Send zap" row to the participant context sheet. Reuses the standard ZapCustomDialog targeting the user's kind-0 metadata addressable note (the canonical "zap a user" base note used throughout amethyst, e.g. profile screen). Single-payable invoices hand off to a wallet via payViaIntent — the same path ReactionsRow uses for in-feed zaps. Split-payee zaps (uncommon for a personal LN address but theoretically possible if the metadata has a zap-split tag) toast a "use the profile screen" message rather than wire a Compose nav host into ModalBottomSheet — the audio-room activity has no nav host of its own and routing back to MainActivity for the rare case isn't worth the plumbing.
This commit is contained in:
+61
@@ -33,16 +33,24 @@ import androidx.compose.material3.ModalBottomSheet
|
|||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.rememberModalBottomSheetState
|
import androidx.compose.material3.rememberModalBottomSheetState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.ui.MainActivity
|
import com.vitorpamplona.amethyst.ui.MainActivity
|
||||||
|
import com.vitorpamplona.amethyst.ui.components.toasts.multiline.UserBasedErrorMessage
|
||||||
|
import com.vitorpamplona.amethyst.ui.note.ZapCustomDialog
|
||||||
|
import com.vitorpamplona.amethyst.ui.note.payViaIntent
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.stringRes
|
import com.vitorpamplona.amethyst.ui.stringRes
|
||||||
import com.vitorpamplona.quartz.experimental.audiorooms.admin.AdminCommandEvent
|
import com.vitorpamplona.quartz.experimental.audiorooms.admin.AdminCommandEvent
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
||||||
import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag
|
import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag
|
||||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NPub
|
import com.vitorpamplona.quartz.nip19Bech32.entities.NPub
|
||||||
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent
|
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent
|
||||||
@@ -143,6 +151,59 @@ internal fun ParticipantHostActionsSheet(
|
|||||||
}
|
}
|
||||||
onDismiss()
|
onDismiss()
|
||||||
}
|
}
|
||||||
|
// Zap — opens the standard ZapCustomDialog targeting the
|
||||||
|
// user's kind-0 metadata note (the canonical "zap a user"
|
||||||
|
// base note throughout amethyst). Single-payable invoices
|
||||||
|
// hand off to a wallet via payViaIntent; split-zap targets
|
||||||
|
// (uncommon for personal LN addresses) are routed back to
|
||||||
|
// the profile screen rather than wired into a non-nav-host
|
||||||
|
// ModalBottomSheet.
|
||||||
|
var showZapDialog by rememberSaveable { mutableStateOf(false) }
|
||||||
|
ActionRow(stringRes(R.string.audio_room_participant_zap)) {
|
||||||
|
showZapDialog = true
|
||||||
|
}
|
||||||
|
if (showZapDialog) {
|
||||||
|
val targetMetadataNote =
|
||||||
|
remember(target) {
|
||||||
|
com.vitorpamplona.amethyst.model.LocalCache
|
||||||
|
.getOrCreateAddressableNote(MetadataEvent.createAddress(target))
|
||||||
|
}
|
||||||
|
// Pre-resolved at composition because callbacks below run
|
||||||
|
// outside a @Composable scope (stringRes is composable-only).
|
||||||
|
val splitUnsupportedMsg = stringRes(R.string.audio_room_participant_zap_split_unsupported)
|
||||||
|
ZapCustomDialog(
|
||||||
|
onZapStarts = {},
|
||||||
|
onClose = {
|
||||||
|
showZapDialog = false
|
||||||
|
onDismiss()
|
||||||
|
},
|
||||||
|
onError = { _, message, user ->
|
||||||
|
accountViewModel.toastManager.toast(
|
||||||
|
R.string.error_dialog_zap_error,
|
||||||
|
UserBasedErrorMessage(message, user),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onProgress = { /* no progress UI inside the sheet — single-payable handoff is fast */ },
|
||||||
|
onPayViaIntent = { payables ->
|
||||||
|
if (payables.size == 1) {
|
||||||
|
val payable = payables.first()
|
||||||
|
payViaIntent(payable.invoice, context, { }) { error ->
|
||||||
|
accountViewModel.toastManager.toast(
|
||||||
|
R.string.error_dialog_zap_error,
|
||||||
|
UserBasedErrorMessage(error, payable.info.user),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
accountViewModel.toastManager.toast(
|
||||||
|
R.string.error_dialog_zap_error,
|
||||||
|
UserBasedErrorMessage(splitUnsupportedMsg, null),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
accountViewModel = accountViewModel,
|
||||||
|
baseNote = targetMetadataNote,
|
||||||
|
)
|
||||||
|
}
|
||||||
ActionRow(
|
ActionRow(
|
||||||
text =
|
text =
|
||||||
stringRes(
|
stringRes(
|
||||||
|
|||||||
@@ -540,6 +540,8 @@
|
|||||||
<string name="audio_room_demote_listener">Demote to listener</string>
|
<string name="audio_room_demote_listener">Demote to listener</string>
|
||||||
<string name="audio_room_kick_action">Kick</string>
|
<string name="audio_room_kick_action">Kick</string>
|
||||||
<string name="audio_room_participant_view_profile">View profile</string>
|
<string name="audio_room_participant_view_profile">View profile</string>
|
||||||
|
<string name="audio_room_participant_zap">Send zap</string>
|
||||||
|
<string name="audio_room_participant_zap_split_unsupported">Split zaps are not supported from inside an audio room. Open the profile screen to send.</string>
|
||||||
<string name="audio_room_participant_follow">Follow</string>
|
<string name="audio_room_participant_follow">Follow</string>
|
||||||
<string name="audio_room_participant_unfollow">Unfollow</string>
|
<string name="audio_room_participant_unfollow">Unfollow</string>
|
||||||
<string name="audio_room_participant_mute">Mute</string>
|
<string name="audio_room_participant_mute">Mute</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user