feat: screener for message requests #24
@@ -85,6 +85,8 @@ fun ProfileScreen(pubkey: String, screening: Boolean = false) {
|
|||||||
|
|
||||||
var addressVerified by remember { mutableStateOf(false) }
|
var addressVerified by remember { mutableStateOf(false) }
|
||||||
var lastActivity by remember { mutableStateOf<Timestamp?>(null) }
|
var lastActivity by remember { mutableStateOf<Timestamp?>(null) }
|
||||||
|
var isContact by remember { mutableStateOf(false) }
|
||||||
|
var mutualContacts by remember { mutableStateOf<Set<PublicKey>>(emptySet()) }
|
||||||
|
|
||||||
LaunchedEffect(screening) {
|
LaunchedEffect(screening) {
|
||||||
if (screening) {
|
if (screening) {
|
||||||
@@ -95,6 +97,10 @@ fun ProfileScreen(pubkey: String, screening: Boolean = false) {
|
|||||||
}
|
}
|
||||||
// Get the last activity
|
// Get the last activity
|
||||||
viewModel.verifyActivity(pubkey)?.let { lastActivity = it }
|
viewModel.verifyActivity(pubkey)?.let { lastActivity = it }
|
||||||
|
// Check contact
|
||||||
|
viewModel.verifyContact(pubkey).let { isContact = it }
|
||||||
|
// Get mutual contacts
|
||||||
|
viewModel.mutualContacts(pubkey).let { mutualContacts = it }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -296,7 +296,11 @@ class Nostr {
|
|||||||
|
|
||||||
if (event.kind().asStd()?.equals(KindStandard.CONTACT_LIST) == true) {
|
if (event.kind().asStd()?.equals(KindStandard.CONTACT_LIST) == true) {
|
||||||
if (isSignedByUser(event = event)) {
|
if (isSignedByUser(event = event)) {
|
||||||
onContactListUpdate(event.tags().publicKeys())
|
val pubkeys = event.tags().publicKeys();
|
||||||
|
// Get mutual contacts
|
||||||
|
getMutualContacts(pubkeys)
|
||||||
|
// Emit contact list update
|
||||||
|
onContactListUpdate(pubkeys)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,6 +317,7 @@ class Nostr {
|
|||||||
// Logic to notify UI after processing
|
// Logic to notify UI after processing
|
||||||
// Cancel previous tracker if it exists
|
// Cancel previous tracker if it exists
|
||||||
eoseTrackerJob?.cancel()
|
eoseTrackerJob?.cancel()
|
||||||
|
|
||||||
// Start a new tracker
|
// Start a new tracker
|
||||||
eoseTrackerJob = launch {
|
eoseTrackerJob = launch {
|
||||||
delay(10000.milliseconds) // Wait for 10 seconds
|
delay(10000.milliseconds) // Wait for 10 seconds
|
||||||
@@ -360,6 +365,27 @@ class Nostr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun getMutualContacts(pubkeys: List<PublicKey>) {
|
||||||
|
try {
|
||||||
|
val kind = Kind.fromStd(KindStandard.CONTACT_LIST);
|
||||||
|
val filter = Filter().kind(kind).authors(pubkeys).limit(200u)
|
||||||
|
val opts = SubscribeAutoCloseOptions().exitPolicy(ReqExitPolicy.ExitOnEose)
|
||||||
|
|
||||||
|
val target = mutableMapOf<RelayUrl, List<Filter>>()
|
||||||
|
NostrManager.BOOTSTRAP_RELAYS.forEach { relay ->
|
||||||
|
target[RelayUrl.parse(relay)] = listOf(filter)
|
||||||
|
}
|
||||||
|
|
||||||
|
client?.subscribe(
|
||||||
|
target = ReqTarget.manual(target),
|
||||||
|
id = "mutual-contacts",
|
||||||
|
closeOn = opts,
|
||||||
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw IllegalStateException("Failed to fetch mutual contacts: ${e.message}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun getCachedRumor(giftId: EventId): UnsignedEvent? {
|
private suspend fun getCachedRumor(giftId: EventId): UnsignedEvent? {
|
||||||
try {
|
try {
|
||||||
val filter = Filter().identifier(giftId.toHex())
|
val filter = Filter().identifier(giftId.toHex())
|
||||||
@@ -977,4 +1003,39 @@ class Nostr {
|
|||||||
throw IllegalStateException("Failed to get latest activity: ${e.message}", e)
|
throw IllegalStateException("Failed to get latest activity: ${e.message}", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun verifyContact(pubkey: PublicKey): Boolean {
|
||||||
|
try {
|
||||||
|
val kind = Kind.fromStd(KindStandard.CONTACT_LIST)
|
||||||
|
val filter = Filter().kind(kind).author(pubkey).limit(1u)
|
||||||
|
|
||||||
|
val events = client?.database()?.query(filter)
|
||||||
|
val pubkeys = events?.first()?.tags()?.publicKeys() ?: listOf()
|
||||||
|
|
||||||
|
return pubkeys.contains(pubkey)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw IllegalStateException("Failed to get mutual contacts: ${e.message}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun mutualContacts(pubkey: PublicKey): Set<PublicKey> {
|
||||||
|
try {
|
||||||
|
val currentUser =
|
||||||
|
signer.getPublicKeyAsync() ?: throw IllegalStateException("User not signed in")
|
||||||
|
|
||||||
|
val kind = Kind.fromStd(KindStandard.CONTACT_LIST)
|
||||||
|
val filter = Filter().kind(kind).pubkey(pubkey).limit(1u)
|
||||||
|
|
||||||
|
val events = client?.database()?.query(filter)
|
||||||
|
val contacts = mutableSetOf<PublicKey>()
|
||||||
|
|
||||||
|
events?.toVec()?.filter { it.author() != currentUser }?.forEach { event ->
|
||||||
|
contacts.add(event.author())
|
||||||
|
}
|
||||||
|
|
||||||
|
return contacts.toSet()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw IllegalStateException("Failed to get mutual contacts: ${e.message}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -839,6 +839,24 @@ class NostrViewModel(
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun verifyContact(pubkey: PublicKey): Boolean {
|
||||||
|
return try {
|
||||||
|
nostr.verifyContact(pubkey)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
showError("Error: ${e.message}")
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun mutualContacts(pubkey: PublicKey): Set<PublicKey> {
|
||||||
|
return try {
|
||||||
|
nostr.mutualContacts(pubkey)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
showError("Error: ${e.message}")
|
||||||
|
setOf()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun PublicKey.short(): String {
|
fun PublicKey.short(): String {
|
||||||
|
|||||||
Reference in New Issue
Block a user