Trying to fix the crash

This commit is contained in:
Kgothatso Ngako
2026-05-02 01:01:15 +02:00
parent 0531248457
commit bfc540812d
11 changed files with 41 additions and 51 deletions

View File

@@ -103,15 +103,17 @@ abstract class NostrDao(
synchronizationRelayURLs: List<String>,
level: Int
) {
logger.i("Store Nostr Event: $nostrEvent")
val storedNostrEvent = database.nostrEventDao().getNostrEventById(nostrEvent.id)
if (storedNostrEvent == null) {
// Add new nostr event
logger.i("Store Nostr Event: $nostrEvent")
database.nostrEventDao().insert(nostrEvent)
} else if (nostrEvent.createdAt > storedNostrEvent.createdAt) {
// Update nostr event`
logger.i("Update Nostr Event: $nostrEvent")
database.nostrEventDao().upsert(nostrEvent)
} else {
// Nothing else needs to be done
@@ -120,12 +122,12 @@ abstract class NostrDao(
logger.i("This is a placeholder profile might need to get synced...: ${profile.publicKey}")
// Setup the sync here...
} else {
logger.i("We have the latest version for: ${nostrEvent.id}")
return
}
}
// Index nostrEvent
logger.i("Index Nostr Event: ${nostrEvent.id}")
indexNostrEvent(
nostrEvent = nostrEvent,
synchronizationRelayURLs = synchronizationRelayURLs,
@@ -144,7 +146,6 @@ abstract class NostrDao(
val eventIdsToSync = mutableSetOf<String>()
if (nostrEvent.unsignedNostrEventId == null) {
logger.i("Store Nostr Event: $nostrEvent")
// Find or create profile with the pubKey... if not found submit a sync request...
val profile = database.profileDao().getProfileByPublicKey(nostrEvent.pubKey)

View File

@@ -17,36 +17,36 @@ import kotlinx.coroutines.flow.Flow
@Dao
interface NostrEventDao {
@Query("SELECT * FROM NostrEvent WHERE kind in (:kinds) ORDER BY createdAt DESC")
fun observeNostrEvents(kinds: Array<Kind>): Flow<List<LocalNostrEvent>>
fun observeNostrEvents(kinds: Array<Kind>): Flow<List<LocalNostrEvent?>?>
@Query("SELECT * FROM NostrEvent WHERE content LIKE '%' || :search || '%' AND kind in (:kinds) ORDER BY createdAt DESC")
fun observeFilteredNostrEvents(
kinds: Array<Kind>,
search: String
): Flow<List<LocalNostrEvent>>
): Flow<List<LocalNostrEvent?>?>
@Query("SELECT * FROM NostrEvent WHERE kind in (:kinds) AND id in (:ids) ORDER BY createdAt DESC")
fun observeFilteredNostrEvents(
kinds: Array<Kind>,
ids: Array<HexKey>,
): Flow<List<LocalNostrEvent>>
): Flow<List<LocalNostrEvent?>?>
@Query("SELECT * FROM NostrEvent WHERE kind in (:kinds) AND pubKey in (:authors) ORDER BY createdAt DESC LIMIT 50")
fun observeAuthoredNostrEvents(
kinds: Array<Kind>,
authors: Array<HexKey>,
): Flow<List<LocalNostrEvent>>
): Flow<List<LocalNostrEvent?>?>
@Query("SELECT * FROM NostrEvent WHERE tags LIKE '%' || :publicKey || '%' AND kind in (:kinds) ORDER BY createdAt DESC")
fun observePublicKeyMentionedNostrEvents(
kinds: Array<Kind>,
publicKey: HexKey
): Flow<List<LocalNostrEvent>>
): Flow<List<LocalNostrEvent?>?>
@RawQuery
fun observePublicKeyFollowingNostrEvents(
query: RoomRawQuery
): Flow<List<LocalNostrEvent>>
): Flow<List<LocalNostrEvent?>?>
@Query("SELECT * FROM NostrEvent WHERE kind in (:kinds) ORDER BY savedAt DESC")
fun getAllNostrEvents(kinds: Array<Kind>): List<NostrEvent>

View File

