Skip to content

Commit

Permalink
Adds support for Interactive Stories
Browse files Browse the repository at this point in the history
  • Loading branch information
vitorpamplona committed Nov 27, 2024
1 parent 034ee46 commit bdf012f
Show file tree
Hide file tree
Showing 24 changed files with 994 additions and 92 deletions.
164 changes: 153 additions & 11 deletions amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ import com.vitorpamplona.quartz.events.GenericRepostEvent
import com.vitorpamplona.quartz.events.GiftWrapEvent
import com.vitorpamplona.quartz.events.GitReplyEvent
import com.vitorpamplona.quartz.events.HTTPAuthorizationEvent
import com.vitorpamplona.quartz.events.InteractiveStoryBaseEvent
import com.vitorpamplona.quartz.events.InteractiveStoryPrologueEvent
import com.vitorpamplona.quartz.events.InteractiveStoryReadingStateEvent
import com.vitorpamplona.quartz.events.InteractiveStorySceneEvent
import com.vitorpamplona.quartz.events.LiveActivitiesChatMessageEvent
import com.vitorpamplona.quartz.events.LnZapEvent
import com.vitorpamplona.quartz.events.LnZapPaymentRequestEvent
Expand All @@ -114,6 +118,7 @@ import com.vitorpamplona.quartz.events.Response
import com.vitorpamplona.quartz.events.SealedGossipEvent
import com.vitorpamplona.quartz.events.SearchRelayListEvent
import com.vitorpamplona.quartz.events.StatusEvent
import com.vitorpamplona.quartz.events.StoryOption
import com.vitorpamplona.quartz.events.TextNoteEvent
import com.vitorpamplona.quartz.events.TextNoteModificationEvent
import com.vitorpamplona.quartz.events.TorrentCommentEvent
Expand Down Expand Up @@ -2457,6 +2462,142 @@ class Account(
}
}

suspend fun createInteractiveStoryReadingState(
root: InteractiveStoryBaseEvent,
rootRelay: String?,
readingScene: InteractiveStoryBaseEvent,
readingSceneRelay: String?,
) {
if (!isWriteable()) return

val relayList = getPrivateOutBoxRelayList()

InteractiveStoryReadingStateEvent.create(
root = root,
rootRelay = rootRelay,
currentScene = readingScene,
currentSceneRelay = readingSceneRelay,
signer = signer,
) {
if (relayList.isNotEmpty()) {
Client.sendPrivately(it, relayList = relayList)
} else {
Client.send(it)
}
LocalCache.justConsume(it, null)
}
}

suspend fun updateInteractiveStoryReadingState(
readingState: InteractiveStoryReadingStateEvent,
readingScene: InteractiveStoryBaseEvent,
readingSceneRelay: String?,
) {
if (!isWriteable()) return

val relayList = getPrivateOutBoxRelayList()

InteractiveStoryReadingStateEvent.update(
base = readingState,
currentScene = readingScene,
currentSceneRelay = readingSceneRelay,
signer = signer,
) {
if (relayList.isNotEmpty()) {
Client.sendPrivately(it, relayList = relayList)
} else {
Client.send(it)
}
LocalCache.justConsume(it, null)
}
}

suspend fun sendInteractiveStoryPrologue(
baseId: String,
title: String,
content: String,
options: List<StoryOption>,
summary: String? = null,
image: String? = null,
zapReceiver: List<ZapSplitSetup>? = null,
wantsToMarkAsSensitive: Boolean = false,
zapRaiserAmount: Long? = null,
nip94attachments: List<FileHeaderEvent>? = null,
draftTag: String? = null,
relayList: List<RelaySetupInfo>,
) {
if (!isWriteable()) return

InteractiveStoryPrologueEvent.create(
baseId = baseId,
title = title,
content = content,
options = options,
summary = summary,
image = image,
zapReceiver = zapReceiver,
markAsSensitive = wantsToMarkAsSensitive,
zapRaiserAmount = zapRaiserAmount,
nip94attachments = nip94attachments,
signer = signer,
isDraft = draftTag != null,
) {
if (draftTag != null) {
if (content.isBlank()) {
deleteDraft(draftTag)
} else {
DraftEvent.create(draftTag, it, signer) { draftEvent ->
sendDraftEvent(draftEvent)
}
}
} else {
Client.send(it, relayList = relayList)
LocalCache.justConsume(it, null)
}
}
}

