Follow and unfollow logic
This commit is contained in:
@@ -2,6 +2,7 @@ package ac.cord.auxiliary.compose.database.dao
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.Connection
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Upsert
|
||||
@@ -23,4 +24,7 @@ interface ConnectionDao {
|
||||
@Upsert
|
||||
suspend fun upsert(connection: Connection)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(connection: Connection)
|
||||
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import androidx.room.Query
|
||||
import androidx.room.Upsert
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Kind
|
||||
import fr.acinq.bitcoin.PublicKey
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
@@ -43,6 +44,9 @@ interface NostrEventDao {
|
||||
@Query("SELECT * FROM NostrEvent WHERE id = :id")
|
||||
fun getNostrEventById(id: String): NostrEvent?
|
||||
|
||||
@Query("SELECT * FROM NostrEvent WHERE pubKey = :publicKey AND kind = :kind")
|
||||
fun getNostrEventByPublicKeyAndKind(publicKey: HexKey, kind: Kind): NostrEvent?
|
||||
|
||||
@Upsert
|
||||
suspend fun upsert(nostrEvent: NostrEvent)
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import ac.cord.auxiliary.compose.repository.NostrRepository
|
||||
import ac.cord.auxiliary.compose.repository.RelayRepository
|
||||
import co.touchlab.kermit.Logger
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Kind
|
||||
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
||||
import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent
|
||||
import com.vitorpamplona.quartz.nip02FollowList.RelaySet
|
||||
@@ -70,6 +71,10 @@ class DatabaseNostrRepository(
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun deleteConnection(connection: Connection) {
|
||||
database.connectionDao().delete(connection)
|
||||
}
|
||||
|
||||
override suspend fun observeUnsignedNostrEvents(publicKey: HexKey): Flow<UnsignedNostrEvent?> {
|
||||
return database.unsignedNostrEventDao().observeUnsignedNostrEvents(publicKey)
|
||||
}
|
||||
@@ -239,6 +244,7 @@ class DatabaseNostrRepository(
|
||||
}
|
||||
|
||||
override suspend fun saveUnsignedNostrEvent(unsignedNostrEvent: UnsignedNostrEvent): UnsignedNostrEvent? = try {
|
||||
// TODO: We can actually check the unsignedNostrEvent.pubKey for support... if it's writeable
|
||||
delay(2_100) // Just to make it look like we are doing serious work...
|
||||
unsignedNostrEvent.copy(
|
||||
id = database.unsignedNostrEventDao().upsert(unsignedNostrEvent)
|
||||
@@ -328,6 +334,13 @@ class DatabaseNostrRepository(
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getNostrEvent(publicKey: HexKey, kind: Kind): NostrEvent? {
|
||||
return database.nostrEventDao().getNostrEventByPublicKeyAndKind(
|
||||
publicKey = publicKey,
|
||||
kind = kind
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun observeNostrFeed(): Flow<List<LocalNostrEvent>> {
|
||||
return database.nostrEventDao().observeNostrEvents(
|
||||
kinds = arrayOf(
|
||||
|
||||
@@ -17,6 +17,7 @@ import ac.cord.auxiliary.compose.database.model.intermdiate.LocalProfileWithFoll
|
||||
import ac.cord.auxiliary.compose.database.model.typealiases.SynchronizationFilterArray
|
||||
import ac.cord.auxiliary.compose.database.model.types.SynchronizationFilter
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Kind
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface NostrRepository {
|
||||
@@ -24,6 +25,8 @@ interface NostrRepository {
|
||||
|
||||
suspend fun observeRelation(publicKey: HexKey, activePublicKey: HexKey): Flow<List<Connection>>
|
||||
|
||||
suspend fun deleteConnection(connection: Connection)
|
||||
|
||||
suspend fun observeUnsignedNostrEvents(publicKey: HexKey): Flow<UnsignedNostrEvent?>
|
||||
|
||||
suspend fun observePendingBroadcastNostrEventRequests(): Flow<List<LocalBroadcastNostrEventRequest>>
|
||||
@@ -76,6 +79,9 @@ interface NostrRepository {
|
||||
|
||||
suspend fun observeSynchronizeNostrEventRequestByPurposeAndStatusCount(purpose: String): Flow<Int>
|
||||
|
||||
|
||||
suspend fun getNostrEvent(publicKey: HexKey, kind: Kind): NostrEvent?
|
||||
|
||||
suspend fun observeNostrFeed(): Flow<List<LocalNostrEvent>>
|
||||
|
||||
suspend fun observeNostrFeed(synchronizationFilter: SynchronizationFilter): Flow<List<LocalNostrEvent>>
|
||||
@@ -109,6 +115,10 @@ interface NostrRepository {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun deleteConnection(connection: Connection) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun observeUnsignedNostrEvents(publicKey: HexKey): Flow<UnsignedNostrEvent?> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
@@ -186,6 +196,13 @@ interface NostrRepository {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun getNostrEvent(
|
||||
publicKey: HexKey,
|
||||
kind: Kind
|
||||
): NostrEvent? {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun observeNostrFeed(): Flow<List<LocalNostrEvent>> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ fun MetadataEventDetail(
|
||||
}
|
||||
) {
|
||||
Text(
|
||||
text = if (metadataEventDetailUIState.followingActiveUserConnection == null) {
|
||||
text = if (metadataEventDetailUIState.followingActiveUserConnection != null) {
|
||||
"follow back"
|
||||
} else {
|
||||
"follow"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package ac.cord.auxiliary.compose.ui.view.model
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.Connection
|
||||
import ac.cord.auxiliary.compose.database.model.UnsignedNostrEvent
|
||||
import ac.cord.auxiliary.compose.database.model.types.SynchronizationFilter
|
||||
import ac.cord.auxiliary.compose.managers.SeedManager
|
||||
import ac.cord.auxiliary.compose.repository.NostrRepository
|
||||
@@ -17,12 +18,17 @@ import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import co.touchlab.kermit.Logger
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArray
|
||||
import com.vitorpamplona.quartz.nip01Core.core.toHexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.people.isTaggedUser
|
||||
import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent
|
||||
import com.vitorpamplona.quartz.nip02FollowList.RelaySet
|
||||
import com.vitorpamplona.quartz.nip02FollowList.tags.ContactTag
|
||||
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
|
||||
import com.vitorpamplona.quartz.nip18Reposts.RepostEvent
|
||||
import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent
|
||||
import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent
|
||||
import com.vitorpamplona.quartz.nip31Alts.AltTag
|
||||
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.BookmarkListEvent
|
||||
import com.vitorpamplona.quartz.nip51Lists.relayLists.RelayFeedsListEvent
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportEvent
|
||||
@@ -63,11 +69,17 @@ class MetadataEventDetailViewModel(
|
||||
activePublicKey = activePublicKey
|
||||
).collect { relations ->
|
||||
logger.d("We found relations: $relations")
|
||||
|
||||
metadataEventDetailUIState = MetadataEventDetailUIState.Loaded(
|
||||
isActiveUser = activePublicKey == publicKey,
|
||||
followingActiveUserConnection = relations.find { connection -> connection.sourcePublicKey == publicKey && connection.destinationPublicKey == activePublicKey },
|
||||
followedByActiveUserConnection = relations.find { connection -> connection.sourcePublicKey == activePublicKey && connection.destinationPublicKey == publicKey }
|
||||
)
|
||||
|
||||
if (isActionPending.value) {
|
||||
// This means this new relation was caused by user action...
|
||||
isActionPending.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,7 +222,45 @@ class MetadataEventDetailViewModel(
|
||||
|
||||
val activePublicKey = SeedManager.activePublicKey().toHexKey()
|
||||
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val contactListEvent = nostrRepository.getNostrEvent(
|
||||
publicKey = activePublicKey,
|
||||
kind = ContactListEvent.KIND
|
||||
)
|
||||
|
||||
|
||||
val followUsers: TagArray = if (contactListEvent != null) {
|
||||
if (contactListEvent.tags.isTaggedUser(publicKey)) {
|
||||
// User already being followed
|
||||
logger.d("User is already following $publicKey")
|
||||
return@launch
|
||||
}
|
||||
|
||||
contactListEvent.tags.plus(
|
||||
ContactTag(
|
||||
pubKey = publicKey
|
||||
).toTagArray()
|
||||
)
|
||||
} else {
|
||||
arrayOf(
|
||||
ContactTag(activePublicKey, null, null).toTagArray(),
|
||||
ContactTag(publicKey, null, null).toTagArray(),
|
||||
)
|
||||
}
|
||||
val contactListTagList = listOf(AltTag.assemble(ContactListEvent.ALT)) +
|
||||
followUsers.map { it }
|
||||
|
||||
nostrRepository.saveUnsignedNostrEvent(
|
||||
UnsignedNostrEvent(
|
||||
pubKey = activePublicKey,
|
||||
kind = ContactListEvent.KIND,
|
||||
tags = contactListTagList.toTypedArray(),
|
||||
content = RelaySet.assemble(
|
||||
emptyMap()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun unfollow(connection: Connection) {
|
||||
@@ -218,6 +268,34 @@ class MetadataEventDetailViewModel(
|
||||
|
||||
val activePublicKey = SeedManager.activePublicKey().toHexKey()
|
||||
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val contactListEvent = nostrRepository.getNostrEvent(
|
||||
publicKey = activePublicKey,
|
||||
kind = ContactListEvent.KIND
|
||||
)
|
||||
|
||||
|
||||
if (contactListEvent != null) {
|
||||
if (!contactListEvent.tags.isTaggedUser(publicKey)) {
|
||||
logger.d("User is not being followed so no need to unfollow: $publicKey")
|
||||
} else {
|
||||
nostrRepository.saveUnsignedNostrEvent(
|
||||
UnsignedNostrEvent(
|
||||
pubKey = activePublicKey,
|
||||
kind = ContactListEvent.KIND,
|
||||
tags = contactListEvent.tags.filter { it.size > 1 && it[1] != publicKey }.toTypedArray(),
|
||||
content = RelaySet.assemble(
|
||||
emptyMap()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
nostrRepository.deleteConnection(
|
||||
connection
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
companion object {
|
||||
const val TAG = "MetadataEventDetailViewModel"
|
||||
|
||||
Reference in New Issue
Block a user