mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-04-09 20:39:24 +02:00
Displays links in the Status if they are present.
This commit is contained in:
parent
5b596d2a56
commit
b57dd98059
@ -6,9 +6,12 @@ import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.text.ClickableText
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.LocalTextStyle
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.OpenInNew
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
@ -31,14 +34,19 @@ import com.vitorpamplona.amethyst.model.AddressableNote
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.service.Nip05Verifier
|
||||
import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote
|
||||
import com.vitorpamplona.amethyst.ui.note.LoadStatuses
|
||||
import com.vitorpamplona.amethyst.ui.note.NIP05CheckingIcon
|
||||
import com.vitorpamplona.amethyst.ui.note.NIP05FailedVerification
|
||||
import com.vitorpamplona.amethyst.ui.note.NIP05VerifiedIcon
|
||||
import com.vitorpamplona.amethyst.ui.note.routeFor
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.theme.Font14SP
|
||||
import com.vitorpamplona.amethyst.ui.theme.NIP05IconSize
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size15Modifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size16Modifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size18Modifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.lessImportantLink
|
||||
import com.vitorpamplona.amethyst.ui.theme.nip05
|
||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||
import com.vitorpamplona.quartz.events.AddressableEvent
|
||||
@ -105,21 +113,31 @@ fun nip05VerificationAsAState(userMetadata: UserMetadata, pubkeyHex: String): Mu
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ObserveDisplayNip05Status(baseNote: Note, columnModifier: Modifier = Modifier) {
|
||||
fun ObserveDisplayNip05Status(
|
||||
baseNote: Note,
|
||||
columnModifier: Modifier = Modifier,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val author by baseNote.live().authorChanges.observeAsState()
|
||||
|
||||
author?.let {
|
||||
ObserveDisplayNip05Status(it, columnModifier)
|
||||
ObserveDisplayNip05Status(it, columnModifier, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ObserveDisplayNip05Status(baseUser: User, columnModifier: Modifier = Modifier) {
|
||||
fun ObserveDisplayNip05Status(
|
||||
baseUser: User,
|
||||
columnModifier: Modifier = Modifier,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val nip05 by baseUser.live().nip05Changes.observeAsState(baseUser.nip05())
|
||||
|
||||
LoadStatuses(baseUser) { statuses ->
|
||||
Crossfade(targetState = nip05, modifier = columnModifier, label = "ObserveDisplayNip05StatusCrossfade") {
|
||||
VerifyAndDisplayNIP05OrStatusLine(it, statuses, baseUser, columnModifier)
|
||||
VerifyAndDisplayNIP05OrStatusLine(it, statuses, baseUser, columnModifier, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -129,7 +147,9 @@ private fun VerifyAndDisplayNIP05OrStatusLine(
|
||||
nip05: String?,
|
||||
statuses: ImmutableList<AddressableNote>,
|
||||
baseUser: User,
|
||||
columnModifier: Modifier = Modifier
|
||||
columnModifier: Modifier = Modifier,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
Column(modifier = columnModifier) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
@ -139,13 +159,13 @@ private fun VerifyAndDisplayNIP05OrStatusLine(
|
||||
if (nip05Verified.value != true) {
|
||||
DisplayNIP05(nip05, nip05Verified)
|
||||
} else if (!statuses.isEmpty()) {
|
||||
RotateStatuses(statuses)
|
||||
RotateStatuses(statuses, accountViewModel, nav)
|
||||
} else {
|
||||
DisplayNIP05(nip05, nip05Verified)
|
||||
}
|
||||
} else {
|
||||
if (!statuses.isEmpty()) {
|
||||
RotateStatuses(statuses)
|
||||
RotateStatuses(statuses, accountViewModel, nav)
|
||||
} else {
|
||||
DisplayUsersNpub(baseUser.pubkeyDisplayHex())
|
||||
}
|
||||
@ -155,12 +175,16 @@ private fun VerifyAndDisplayNIP05OrStatusLine(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RotateStatuses(statuses: ImmutableList<AddressableNote>) {
|
||||
fun RotateStatuses(
|
||||
statuses: ImmutableList<AddressableNote>,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
var indexToDisplay by remember {
|
||||
mutableIntStateOf(0)
|
||||
}
|
||||
|
||||
DisplayStatus(statuses[indexToDisplay])
|
||||
DisplayStatus(statuses[indexToDisplay], accountViewModel, nav)
|
||||
|
||||
if (statuses.size > 1) {
|
||||
LaunchedEffect(Unit) {
|
||||
@ -184,13 +208,26 @@ fun DisplayUsersNpub(npub: String) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DisplayStatus(addressableNote: AddressableNote) {
|
||||
fun DisplayStatus(
|
||||
addressableNote: AddressableNote,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val noteState by addressableNote.live().metadata.observeAsState()
|
||||
|
||||
val content = remember(noteState) { addressableNote.event?.content() ?: "" }
|
||||
val type = remember(noteState) {
|
||||
(addressableNote.event as? AddressableEvent)?.dTag() ?: ""
|
||||
}
|
||||
val url = remember(noteState) {
|
||||
addressableNote.event?.firstTaggedUrl()?.ifBlank { null }
|
||||
}
|
||||
val nostrATag = remember(noteState) {
|
||||
addressableNote.event?.firstTaggedAddress()
|
||||
}
|
||||
val nostrHexID = remember(noteState) {
|
||||
addressableNote.event?.firstTaggedEvent()?.ifBlank { null }
|
||||
}
|
||||
|
||||
when (type) {
|
||||
"music" -> Icon(
|
||||
@ -209,6 +246,63 @@ fun DisplayStatus(addressableNote: AddressableNote) {
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
|
||||
if (url != null) {
|
||||
val uri = LocalUriHandler.current
|
||||
IconButton(
|
||||
modifier = Size15Modifier,
|
||||
onClick = { runCatching { uri.openUri(url.trim()) } }
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.OpenInNew,
|
||||
null,
|
||||
modifier = Size15Modifier,
|
||||
tint = MaterialTheme.colors.lessImportantLink
|
||||
)
|
||||
}
|
||||
} else if (nostrATag != null) {
|
||||
LoadAddressableNote(nostrATag) { note ->
|
||||
if (note != null) {
|
||||
IconButton(
|
||||
modifier = Size15Modifier,
|
||||
onClick = {
|
||||
routeFor(
|
||||
note,
|
||||
accountViewModel.userProfile()
|
||||
)?.let { nav(it) }
|
||||
}
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.OpenInNew,
|
||||
null,
|
||||
modifier = Size15Modifier,
|
||||
tint = MaterialTheme.colors.lessImportantLink
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (nostrHexID != null) {
|
||||
LoadNote(baseNoteHex = nostrHexID) {
|
||||
if (it != null) {
|
||||
IconButton(
|
||||
modifier = Size15Modifier,
|
||||
onClick = {
|
||||
routeFor(
|
||||
it,
|
||||
accountViewModel.userProfile()
|
||||
)?.let { nav(it) }
|
||||
}
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.OpenInNew,
|
||||
null,
|
||||
modifier = Size15Modifier,
|
||||
tint = MaterialTheme.colors.lessImportantLink
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
@ -2487,7 +2487,7 @@ fun SecondUserInfoRow(
|
||||
val noteAuthor = remember { note.author } ?: return
|
||||
|
||||
Row(verticalAlignment = CenterVertically, modifier = UserNameMaxRowHeight) {
|
||||
ObserveDisplayNip05Status(noteAuthor, remember { Modifier.weight(1f) })
|
||||
ObserveDisplayNip05Status(noteAuthor, remember { Modifier.weight(1f) }, accountViewModel, nav)
|
||||
|
||||
val geo = remember { noteEvent.getGeoHash() }
|
||||
if (geo != null) {
|
||||
|
@ -328,7 +328,7 @@ fun NoteMaster(
|
||||
}
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
ObserveDisplayNip05Status(baseNote, remember { Modifier.weight(1f) })
|
||||
ObserveDisplayNip05Status(baseNote, remember { Modifier.weight(1f) }, accountViewModel, nav)
|
||||
|
||||
val geo = remember { noteEvent.getGeoHash() }
|
||||
if (geo != null) {
|
||||
|
@ -504,7 +504,7 @@ fun ChatroomHeader(
|
||||
|
||||
Column(modifier = Modifier.padding(start = 10.dp)) {
|
||||
UsernameDisplay(baseUser)
|
||||
ObserveDisplayNip05Status(baseUser)
|
||||
ObserveDisplayNip05Status(baseUser, accountViewModel = accountViewModel, nav = nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -374,7 +374,9 @@ private fun RenderAuthorInformation(
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
ObserveDisplayNip05Status(
|
||||
remember { note.author!! },
|
||||
remember { Modifier.weight(1f) }
|
||||
remember { Modifier.weight(1f) },
|
||||
accountViewModel,
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
Row(
|
||||
|
@ -69,6 +69,16 @@ open class Event(
|
||||
|
||||
override fun taggedUrls() = tags.filter { it.size > 1 && it[0] == "r" }.map { it[1] }
|
||||
|
||||
override fun firstTaggedUser() = tags.firstOrNull { it.size > 1 && it[0] == "p" }?.let { it[1] }
|
||||
override fun firstTaggedEvent() = tags.firstOrNull { it.size > 1 && it[0] == "e" }?.let { it[1] }
|
||||
override fun firstTaggedUrl() = tags.firstOrNull { it.size > 1 && it[0] == "r" }?.let { it[1] }
|
||||
override fun firstTaggedAddress() = tags.firstOrNull { it.size > 1 && it[0] == "r" }?.let {
|
||||
val aTagValue = it[1]
|
||||
val relay = it.getOrNull(2)
|
||||
|
||||
ATag.parse(aTagValue, relay)
|
||||
}
|
||||
|
||||
override fun taggedEmojis() = tags.filter { it.size > 2 && it[0] == "emoji" }.map { EmojiUrl(it[1], it[2]) }
|
||||
|
||||
override fun isSensitive() = tags.any {
|
||||
|
@ -68,6 +68,11 @@ interface EventInterface {
|
||||
fun taggedEvents(): List<HexKey>
|
||||
fun taggedUrls(): List<String>
|
||||
|
||||
fun firstTaggedAddress(): ATag?
|
||||
fun firstTaggedUser(): HexKey?
|
||||
fun firstTaggedEvent(): HexKey?
|
||||
fun firstTaggedUrl(): String?
|
||||
|
||||
fun taggedEmojis(): List<EmojiUrl>
|
||||
fun matchTag1With(text: String): Boolean
|
||||
fun isExpired(): Boolean
|
||||
|
@ -44,10 +44,11 @@ class StatusEvent(
|
||||
privateKey: ByteArray,
|
||||
createdAt: Long = TimeUtils.now()
|
||||
): StatusEvent {
|
||||
val tags = event.tags.plus(listOf(listOf("r", "http://amethyst.social")))
|
||||
val pubKey = event.pubKey()
|
||||
val id = generateId(pubKey, createdAt, kind, event.tags, newStatus)
|
||||
val id = generateId(pubKey, createdAt, kind, tags, newStatus)
|
||||
val sig = CryptoUtils.sign(id, privateKey)
|
||||
return StatusEvent(id.toHexKey(), pubKey, createdAt, event.tags, newStatus, sig.toHexKey())
|
||||
return StatusEvent(id.toHexKey(), pubKey, createdAt, tags, newStatus, sig.toHexKey())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user