suspend fun sendInteractiveStoryScene(
baseId: String,
title: String,
content: String,
options: List<StoryOption>,
zapReceiver: List<ZapSplitSetup>? = null,
wantsToMarkAsSensitive: Boolean = false,
zapRaiserAmount: Long? = null,
nip94attachments: List<FileHeaderEvent>? = null,
draftTag: String? = null,
relayList: List<RelaySetupInfo>,
) {
if (!isWriteable()) return

InteractiveStorySceneEvent.create(
baseId = baseId,
title = title,
content = content,
options = options,
zapReceiver = zapReceiver,
markAsSensitive = wantsToMarkAsSensitive,
zapRaiserAmount = zapRaiserAmount,
nip94attachments = nip94attachments,
signer = signer,
isDraft = draftTag != null,
) {
if (draftTag != null) {
if (content.isBlank()) {
deleteDraft(draftTag)
} else {
DraftEvent.create(draftTag, it, signer) { draftEvent ->
sendDraftEvent(draftEvent)
}
}
} else {
Client.send(it, relayList = relayList)
LocalCache.justConsume(it, null)
}
}
}

suspend fun sendPost(
message: String,
replyTo: List<Note>?,
Expand Down Expand Up @@ -2823,18 +2964,19 @@ class Account(
}
}

