Skip to content

Commit 2065dc7

Browse files
Fix stream pill flicker when returning to the foreground (#1087)
Co-authored-by: Aleksandar Ilic <aleksandar@appollo41.com>
1 parent 650ab01 commit 2065dc7

5 files changed

Lines changed: 68 additions & 1 deletion

File tree

app/src/main/kotlin/net/primal/android/user/subscriptions/SubscriptionsManager.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import net.primal.core.networking.primal.PrimalApiClient
2929
import net.primal.core.networking.primal.PrimalCacheFilter
3030
import net.primal.core.networking.primal.PrimalSocketSubscription
3131
import net.primal.core.utils.coroutines.DispatcherProvider
32+
import net.primal.core.utils.runCatching
3233
import net.primal.core.utils.serialization.encodeToJsonString
3334
import net.primal.data.remote.api.notifications.model.PubkeyRequestBody
3435
import net.primal.domain.streams.StreamRepository
@@ -138,6 +139,7 @@ class SubscriptionsManager @Inject constructor(
138139

139140
private fun launchStreamsFromFollowsSubscription(userId: String) =
140141
scope.launch {
142+
runCatching { streamRepository.fetchLiveEventsFromFollows(userId = userId) }
141143
streamRepository.startLiveEventsFromFollowsSubscription(userId = userId)
142144
}
143145

data/caching/remote/src/commonMain/kotlin/net/primal/data/remote/api/stream/LiveStreamApi.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,7 @@ interface LiveStreamApi {
1717

1818
suspend fun subscribeToLiveEventsFromFollows(userId: String): Flow<NostrEvent>
1919

20+
suspend fun getLiveEventsFromFollowsSnapshot(userId: String): List<NostrEvent>
21+
2022
suspend fun findLiveStream(body: FindLiveStreamRequestBody): FindLiveStreamResponse
2123
}

data/caching/remote/src/commonMain/kotlin/net/primal/data/remote/api/stream/LiveStreamApiImpl.kt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@ package net.primal.data.remote.api.stream
22

33
import io.github.aakira.napier.Napier
44
import kotlin.time.Duration.Companion.milliseconds
5+
import kotlin.time.Duration.Companion.seconds
56
import kotlin.uuid.Uuid
7+
import kotlinx.coroutines.FlowPreview
8+
import kotlinx.coroutines.TimeoutCancellationException
69
import kotlinx.coroutines.flow.Flow
710
import kotlinx.coroutines.flow.catch
811
import kotlinx.coroutines.flow.map
912
import kotlinx.coroutines.flow.mapNotNull
13+
import kotlinx.coroutines.flow.takeWhile
14+
import kotlinx.coroutines.flow.timeout
1015
import net.primal.core.networking.primal.PrimalApiClient
1116
import net.primal.core.networking.primal.PrimalCacheFilter
1217
import net.primal.core.networking.sockets.NostrIncomingMessage
@@ -73,6 +78,36 @@ class LiveStreamApiImpl(
7378
}
7479
}
7580

81+
@OptIn(FlowPreview::class)
82+
override suspend fun getLiveEventsFromFollowsSnapshot(userId: String): List<NostrEvent> {
83+
val subscriptionId = Uuid.random().toPrimalSubscriptionId()
84+
val liveEvents = mutableListOf<NostrEvent>()
85+
try {
86+
primalApiClient
87+
.subscribe(
88+
subscriptionId = subscriptionId,
89+
message = PrimalCacheFilter(
90+
primalVerb = PrimalVerb.LIVE_EVENTS_FROM_FOLLOWS.id,
91+
optionsJson = LiveEventsFromFollowsRequest(pubkey = userId).encodeToJsonString(),
92+
),
93+
)
94+
.takeWhile {
95+
it is NostrIncomingMessage.EventMessage || it is NostrIncomingMessage.EventsMessage
96+
}
97+
.timeout(5.seconds)
98+
.collect { message ->
99+
when (message) {
100+
is NostrIncomingMessage.EventMessage -> message.nostrEvent?.let { liveEvents.add(it) }
101+
is NostrIncomingMessage.EventsMessage -> liveEvents.addAll(message.nostrEvents)
102+
else -> Unit
103+
}
104+
}
105+
} catch (error: TimeoutCancellationException) {
106+
Napier.w(throwable = error) { "Timed out collecting `live_events_from_follows` snapshot." }
107+
}
108+
return liveEvents.filter { it.kind == NostrEventKind.LiveActivity.value }
109+
}
110+
76111
override suspend fun findLiveStream(body: FindLiveStreamRequestBody): FindLiveStreamResponse {
77112
val queryResult = primalApiClient.query(
78113
message = PrimalCacheFilter(

data/caching/repository/src/commonMain/kotlin/net/primal/data/repository/streams/StreamRepositoryImpl.kt

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,35 @@ class StreamRepositoryImpl(
112112
return@withContext job
113113
}
114114

115+
override suspend fun fetchLiveEventsFromFollows(userId: String) =
116+
withContext(dispatcherProvider.io()) {
117+
val currentLiveStreams = liveStreamApi.getLiveEventsFromFollowsSnapshot(userId = userId)
118+
.mapNotNull { it.asStreamData() }
119+
120+
currentLiveStreams.forEach { liveActivity ->
121+
scope.launch {
122+
profileRepository.fetchMissingProfiles(profileIds = listOf(liveActivity.mainHostId))
123+
}
124+
}
125+
126+
database.withTransaction {
127+
database.streams().upsertStreamData(data = currentLiveStreams)
128+
database.streamFollows().deleteAllByOwnerId(ownerId = userId)
129+
currentLiveStreams
130+
.filter { it.isLive() }
131+
.forEach { liveActivity ->
132+
database.streamFollows().upsert(
133+
data = StreamFollowsCrossRef(
134+
streamATag = liveActivity.aTag,
135+
ownerId = userId,
136+
),
137+
)
138+
}
139+
}
140+
}
141+
115142
override suspend fun startLiveEventsFromFollowsSubscription(userId: String) =
116143
withContext(dispatcherProvider.io()) {
117-
database.streamFollows().deleteAllByOwnerId(ownerId = userId)
118144
liveStreamApi.subscribeToLiveEventsFromFollows(userId = userId)
119145
.collect { liveActivityEvent ->
120146
val liveActivity = liveActivityEvent.asStreamData() ?: return@collect

domain/primal/src/commonMain/kotlin/net/primal/domain/streams/StreamRepository.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ interface StreamRepository {
3535
streamContentModerationMode: StreamContentModerationMode,
3636
): Job
3737

38+
suspend fun fetchLiveEventsFromFollows(userId: String)
39+
3840
suspend fun startLiveEventsFromFollowsSubscription(userId: String)
3941

4042
fun observeLiveEventsFromFollows(userId: String): Flow<List<Stream>>

0 commit comments

Comments
 (0)