diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt b/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt index f638f542d..03f8d0b14 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt @@ -8,6 +8,7 @@ import com.vitorpamplona.amethyst.service.NostrChatroomListDataSource import com.vitorpamplona.amethyst.service.NostrGlobalDataSource import com.vitorpamplona.amethyst.service.NostrHomeDataSource import com.vitorpamplona.amethyst.service.NostrNotificationDataSource +import com.vitorpamplona.amethyst.service.NostrSingleChannelDataSource import com.vitorpamplona.amethyst.service.NostrSingleEventDataSource import com.vitorpamplona.amethyst.service.NostrSingleUserDataSource import com.vitorpamplona.amethyst.service.NostrThreadDataSource @@ -48,6 +49,7 @@ object ServiceManager { NostrHomeDataSource.start() NostrNotificationDataSource.start() NostrSingleEventDataSource.start() + NostrSingleChannelDataSource.start() NostrSingleUserDataSource.start() NostrThreadDataSource.start() NostrChatroomListDataSource.start() @@ -68,6 +70,7 @@ object ServiceManager { NostrGlobalDataSource.stop() NostrNotificationDataSource.stop() + NostrSingleChannelDataSource.stop() NostrSingleEventDataSource.stop() NostrSingleUserDataSource.stop() NostrThreadDataSource.stop() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt index b93e5c772..48b6b47f0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt @@ -1,6 +1,7 @@ package com.vitorpamplona.amethyst.model import androidx.lifecycle.LiveData +import com.vitorpamplona.amethyst.service.NostrSingleEventDataSource import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent import com.vitorpamplona.amethyst.ui.note.toShortenHex import java.util.concurrent.ConcurrentHashMap @@ -52,6 +53,16 @@ class ChannelLiveData(val channel: Channel): LiveData(ChannelState fun refresh() { postValue(ChannelState(channel)) } + + override fun onActive() { + super.onActive() + NostrSingleEventDataSource.add(channel.idHex) + } + + override fun onInactive() { + super.onInactive() + NostrSingleEventDataSource.remove(channel.idHex) + } } class ChannelState(val channel: Channel) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleChannelDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleChannelDataSource.kt new file mode 100644 index 000000000..3ef9c07d2 --- /dev/null +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleChannelDataSource.kt @@ -0,0 +1,73 @@ +package com.vitorpamplona.amethyst.service + +import com.vitorpamplona.amethyst.model.LocalCache +import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent +import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent +import com.vitorpamplona.amethyst.service.model.ChannelMetadataEvent +import com.vitorpamplona.amethyst.service.model.ReactionEvent +import com.vitorpamplona.amethyst.service.model.RepostEvent +import java.util.Collections +import nostr.postr.JsonFilter +import nostr.postr.events.TextNoteEvent + +object NostrSingleChannelDataSource: NostrDataSource("SingleChannelFeed") { + private var channelsToWatch = setOf() + + private fun createRepliesAndReactionsFilter(): JsonFilter? { + val reactionsToWatch = channelsToWatch.map { it } + + if (reactionsToWatch.isEmpty()) { + return null + } + + // downloads all the reactions to a given event. + return JsonFilter( + kinds = listOf(ChannelMetadataEvent.kind), + tags = mapOf("e" to reactionsToWatch) + ) + } + + fun createLoadEventsIfNotLoadedFilter(): JsonFilter? { + val directEventsToLoad = channelsToWatch + .map { LocalCache.getOrCreateChannel(it) } + .filter { it.notes.isEmpty() } + + val interestedEvents = (directEventsToLoad).map { it.idHex }.toSet() + + if (interestedEvents.isEmpty()) { + return null + } + + // downloads linked events to this event. + return JsonFilter( + kinds = listOf(ChannelCreateEvent.kind), + ids = interestedEvents.toList() + ) + } + + val repliesAndReactionsChannel = requestNewChannel() + val loadEventsChannel = requestNewChannel() + + override fun feed(): List { + return emptyList() + } + + override fun updateChannelFilters() { + val reactions = createRepliesAndReactionsFilter() + val missing = createLoadEventsIfNotLoadedFilter() + + repliesAndReactionsChannel.filter = listOfNotNull(reactions).ifEmpty { null } + loadEventsChannel.filter = listOfNotNull(missing).ifEmpty { null } + } + + fun add(eventId: String) { + channelsToWatch = channelsToWatch.plus(eventId) + invalidateFilters() + } + + fun remove(eventId: String) { + channelsToWatch = channelsToWatch.minus(eventId) + invalidateFilters() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index 1d0e0507a..e656e1be6 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -155,6 +155,33 @@ fun NoteCompose( ) } } + + // boosted picture + val baseChannel = note.channel + if (note.event is ChannelMessageEvent && baseChannel != null) { + val channelState by baseChannel.live.observeAsState() + val channel = channelState?.channel + + if (channel != null) { + Box( + Modifier + .width(30.dp) + .height(30.dp) + .align(Alignment.BottomEnd)) { + AsyncImage( + model = channel.profilePicture(), + placeholder = null, + contentDescription = "Group Picture", + modifier = Modifier + .width(30.dp) + .height(30.dp) + .clip(shape = CircleShape) + .background(MaterialTheme.colors.background) + .border(2.dp, MaterialTheme.colors.background, CircleShape) + ) + } + } + } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt index 0685942ae..df0086235 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt @@ -91,11 +91,14 @@ fun ReplyInformationChannel(replyTo: MutableList?, mentions: List?, @Composable fun ReplyInformationChannel(replyTo: MutableList?, mentions: List?, - channel: Channel, + baseChannel: Channel, prefix: String = "", onUserTagClick: (User) -> Unit, onChannelTagClick: (Channel) -> Unit ) { + val channelState by baseChannel.live.observeAsState() + val channel = channelState?.channel ?: return + FlowRow() { Text( "in channel ",