@@ -6,7 +6,7 @@ import androidx.room3.Embedded
import androidx.room3.Relation
data class LocalMention(
@Embedded val mention: Mention,
@Embedded val mention: Mention?,
@Relation(
parentColumn = "mentionedPublicKey",

View File

@@ -61,7 +61,7 @@ data class LocalNostrEvent(
parentColumn = "id",
entityColumn = "nostrEventId",
)
val mentionedProfiles: List<LocalMention?> = emptyList(),
val mentionedProfiles: List<LocalMention?>? = emptyList(),
) {
@Composable
fun RenderNotePreview() {

View File

@@ -57,14 +57,11 @@ import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlin.collections.emptyMap
import kotlin.collections.plus
import kotlin.time.Clock
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds
import kotlin.time.Instant
class DatabaseNostrRepository(
@@ -73,12 +70,12 @@ class DatabaseNostrRepository(
): NostrRepository, RelayRepository {
companion object {
const val TAG = "DatabaseNostrRepository"
private val storeNostrEventMutex = Mutex()
}
val logger = Logger.withTag(TAG)
private val storeNostrEventMutex = Mutex()
override suspend fun observeProfile(publicKey: HexKey): Flow<LocalAccount?> {
return database.unsignedNostrEventDao().observeProfile(publicKey)
}
@@ -404,6 +401,7 @@ class DatabaseNostrRepository(
synchronizationRelayURLs: List<String>
) {
storeNostrEventMutex.withLock {
logger.d("saveNostrEvent: $nostrEvent")
database.nostrDao().storeNostrEvent(
nostrEvent,
synchronizationRelayURLs = synchronizationRelayURLs,
@@ -417,6 +415,7 @@ class DatabaseNostrRepository(
)
)
}
logger.d("done: ${nostrEvent.id}")
}
override suspend fun queueSynchronizeNostrEvent(
@@ -442,7 +441,7 @@ class DatabaseNostrRepository(
)
}
override suspend fun observeNostrFeed(): Flow<List<LocalNostrEvent>> {
override suspend fun observeNostrFeed(): Flow<List<LocalNostrEvent?>?> {
return database.nostrEventDao().observeNostrEvents(
kinds = arrayOf(
TextNoteEvent.KIND,
@@ -453,7 +452,7 @@ class DatabaseNostrRepository(
)
}
override suspend fun observeNostrFeed(synchronizationFilter: SynchronizationFilter): Flow<List<LocalNostrEvent>> {
override suspend fun observeNostrFeed(synchronizationFilter: SynchronizationFilter): Flow<List<LocalNostrEvent?>?> {
return when {
synchronizationFilter.kinds != null && synchronizationFilter.search != null -> {

View File

@@ -84,9 +84,9 @@ interface NostrRepository {
suspend fun getNostrEvent(publicKey: HexKey, kind: Kind): NostrEvent?
suspend fun observeNostrFeed(): Flow<List<LocalNostrEvent>>
suspend fun observeNostrFeed(): Flow<List<LocalNostrEvent?>?>
suspend fun observeNostrFeed(synchronizationFilter: SynchronizationFilter): Flow<List<LocalNostrEvent>>
suspend fun observeNostrFeed(synchronizationFilter: SynchronizationFilter): Flow<List<LocalNostrEvent?>?>
suspend fun observeLocalNostrEventById(nostrEventId: String): Flow<LocalNostrEvent?>
@@ -207,11 +207,11 @@ interface NostrRepository {
TODO("Not yet implemented")
}
override suspend fun observeNostrFeed(): Flow<List<LocalNostrEvent>> {
override suspend fun observeNostrFeed(): Flow<List<LocalNostrEvent?>?> {
TODO("Not yet implemented")
}
override suspend fun observeNostrFeed(synchronizationFilter: SynchronizationFilter): Flow<List<LocalNostrEvent>> {
override suspend fun observeNostrFeed(synchronizationFilter: SynchronizationFilter): Flow<List<LocalNostrEvent?>?> {
TODO("Not yet implemented")
}

View File

@@ -35,7 +35,7 @@ import coil3.compose.AsyncImage
fun RichContent(
nostrEvent: NostrEvent,
localQuotedNostrEvent: LocalQuotedNostrEvent?,
mentionedProfiles: List<LocalMention?>,
mentionedProfiles: List<LocalMention?>?,
style: TextStyle = MaterialTheme.typography.bodyLarge,
color: Color = MaterialTheme.colorScheme.onSurface,
linkColor: Color = Color.Unspecified,
@@ -110,7 +110,7 @@ fun RichContent(
val profileNames = remember(profilePubkeys) {
val names = mutableMapOf<String, String>()
if (mentionedProfiles.isNotEmpty()) {
if (mentionedProfiles?.isNotEmpty() == true) {
Logger.withTag("RichContent").d("mentionedProfiles: ${mentionedProfiles}")
for (pubkey in profilePubkeys) {
val mentionedProfile = mentionedProfiles.find { mentionedProfile -> mentionedProfile?.profile?.publicKey == pubkey }

View File

@@ -36,7 +36,7 @@ internal fun TextNoteFeedItem(
profile: Profile?,
localInReplyToNostrEvent: LocalInReplyToNostrEvent?,
localQuotedNostrEvent: LocalQuotedNostrEvent?,
mentionedProfiles: List<LocalMention?>,
mentionedProfiles: List<LocalMention?>?,
onNavigateToEvent: (HexKey) -> Unit
) {
if (localInReplyToNostrEvent != null) {

View File

@@ -2,7 +2,6 @@ package ac.cord.auxiliary.compose.ui.view.model
import ac.cord.auxiliary.compose.database.model.SynchronizeNostrEventRequest
import ac.cord.auxiliary.compose.database.model.types.SynchronizationFilter
import ac.cord.auxiliary.compose.managers.SeedManager
import ac.cord.auxiliary.compose.nostr.Relays
import ac.cord.auxiliary.compose.repository.NostrRepository
import ac.cord.auxiliary.compose.ui.composable.navigation.routes.NostrEventDetailRoute
@@ -34,19 +33,8 @@ import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import co.touchlab.kermit.Logger
import com.vitorpamplona.quartz.nip01Core.core.toHexKey
import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent
import com.vitorpamplona.quartz.nip04Dm.messages.PrivateDmEvent
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
import com.vitorpamplona.quartz.nip18Reposts.RepostEvent
import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent
import com.vitorpamplona.quartz.nip96FileStorage.config.FileServersEvent
import com.vitorpamplona.quartz.nipB7Blossom.BlossomServersEvent
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
class FeedListViewModel(
@@ -74,7 +62,7 @@ class FeedListViewModel(
synchronizationFilter
).collect { localNostrEvents ->
feedListUIState = FeedListUIState.Loaded(
localNostrEvents = localNostrEvents
localNostrEvents = localNostrEvents?.filterNotNull() ?: emptyList()
)
}
}

View File

@@ -32,6 +32,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.getAndUpdate
import kotlinx.coroutines.flow.timeout
import kotlinx.coroutines.launch
@@ -94,7 +95,7 @@ class NavigationViewModel(
scope.launch(Dispatchers.IO) {
nostrRepository.observeUnsignedNostrEvents(
publicKey = SeedManager.activePublicKey().toHexKey()
).collect { unsignedNostrEventOrNull ->
).distinctUntilChanged().collect { unsignedNostrEventOrNull ->
unsignedNostrEventOrNull?.let { unsignedNostrEvent ->
logger.d("Unsigned")
val event = tempSigner.signNormal<Event>(
@@ -128,7 +129,7 @@ class NavigationViewModel(
logger.i { "observePendingSyncNostrEventRequests" }
scope.launch(Dispatchers.IO) {
nostrRepository.observePendingSynchronizeNostrEventRequests().collect { synchronizeNostrEventRequestOrNull ->
nostrRepository.observePendingSynchronizeNostrEventRequests().distinctUntilChanged().collect { synchronizeNostrEventRequestOrNull ->
synchronizeNostrEventRequestOrNull?.let { synchronizeNostrEventRequest ->
logger.i("synchronizeNostrEventRequest: $synchronizeNostrEventRequest")
val reqCommand = ReqCmd(
@@ -158,15 +159,16 @@ class NavigationViewModel(
).collect { nostrIncomingMessage ->
when (nostrIncomingMessage) {
is NostrIncomingMessage.EventMessage -> {
logger.d("Import message: $nostrIncomingMessage")
nostrIncomingMessage.nostrEvent?.let {
nostrRepository.saveNostrEvent(
nostrEvent = it,
synchronizeNostrEventRequest,
synchronizationRelayURLs = listOf(synchronizeNostrEventRequest.relayURL) // TODO: + Relays.eventPublishRelaySet.map { normalizedRelayUrl -> normalizedRelayUrl.url }
)
scope.launch(Dispatchers.IO) {
logger.d("Import message: $nostrIncomingMessage")
nostrIncomingMessage.nostrEvent?.let {
nostrRepository.saveNostrEvent(
nostrEvent = it,
synchronizeNostrEventRequest,
synchronizationRelayURLs = listOf(synchronizeNostrEventRequest.relayURL) // TODO: + Relays.eventPublishRelaySet.map { normalizedRelayUrl -> normalizedRelayUrl.url }
)
}
}
}
is NostrIncomingMessage.EventsMessage -> {
logger.d("Import messages: $nostrIncomingMessage")
@@ -212,7 +214,7 @@ class NavigationViewModel(
logger.i { "observePendingBroadcastNostrEventRequests" }
scope.launch(Dispatchers.IO) {
nostrRepository.observePendingBroadcastNostrEventRequests().collect { localBroadcastNostrEventRequests ->
nostrRepository.observePendingBroadcastNostrEventRequests().distinctUntilChanged().collect { localBroadcastNostrEventRequests ->
localBroadcastNostrEventRequests.forEach { localBroadcastNostrEventRequest ->
nostrRepository.broadcastProcessed(
@@ -289,7 +291,7 @@ class NavigationViewModel(
logger.i("Observing: $publicKey")
nostrRepository.observeProfile(
publicKey = publicKey
).collect { localProfile ->
).distinctUntilChanged().collect { localProfile ->
logger.i("Local Profile: $localProfile")
_navigationUIState.getAndUpdate {
if (localProfile == null) {

View File

@@ -161,7 +161,7 @@ class SearchResultViewModel(
// This is something not taking into consideration the results we are actually looking for...
nostrRepository.observeNostrFeed(synchronizationFilter).collect { localNostrEvents ->
searchResultListUIState = SearchResultListUIState.Loaded(
localNostrEvents = localNostrEvents
localNostrEvents = localNostrEvents?.filterNotNull() ?: emptyList()
)
}
}