Finishing the rendering of card notes for DMs and live chats
This commit is contained in:
@@ -25,12 +25,14 @@ import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.quartz.encoders.HexKey
|
||||
import com.vitorpamplona.quartz.events.AddressableEvent
|
||||
import com.vitorpamplona.quartz.events.ChannelCreateEvent
|
||||
import com.vitorpamplona.quartz.events.ChannelMessageEvent
|
||||
import com.vitorpamplona.quartz.events.ChannelMetadataEvent
|
||||
import com.vitorpamplona.quartz.events.ChatroomKey
|
||||
import com.vitorpamplona.quartz.events.ChatroomKeyable
|
||||
import com.vitorpamplona.quartz.events.CommunityDefinitionEvent
|
||||
import com.vitorpamplona.quartz.events.DraftEvent
|
||||
import com.vitorpamplona.quartz.events.EventInterface
|
||||
import com.vitorpamplona.quartz.events.IsInPublicChatChannel
|
||||
import com.vitorpamplona.quartz.events.LiveActivitiesChatMessageEvent
|
||||
import com.vitorpamplona.quartz.events.LiveActivitiesEvent
|
||||
import kotlinx.collections.immutable.persistentSetOf
|
||||
@@ -40,18 +42,51 @@ fun routeFor(
|
||||
note: Note,
|
||||
loggedIn: User,
|
||||
): String? {
|
||||
val noteEvent = note.event
|
||||
val noteEvent = note.event ?: return "Note/${URLEncoder.encode(note.idHex, "utf-8")}"
|
||||
|
||||
if (
|
||||
noteEvent is ChannelMessageEvent ||
|
||||
noteEvent is ChannelCreateEvent ||
|
||||
noteEvent is ChannelMetadataEvent
|
||||
) {
|
||||
note.channelHex()?.let {
|
||||
return routeFor(noteEvent, loggedIn)
|
||||
}
|
||||
|
||||
fun routeFor(
|
||||
noteEvent: EventInterface,
|
||||
loggedIn: User,
|
||||
): String? {
|
||||
if (noteEvent is DraftEvent) {
|
||||
val innerEvent = noteEvent.preCachedDraft(loggedIn.pubkeyHex)
|
||||
|
||||
if (innerEvent is IsInPublicChatChannel) {
|
||||
innerEvent.channel()?.let {
|
||||
return "Channel/$it"
|
||||
}
|
||||
} else if (innerEvent is LiveActivitiesEvent) {
|
||||
innerEvent.address().toTag().let {
|
||||
return "Channel/${URLEncoder.encode(it, "utf-8")}"
|
||||
}
|
||||
} else if (innerEvent is LiveActivitiesChatMessageEvent) {
|
||||
innerEvent.activity()?.toTag()?.let {
|
||||
return "Channel/${URLEncoder.encode(it, "utf-8")}"
|
||||
}
|
||||
} else if (innerEvent is ChatroomKeyable) {
|
||||
val room = innerEvent.chatroomKey(loggedIn.pubkeyHex)
|
||||
loggedIn.createChatroom(room)
|
||||
return "Room/${room.hashCode()}"
|
||||
} else if (innerEvent is AddressableEvent) {
|
||||
return "Note/${URLEncoder.encode(noteEvent.address().toTag(), "utf-8")}"
|
||||
} else {
|
||||
return "Note/${URLEncoder.encode(noteEvent.id(), "utf-8")}"
|
||||
}
|
||||
} else if (noteEvent is IsInPublicChatChannel) {
|
||||
noteEvent.channel()?.let {
|
||||
return "Channel/$it"
|
||||
}
|
||||
} else if (noteEvent is LiveActivitiesEvent || noteEvent is LiveActivitiesChatMessageEvent) {
|
||||
note.channelHex()?.let {
|
||||
} else if (noteEvent is ChannelCreateEvent) {
|
||||
return "Channel/${noteEvent.id}"
|
||||
} else if (noteEvent is LiveActivitiesEvent) {
|
||||
noteEvent.address().toTag().let {
|
||||
return "Channel/${URLEncoder.encode(it, "utf-8")}"
|
||||
}
|
||||
} else if (noteEvent is LiveActivitiesChatMessageEvent) {
|
||||
noteEvent.activity()?.toTag()?.let {
|
||||
return "Channel/${URLEncoder.encode(it, "utf-8")}"
|
||||
}
|
||||
} else if (noteEvent is ChatroomKeyable) {
|
||||
@@ -59,9 +94,11 @@ fun routeFor(
|
||||
loggedIn.createChatroom(room)
|
||||
return "Room/${room.hashCode()}"
|
||||
} else if (noteEvent is CommunityDefinitionEvent) {
|
||||
return "Community/${URLEncoder.encode(note.idHex, "utf-8")}"
|
||||
return "Community/${URLEncoder.encode(noteEvent.address().toTag(), "utf-8")}"
|
||||
} else if (noteEvent is AddressableEvent) {
|
||||
return "Note/${URLEncoder.encode(noteEvent.address().toTag(), "utf-8")}"
|
||||
} else {
|
||||
return "Note/${URLEncoder.encode(note.idHex, "utf-8")}"
|
||||
return "Note/${URLEncoder.encode(noteEvent.id(), "utf-8")}"
|
||||
}
|
||||
|
||||
return null
|
||||
|
||||
@@ -85,6 +85,7 @@ import com.vitorpamplona.amethyst.ui.note.types.RenderAppDefinition
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderAudioHeader
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderAudioTrack
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderBadgeAward
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderChatMessage
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderClassifieds
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderEmojiPack
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderFhirResource
|
||||
@@ -92,6 +93,7 @@ import com.vitorpamplona.amethyst.ui.note.types.RenderGitIssueEvent
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderGitPatchEvent
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderGitRepositoryEvent
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderHighlight
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderLiveActivityChatMessage
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderLiveActivityEvent
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderLongFormContent
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderPinListEvent
|
||||
@@ -139,6 +141,7 @@ import com.vitorpamplona.quartz.events.BaseTextNoteEvent
|
||||
import com.vitorpamplona.quartz.events.ChannelCreateEvent
|
||||
import com.vitorpamplona.quartz.events.ChannelMessageEvent
|
||||
import com.vitorpamplona.quartz.events.ChannelMetadataEvent
|
||||
import com.vitorpamplona.quartz.events.ChatMessageEvent
|
||||
import com.vitorpamplona.quartz.events.ClassifiedsEvent
|
||||
import com.vitorpamplona.quartz.events.CommunityDefinitionEvent
|
||||
import com.vitorpamplona.quartz.events.CommunityPostApprovalEvent
|
||||
@@ -618,6 +621,18 @@ private fun RenderNoteRow(
|
||||
nav,
|
||||
)
|
||||
}
|
||||
is ChatMessageEvent -> {
|
||||
RenderChatMessage(
|
||||
baseNote,
|
||||
makeItShort,
|
||||
canPreview,
|
||||
quotesLeft,
|
||||
backgroundColor,
|
||||
editState,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
}
|
||||
is ClassifiedsEvent -> {
|
||||
RenderClassifieds(
|
||||
noteEvent,
|
||||
@@ -672,6 +687,17 @@ private fun RenderNoteRow(
|
||||
nav,
|
||||
)
|
||||
}
|
||||
is LiveActivitiesChatMessageEvent ->
|
||||
RenderLiveActivityChatMessage(
|
||||
baseNote,
|
||||
makeItShort,
|
||||
canPreview,
|
||||
quotesLeft,
|
||||
backgroundColor,
|
||||
editState,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
else -> {
|
||||
RenderTextEvent(
|
||||
baseNote,
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.note.types
|
||||
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.ui.components.GenericLoadable
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChatroomHeader
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.replyModifier
|
||||
import com.vitorpamplona.quartz.events.ChatroomKeyable
|
||||
|
||||
@Composable
|
||||
fun RenderChatMessage(
|
||||
note: Note,
|
||||
makeItShort: Boolean,
|
||||
canPreview: Boolean,
|
||||
quotesLeft: Int,
|
||||
backgroundColor: MutableState<Color>,
|
||||
editState: State<GenericLoadable<EditState>>,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
val userRoom by
|
||||
remember(note) {
|
||||
derivedStateOf {
|
||||
(note.event as? ChatroomKeyable)?.chatroomKey(accountViewModel.userProfile().pubkeyHex)
|
||||
}
|
||||
}
|
||||
|
||||
userRoom?.let {
|
||||
if (it.users.size > 1 || (it.users.size == 1 && note.author == accountViewModel.account.userProfile())) {
|
||||
ChatroomHeader(it, MaterialTheme.colorScheme.replyModifier.padding(10.dp), accountViewModel, nav)
|
||||
Spacer(modifier = StdVertSpacer)
|
||||
}
|
||||
}
|
||||
|
||||
RenderTextEvent(
|
||||
note,
|
||||
makeItShort,
|
||||
canPreview,
|
||||
quotesLeft,
|
||||
backgroundColor,
|
||||
editState,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.note.types
|
||||
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.ui.components.GenericLoadable
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChannelHeader
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.replyModifier
|
||||
import com.vitorpamplona.quartz.events.LiveActivitiesChatMessageEvent
|
||||
|
||||
@Composable
|
||||
fun RenderLiveActivityChatMessage(
|
||||
note: Note,
|
||||
makeItShort: Boolean,
|
||||
canPreview: Boolean,
|
||||
quotesLeft: Int,
|
||||
backgroundColor: MutableState<Color>,
|
||||
editState: State<GenericLoadable<EditState>>,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
val noteEvent = note.event
|
||||
val showChannelInfo =
|
||||
remember(noteEvent) {
|
||||
if (noteEvent is LiveActivitiesChatMessageEvent) {
|
||||
noteEvent.activity()?.toTag()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
showChannelInfo?.let {
|
||||
ChannelHeader(
|
||||
channelHex = it,
|
||||
showVideo = false,
|
||||
sendToChannel = true,
|
||||
modifier = MaterialTheme.colorScheme.replyModifier.padding(10.dp),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
Spacer(modifier = StdVertSpacer)
|
||||
}
|
||||
|
||||
RenderTextEvent(
|
||||
note,
|
||||
makeItShort,
|
||||
canPreview,
|
||||
quotesLeft,
|
||||
backgroundColor,
|
||||
editState,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
}
|
||||
@@ -20,16 +20,21 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.note.types
|
||||
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.ui.components.SensitivityWarning
|
||||
@@ -37,8 +42,12 @@ import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer
|
||||
import com.vitorpamplona.amethyst.ui.note.LoadDecryptedContent
|
||||
import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChatroomHeader
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.ui.theme.replyModifier
|
||||
import com.vitorpamplona.quartz.encoders.toNpub
|
||||
import com.vitorpamplona.quartz.events.ChatroomKeyable
|
||||
import com.vitorpamplona.quartz.events.EmptyTagList
|
||||
import com.vitorpamplona.quartz.events.PrivateDmEvent
|
||||
import com.vitorpamplona.quartz.events.toImmutableListOfLists
|
||||
@@ -57,6 +66,20 @@ fun RenderPrivateMessage(
|
||||
) {
|
||||
val noteEvent = note.event as? PrivateDmEvent ?: return
|
||||
|
||||
val userRoom by
|
||||
remember(note) {
|
||||
derivedStateOf {
|
||||
(note.event as? ChatroomKeyable)?.chatroomKey(accountViewModel.userProfile().pubkeyHex)
|
||||
}
|
||||
}
|
||||
|
||||
userRoom?.let {
|
||||
if (it.users.size > 1 || (it.users.size == 1 && note.author == accountViewModel.account.userProfile())) {
|
||||
ChatroomHeader(it, MaterialTheme.colorScheme.replyModifier.padding(10.dp), accountViewModel, nav)
|
||||
Spacer(modifier = StdVertSpacer)
|
||||
}
|
||||
}
|
||||
|
||||
val withMe = remember { noteEvent.with(accountViewModel.userProfile().pubkeyHex) }
|
||||
if (withMe) {
|
||||
LoadDecryptedContent(note, accountViewModel) { eventContent ->
|
||||
|
||||
@@ -39,7 +39,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.amethyst.ui.theme.FeedPadding
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdTopPadding
|
||||
import kotlin.time.ExperimentalTime
|
||||
|
||||
@Composable
|
||||
fun ChatroomListFeedView(
|
||||
@@ -81,7 +80,6 @@ private fun CrossFadeState(
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTime::class)
|
||||
@Composable
|
||||
private fun FeedLoaded(
|
||||
state: FeedState.Loaded,
|
||||
|
||||
@@ -645,10 +645,6 @@ fun ChatroomHeader(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalDivider(
|
||||
thickness = DividerThickness,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -685,10 +681,6 @@ fun GroupChatroomHeader(
|
||||
LongRoomHeader(room = room, accountViewModel = accountViewModel, nav = nav)
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalDivider(
|
||||
thickness = DividerThickness,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,10 @@ class DraftEvent(
|
||||
return cachedInnerEvent[signer.pubKey]
|
||||
}
|
||||
|
||||
fun preCachedDraft(pubKey: HexKey): Event? {
|
||||
return cachedInnerEvent[pubKey]
|
||||
}
|
||||
|
||||
fun allCache() = cachedInnerEvent.values
|
||||
|
||||
fun addToCache(
|
||||
|
||||
Reference in New Issue
Block a user