fun sendDraftEvent(draftEvent: DraftEvent) {
val relayList =
normalizedPrivateOutBoxRelaySet.value.map {
RelaySetupInfoToConnect(
it,
shouldUseTorForClean(it),
true,
true,
emptySet(),
)
}
fun getPrivateOutBoxRelayList(): List<RelaySetupInfoToConnect> =
normalizedPrivateOutBoxRelaySet.value.map {
RelaySetupInfoToConnect(
it,
shouldUseTorForClean(it),
true,
true,
emptySet(),
)
}

fun sendDraftEvent(draftEvent: DraftEvent) {
val relayList = getPrivateOutBoxRelayList()
if (relayList.isNotEmpty()) {
Client.sendPrivately(draftEvent, relayList)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ import com.vitorpamplona.quartz.events.GitPatchEvent
import com.vitorpamplona.quartz.events.GitReplyEvent
import com.vitorpamplona.quartz.events.GitRepositoryEvent
import com.vitorpamplona.quartz.events.HighlightEvent
import com.vitorpamplona.quartz.events.InteractiveStoryPrologueEvent
import com.vitorpamplona.quartz.events.InteractiveStoryReadingStateEvent
import com.vitorpamplona.quartz.events.InteractiveStorySceneEvent
import com.vitorpamplona.quartz.events.LiveActivitiesChatMessageEvent
import com.vitorpamplona.quartz.events.LiveActivitiesEvent
import com.vitorpamplona.quartz.events.LnZapEvent
Expand Down Expand Up @@ -449,6 +452,21 @@ object LocalCache {
relay: Relay?,
) = consumeRegularEvent(event, relay)

fun consume(
event: InteractiveStoryPrologueEvent,
relay: Relay?,
) = consumeBaseReplaceable(event, relay)

fun consume(
event: InteractiveStorySceneEvent,
relay: Relay?,
) = consumeBaseReplaceable(event, relay)

fun consume(
event: InteractiveStoryReadingStateEvent,
relay: Relay?,
) = consumeBaseReplaceable(event, relay)

fun consumeRegularEvent(
event: Event,
relay: Relay?,
Expand Down Expand Up @@ -2393,6 +2411,9 @@ object LocalCache {
is GitPatchEvent -> consume(event, relay)
is GitRepositoryEvent -> consume(event, relay)
is HighlightEvent -> consume(event, relay)
is InteractiveStoryPrologueEvent -> consume(event, relay)
is InteractiveStorySceneEvent -> consume(event, relay)
is InteractiveStoryReadingStateEvent -> consume(event, relay)
is LiveActivitiesEvent -> consume(event, relay)
is LiveActivitiesChatMessageEvent -> consume(event, relay)
is LnZapEvent -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ import com.vitorpamplona.quartz.events.GitIssueEvent
import com.vitorpamplona.quartz.events.GitPatchEvent
import com.vitorpamplona.quartz.events.GitReplyEvent
import com.vitorpamplona.quartz.events.HighlightEvent
import com.vitorpamplona.quartz.events.InteractiveStoryPrologueEvent
import com.vitorpamplona.quartz.events.InteractiveStorySceneEvent
import com.vitorpamplona.quartz.events.LnZapEvent
import com.vitorpamplona.quartz.events.LnZapPaymentResponseEvent
import com.vitorpamplona.quartz.events.MetadataEvent
Expand Down Expand Up @@ -245,6 +247,8 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") {
CalendarDateSlotEvent.KIND,
CalendarTimeSlotEvent.KIND,
CalendarRSVPEvent.KIND,
InteractiveStoryPrologueEvent.KIND,
InteractiveStorySceneEvent.KIND,
),
tags = mapOf("p" to listOf(account.userProfile().pubkeyHex)),
limit = 400,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import com.vitorpamplona.quartz.events.ChannelMessageEvent
import com.vitorpamplona.quartz.events.ClassifiedsEvent
import com.vitorpamplona.quartz.events.CommentEvent
import com.vitorpamplona.quartz.events.HighlightEvent
import com.vitorpamplona.quartz.events.InteractiveStorySceneEvent
import com.vitorpamplona.quartz.events.LiveActivitiesChatMessageEvent
import com.vitorpamplona.quartz.events.LongTextNoteEvent
import com.vitorpamplona.quartz.events.PollNoteEvent
Expand All @@ -38,46 +39,59 @@ import com.vitorpamplona.quartz.events.WikiNoteEvent
object NostrHashtagDataSource : AmethystNostrDataSource("SingleHashtagFeed") {
private var hashtagToWatch: String? = null

fun createLoadHashtagFilter(): TypedFilter? {
val hashToLoad = hashtagToWatch ?: return null
fun createLoadHashtagFilter(): List<TypedFilter> {
val hashToLoad = hashtagToWatch ?: return emptyList()

return TypedFilter(
types = COMMON_FEED_TYPES,
filter =
SincePerRelayFilter(
tags =
mapOf(
"t" to
listOf(
hashToLoad,
hashToLoad.lowercase(),
hashToLoad.uppercase(),
hashToLoad.capitalize(),
),
),
kinds =
listOf(
TextNoteEvent.KIND,
ChannelMessageEvent.KIND,
LongTextNoteEvent.KIND,
PollNoteEvent.KIND,
LiveActivitiesChatMessageEvent.KIND,
ClassifiedsEvent.KIND,
HighlightEvent.KIND,
AudioTrackEvent.KIND,
AudioHeaderEvent.KIND,
WikiNoteEvent.KIND,
CommentEvent.KIND,
),
limit = 200,
),
val hashtagsToFollow =
listOf(
hashToLoad,
hashToLoad.lowercase(),
hashToLoad.uppercase(),
hashToLoad.capitalize(),
)

return listOf(
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
SincePerRelayFilter(
tags = mapOf("t" to hashtagsToFollow),
kinds =
listOf(
TextNoteEvent.KIND,
ChannelMessageEvent.KIND,
LongTextNoteEvent.KIND,
PollNoteEvent.KIND,
LiveActivitiesChatMessageEvent.KIND,
ClassifiedsEvent.KIND,
HighlightEvent.KIND,
AudioTrackEvent.KIND,
AudioHeaderEvent.KIND,
WikiNoteEvent.KIND,
CommentEvent.KIND,
),
limit = 200,
),
),
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
SincePerRelayFilter(
tags = mapOf("t" to hashtagsToFollow),
kinds =
listOf(
InteractiveStorySceneEvent.KIND,
),
limit = 200,
),
),
)
}

val loadHashtagChannel = requestNewChannel()

override fun updateChannelFilters() {
loadHashtagChannel.typedFilters = listOfNotNull(createLoadHashtagFilter()).ifEmpty { null }
loadHashtagChannel.typedFilters = createLoadHashtagFilter().ifEmpty { null }
}

fun loadHashtag(tag: String?) {
Expand Down
Loading

0 comments on commit bdf012f

Please sign in to comment.