Prep to show loading on pending sync
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 1,
|
||||
"identityHash": "31032766d6bdd6ae4664e854a928dd32",
|
||||
"identityHash": "770e86deaca12c1e4d82a71f6613da37",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "BroadcastNostrEventReceipt",
|
||||
@@ -929,7 +929,7 @@
|
||||
},
|
||||
{
|
||||
"tableName": "SynchronizeNostrEventRequest",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `status` TEXT NOT NULL, `relayURL` TEXT NOT NULL, `isRecommendedRelay` INTEGER NOT NULL, `synchronizationFilters` TEXT NOT NULL, `nostrEventId` TEXT, `unsignedNostrEventId` INTEGER, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`unsignedNostrEventId`) REFERENCES `UnsignedNostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `purpose` TEXT NOT NULL, `status` TEXT NOT NULL, `relayURL` TEXT NOT NULL, `isRecommendedRelay` INTEGER NOT NULL, `synchronizationFilters` TEXT NOT NULL, `nostrEventId` TEXT, `unsignedNostrEventId` INTEGER, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`unsignedNostrEventId`) REFERENCES `UnsignedNostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
@@ -937,6 +937,12 @@
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "purpose",
|
||||
"columnName": "purpose",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "status",
|
||||
"columnName": "status",
|
||||
@@ -1368,7 +1374,7 @@
|
||||
],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '31032766d6bdd6ae4664e854a928dd32')"
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '770e86deaca12c1e4d82a71f6613da37')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -122,6 +122,7 @@ abstract class NostrDao(
|
||||
database.synchronizeNostrEventRequestDao().insert(
|
||||
synchronizationRelayURLs.map { synchronizationRelayURL ->
|
||||
SynchronizeNostrEventRequest(
|
||||
purpose = "synchronization",
|
||||
synchronizationFilters = arrayOf(
|
||||
SynchronizationFilter(
|
||||
authors = arrayOf(nostrEvent.pubKey),
|
||||
@@ -144,6 +145,7 @@ abstract class NostrDao(
|
||||
val synchronizeNostrEventRequests = if (recommendRelayUrl != null) {
|
||||
listOf(
|
||||
SynchronizeNostrEventRequest(
|
||||
purpose = "synchronization",
|
||||
synchronizationFilters = arrayOf(
|
||||
SynchronizationFilter(
|
||||
ids = arrayOf(taggedEvent.eventId)
|
||||
@@ -156,6 +158,7 @@ abstract class NostrDao(
|
||||
} else {
|
||||
synchronizationRelayURLs.map { synchronizationRelayURL ->
|
||||
SynchronizeNostrEventRequest(
|
||||
purpose = "synchronization",
|
||||
synchronizationFilters = arrayOf(
|
||||
SynchronizationFilter(
|
||||
ids = arrayOf(taggedEvent.eventId)
|
||||
@@ -178,6 +181,7 @@ abstract class NostrDao(
|
||||
val synchronizeNostrEventRequests = if (recommendedRelay != null) {
|
||||
listOf(
|
||||
SynchronizeNostrEventRequest(
|
||||
purpose = "synchronization",
|
||||
synchronizationFilters = arrayOf(
|
||||
SynchronizationFilter(
|
||||
authors = arrayOf(taggedUser.pubKey),
|
||||
@@ -191,6 +195,7 @@ abstract class NostrDao(
|
||||
} else {
|
||||
synchronizationRelayURLs.map { synchronizationRelayURL ->
|
||||
SynchronizeNostrEventRequest(
|
||||
purpose = "synchronization",
|
||||
synchronizationFilters = arrayOf(
|
||||
SynchronizationFilter(
|
||||
authors = arrayOf(taggedUser.pubKey),
|
||||
@@ -266,6 +271,7 @@ abstract class NostrDao(
|
||||
database.synchronizeNostrEventRequestDao().insert(
|
||||
synchronizationRelayURLs.map { synchronizationRelayURL ->
|
||||
SynchronizeNostrEventRequest(
|
||||
purpose = "synchronization",
|
||||
synchronizationFilters = arrayOf(
|
||||
SynchronizationFilter(
|
||||
authors = arrayOf(nostrEvent.pubKey),
|
||||
@@ -298,6 +304,7 @@ abstract class NostrDao(
|
||||
database.synchronizeNostrEventRequestDao().insert(
|
||||
synchronizationRelayURLs.map { synchronizationRelayURL ->
|
||||
SynchronizeNostrEventRequest(
|
||||
purpose = "synchronization",
|
||||
synchronizationFilters = arrayOf(
|
||||
SynchronizationFilter(
|
||||
ids = arrayOf(zap.postId)
|
||||
|
||||
@@ -12,6 +12,9 @@ interface SynchronizeNostrEventRequestDao {
|
||||
@Query("SELECT * FROM SynchronizeNostrEventRequest WHERE status = :status")
|
||||
fun observeSynchronizeNostrEventRequestsByStatus(status: String): Flow<SynchronizeNostrEventRequest?>
|
||||
|
||||
@Query("SELECT COUNT(*) FROM SynchronizeNostrEventRequest WHERE purpose = :purpose AND status IN (:status)")
|
||||
fun observeSynchronizeNostrEventRequestByPurposeAndStatusCount(purpose: String, status: List<String>): Flow<Int>
|
||||
|
||||
@Upsert
|
||||
fun upsert(synchronizeNostrEventRequest: SynchronizeNostrEventRequest)
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ import kotlin.uuid.Uuid
|
||||
data class SynchronizeNostrEventRequest(
|
||||
@PrimaryKey
|
||||
val id: String = Uuid.generateV4().toHexDashString(),
|
||||
val purpose: String,
|
||||
val status: String = "pending",
|
||||
val relayURL: String,
|
||||
val isRecommendedRelay: Boolean = false,
|
||||
|
||||
@@ -297,6 +297,13 @@ class DatabaseNostrRepository(
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun observeSynchronizeNostrEventRequestByPurposeAndStatusCount(purpose: String): Flow<Int> {
|
||||
return database.synchronizeNostrEventRequestDao().observeSynchronizeNostrEventRequestByPurposeAndStatusCount(
|
||||
"feed",
|
||||
listOf("pending", "processing")
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun observeNostrFeed(): Flow<List<LocalNostrEvent>> {
|
||||
return database.nostrEventDao().observeNostrEvents(
|
||||
kinds = arrayOf(
|
||||
|
||||
@@ -65,6 +65,8 @@ interface NostrRepository {
|
||||
synchronizeNostrEventRequests: List<SynchronizeNostrEventRequest>,
|
||||
)
|
||||
|
||||
suspend fun observeSynchronizeNostrEventRequestByPurposeAndStatusCount(purpose: String): Flow<Int>
|
||||
|
||||
suspend fun observeNostrFeed(): Flow<List<LocalNostrEvent>>
|
||||
|
||||
suspend fun observeLocalNostrEventById(nostrEventId: String): Flow<LocalNostrEvent?>
|
||||
@@ -145,6 +147,10 @@ interface NostrRepository {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun observeSynchronizeNostrEventRequestByPurposeAndStatusCount(purpose: String): Flow<Int> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun observeNostrFeed(): Flow<List<LocalNostrEvent>> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
@@ -11,8 +11,10 @@ import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
@@ -23,10 +25,12 @@ import androidx.compose.material.icons.filled.Create
|
||||
import androidx.compose.material.icons.filled.Person
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||
import androidx.compose.material3.FilterChip
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LoadingIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.MediumTopAppBar
|
||||
import androidx.compose.material3.Scaffold
|
||||
@@ -45,7 +49,7 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
|
||||
@Composable
|
||||
fun FeedScreen(
|
||||
initialFeedListUIState: FeedListUIState,
|
||||
@@ -194,6 +198,14 @@ fun FeedScreen(
|
||||
}
|
||||
|
||||
}
|
||||
if (feedListViewModel.isSynchronizationPending.value) {
|
||||
item {
|
||||
Spacer(
|
||||
modifier = Modifier.height(50.dp)
|
||||
)
|
||||
LoadingIndicator()
|
||||
}
|
||||
}
|
||||
items(
|
||||
items = feedListUIState.localNostrEvents,
|
||||
key = { localNostrEvent -> localNostrEvent.nostrEvent.id }
|
||||
|
||||
@@ -6,6 +6,7 @@ import ac.aux.compose.managers.SeedManager
|
||||
import ac.aux.compose.nostr.Relays
|
||||
import ac.aux.compose.repository.NostrRepository
|
||||
import ac.aux.compose.ui.view.state.FeedListUIState
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
@@ -14,6 +15,7 @@ import androidx.lifecycle.ViewModelProvider
|
||||
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.nip10Notes.TextNoteEvent
|
||||
import com.vitorpamplona.quartz.nip18Reposts.RepostEvent
|
||||
@@ -28,9 +30,12 @@ class FeedListViewModel(
|
||||
initialFeedListUIState: FeedListUIState,
|
||||
val nostrRepository: NostrRepository
|
||||
): ViewModel() {
|
||||
val logger = Logger.withTag(TAG)
|
||||
var feedListUIState: FeedListUIState by mutableStateOf(initialFeedListUIState)
|
||||
private set
|
||||
|
||||
val isSynchronizationPending: MutableState<Boolean> = mutableStateOf(false)
|
||||
|
||||
fun retryLoad() {
|
||||
feedListUIState = FeedListUIState.Loading
|
||||
loadNostrFeed()
|
||||
@@ -42,6 +47,7 @@ class FeedListViewModel(
|
||||
nostrRepository.queueSynchronizeNostrEvent(
|
||||
Relays.eventPublishRelaySet.map { normalizedRelay ->
|
||||
SynchronizeNostrEventRequest(
|
||||
purpose = "feed",
|
||||
synchronizationFilters = arrayOf(
|
||||
SynchronizationFilter(
|
||||
kinds = arrayOf(
|
||||
@@ -61,6 +67,7 @@ class FeedListViewModel(
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
// Get contact list and sync feed...
|
||||
|
||||
val localProfile = nostrRepository.observeProfile(SeedManager.activePublicKey().toHexKey()).firstOrNull()
|
||||
@@ -73,6 +80,11 @@ class FeedListViewModel(
|
||||
localNostrEvents = localNostrEvents
|
||||
)
|
||||
}
|
||||
|
||||
nostrRepository.observeSynchronizeNostrEventRequestByPurposeAndStatusCount("feed").collect { count ->
|
||||
logger.d("Pending/Processing Synchronization Request: $count")
|
||||
isSynchronizationPending.value = count > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ class NostrEventDetailViewModel(
|
||||
nostrRepository.queueSynchronizeNostrEvent(
|
||||
Relays.eventPublishRelaySet.map { normalizedRelay ->
|
||||
SynchronizeNostrEventRequest(
|
||||
purpose = "detail",
|
||||
synchronizationFilters = arrayOf(
|
||||
SynchronizationFilter(
|
||||
kinds = arrayOf(
|
||||
|
||||
@@ -55,6 +55,7 @@ class UnqueuedProfileSynchronizationViewModel(
|
||||
nostrRepository.queueSynchronizeNostrEvent(
|
||||
Relays.eventPublishRelaySet.map { normalizedRelayUrl ->
|
||||
SynchronizeNostrEventRequest(
|
||||
purpose = "sign-in",
|
||||
synchronizationFilters = arrayOf(
|
||||
SynchronizationFilter(
|
||||
authors = arrayOf(profilePublicKey),
|
||||
|
||||
Reference in New Issue
Block a user