diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index fca97daae..11f4e730c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -83,7 +83,7 @@ object LocalPreferences { private var _currentAccount: String? = null - private fun currentAccount(): String? { + fun currentAccount(): String? { if (_currentAccount == null) { _currentAccount = encryptedPreferences().getString(PrefKeys.CURRENT_ACCOUNT, null) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt index 294676ca6..cbe809125 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt @@ -3,14 +3,17 @@ package com.vitorpamplona.amethyst.model import android.util.Log import androidx.compose.runtime.Stable import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.service.relays.Relay import com.vitorpamplona.amethyst.ui.components.BundledInsert +import com.vitorpamplona.amethyst.ui.dal.BookmarkPrivateFeedFilter import com.vitorpamplona.quartz.encoders.ATag import com.vitorpamplona.quartz.encoders.Hex import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.encoders.HexValidator import com.vitorpamplona.quartz.encoders.Nip19 +import com.vitorpamplona.quartz.encoders.bechToBytes import com.vitorpamplona.quartz.encoders.decodePublicKeyAsHexOrNull import com.vitorpamplona.quartz.encoders.toHexKey import com.vitorpamplona.quartz.events.* @@ -199,6 +202,14 @@ object LocalCache { val user = getOrCreateUser(event.pubKey) if (user.latestBookmarkList == null || event.createdAt > user.latestBookmarkList!!.createdAt) { if (event.dTag() == "bookmark") { + val loggedInUser = LocalPreferences.currentAccount() + val hexKey = loggedInUser?.bechToBytes() + if (hexKey != null) { + val pubKey = Hex.encode(hexKey) + if (pubKey == event.pubKey) { + BookmarkPrivateFeedFilter.content = "" + } + } user.updateBookmark(event) } // Log.d("MT", "New User Metadata ${oldUser.pubkeyDisplayHex} ${oldUser.toBestDisplayName()}") diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/IntentUtils.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/IntentUtils.kt index 383eb3eda..4039acd05 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/IntentUtils.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/IntentUtils.kt @@ -6,4 +6,5 @@ import androidx.activity.result.ActivityResultLauncher object IntentUtils { lateinit var activityResultLauncher: ActivityResultLauncher lateinit var authActivityResultLauncher: ActivityResultLauncher + lateinit var decryptActivityResultLauncher: ActivityResultLauncher } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt index 25e683cf6..0aa63f34a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt @@ -32,6 +32,7 @@ import com.vitorpamplona.amethyst.service.notifications.RegisterAccounts import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.ui.components.DefaultMutedSetting import com.vitorpamplona.amethyst.ui.components.keepPlayingMutex +import com.vitorpamplona.amethyst.ui.dal.BookmarkPrivateFeedFilter import com.vitorpamplona.amethyst.ui.navigation.Route import com.vitorpamplona.amethyst.ui.navigation.debugState import com.vitorpamplona.amethyst.ui.note.Nip47 @@ -110,6 +111,26 @@ class MainActivity : AppCompatActivity() { ServiceManager.shouldPauseService = true } + IntentUtils.decryptActivityResultLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { + if (it.resultCode != Activity.RESULT_OK) { + GlobalScope.launch(Dispatchers.Main) { + Toast.makeText( + Amethyst.instance, + "Sign request rejected", + Toast.LENGTH_SHORT + ).show() + } + BookmarkPrivateFeedFilter.isActivityRunning = false + return@registerForActivityResult + } + + val event = it.data?.getStringExtra("signature") ?: "" + BookmarkPrivateFeedFilter.content = event + BookmarkPrivateFeedFilter.isActivityRunning = false + } + super.onCreate(savedInstanceState) LocalPreferences.migrateSingleUserPrefs() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/BookmarkPrivateFeedFilter.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/BookmarkPrivateFeedFilter.kt index 1c870d18b..bee80ce76 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/BookmarkPrivateFeedFilter.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/BookmarkPrivateFeedFilter.kt @@ -3,27 +3,57 @@ package com.vitorpamplona.amethyst.ui.dal import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.service.IntentUtils +import com.vitorpamplona.amethyst.ui.actions.SignerType +import com.vitorpamplona.amethyst.ui.actions.openAmber +import com.vitorpamplona.quartz.encoders.toHexKey object BookmarkPrivateFeedFilter : FeedFilter() { lateinit var account: Account + var content: String = "" + var isActivityRunning: Boolean = false override fun feedKey(): String { return account.userProfile().latestBookmarkList?.id ?: "" } override fun feed(): List { - val privKey = account.keyPair.privKey ?: return emptyList() - val bookmarks = account.userProfile().latestBookmarkList - val notes = bookmarks?.privateTaggedEvents(privKey) - ?.mapNotNull { LocalCache.checkGetOrCreateNote(it) } ?: emptyList() + if (account.loginWithAmber) { + if (content.isBlank()) { + isActivityRunning = true + openAmber( + bookmarks?.content ?: "", + SignerType.NIP04_DECRYPT, + IntentUtils.decryptActivityResultLauncher, + account.keyPair.pubKey.toHexKey() + ) + while (isActivityRunning) { + Thread.sleep(250) + } + } - val addresses = bookmarks?.privateTaggedAddresses(privKey) - ?.map { LocalCache.getOrCreateAddressableNote(it) } ?: emptyList() + val notes = bookmarks?.privateTaggedEvents(content) + ?.mapNotNull { LocalCache.checkGetOrCreateNote(it) } ?: emptyList() + val addresses = bookmarks?.privateTaggedAddresses(content) + ?.map { LocalCache.getOrCreateAddressableNote(it) } ?: emptyList() - return notes.plus(addresses).toSet() - .sortedWith(compareBy({ it.createdAt() }, { it.idHex })) - .reversed() + return notes.plus(addresses).toSet() + .sortedWith(compareBy({ it.createdAt() }, { it.idHex })) + .reversed() + } else { + val privKey = account.keyPair.privKey ?: return emptyList() + + val notes = bookmarks?.privateTaggedEvents(privKey) + ?.mapNotNull { LocalCache.checkGetOrCreateNote(it) } ?: emptyList() + + val addresses = bookmarks?.privateTaggedAddresses(privKey) + ?.map { LocalCache.getOrCreateAddressableNote(it) } ?: emptyList() + + return notes.plus(addresses).toSet() + .sortedWith(compareBy({ it.createdAt() }, { it.idHex })) + .reversed() + } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/BookmarkListScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/BookmarkListScreen.kt index a8040c539..97890ab3f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/BookmarkListScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/BookmarkListScreen.kt @@ -11,6 +11,7 @@ import androidx.compose.material.Tab import androidx.compose.material.TabRow import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState @@ -91,5 +92,11 @@ fun BookmarkListScreen(accountViewModel: AccountViewModel, nav: (String) -> Unit } } } + + DisposableEffect(Unit) { + onDispose { + BookmarkPrivateFeedFilter.content = "" + } + } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/GeneralListEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/GeneralListEvent.kt index 6a23374b9..b6df2d35e 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/GeneralListEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/GeneralListEvent.kt @@ -52,6 +52,20 @@ abstract class GeneralListEvent( return privateTagsCache } + fun privateTags(content: String): List>? { + if (privateTagsCache != null) { + return privateTagsCache + } + + privateTagsCache = try { + content.let { mapper.readValue>>(it) } + } catch (e: Throwable) { + Log.w("GeneralList", "Error parsing the JSON ${e.message}") + null + } + return privateTagsCache + } + fun privateTagsOrEmpty(privKey: ByteArray): List> { return privateTags(privKey) ?: emptyList() } @@ -61,6 +75,8 @@ abstract class GeneralListEvent( fun privateHashtags(privKey: ByteArray) = privateTags(privKey)?.filter { it.size > 1 && it[0] == "t" }?.map { it[1] } fun privateGeohashes(privKey: ByteArray) = privateTags(privKey)?.filter { it.size > 1 && it[0] == "g" }?.map { it[1] } fun privateTaggedEvents(privKey: ByteArray) = privateTags(privKey)?.filter { it.size > 1 && it[0] == "e" }?.map { it[1] } + fun privateTaggedEvents(content: String) = privateTags(content)?.filter { it.size > 1 && it[0] == "e" }?.map { it[1] } + fun privateTaggedAddresses(privKey: ByteArray) = privateTags(privKey)?.filter { it.firstOrNull() == "a" }?.mapNotNull { val aTagValue = it.getOrNull(1) val relay = it.getOrNull(2) @@ -68,6 +84,13 @@ abstract class GeneralListEvent( if (aTagValue != null) ATag.parse(aTagValue, relay) else null } + fun privateTaggedAddresses(content: String) = privateTags(content)?.filter { it.firstOrNull() == "a" }?.mapNotNull { + val aTagValue = it.getOrNull(1) + val relay = it.getOrNull(2) + + if (aTagValue != null) ATag.parse(aTagValue, relay) else null + } + companion object { fun createPrivateTags( privEvents: List? = null,