From b09577f81694ba0ff82cbe82108757dc497bc354 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 28 Feb 2023 15:24:23 -0500 Subject: [PATCH 01/10] Updating reports to the latest spec --- .../amethyst/model/LocalCache.kt | 4 +- .../com/vitorpamplona/amethyst/model/User.kt | 2 +- .../amethyst/service/model/ReportEvent.kt | 55 ++++++++++++++----- .../amethyst/ui/note/NoteCompose.kt | 21 +++++-- .../ui/screen/loggedIn/ProfileScreen.kt | 11 +++- 5 files changed, 67 insertions(+), 26 deletions(-) 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 7d040a53e..e9575eea8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt @@ -408,8 +408,8 @@ object LocalCache { // Already processed this event. if (note.event != null) return - val mentions = event.reportedAuthor.mapNotNull { checkGetOrCreateUser(it) } - val repliesTo = event.reportedPost.mapNotNull { checkGetOrCreateNote(it) } + val mentions = event.reportedAuthor.mapNotNull { checkGetOrCreateUser(it.key) } + val repliesTo = event.reportedPost.mapNotNull { checkGetOrCreateNote(it.key) } note.loadEvent(event, author, mentions, repliesTo) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt index 64139fdce..7d9c4925a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt @@ -289,7 +289,7 @@ class User(val pubkeyHex: String) { fun hasReport(loggedIn: User, type: ReportEvent.ReportType): Boolean { return reports[loggedIn]?.firstOrNull() { - it.event is ReportEvent && (it.event as ReportEvent).reportType.contains(type) + it.event is ReportEvent && (it.event as ReportEvent).reportedAuthor.any { it.reportType == type } } != null } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/model/ReportEvent.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/model/ReportEvent.kt index 1d962e421..cbee5cf0b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/model/ReportEvent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/model/ReportEvent.kt @@ -5,6 +5,8 @@ import nostr.postr.Utils import nostr.postr.events.Event import nostr.postr.toHex +data class ReportedKey(val key: String, val reportType: ReportEvent.ReportType) + // NIP 56 event. class ReportEvent ( id: ByteArray, @@ -15,14 +17,37 @@ class ReportEvent ( sig: ByteArray ): Event(id, pubKey, createdAt, kind, tags, content, sig) { - @Transient val reportType: List - @Transient val reportedPost: List - @Transient val reportedAuthor: List + @Transient val reportedPost: List + @Transient val reportedAuthor: List init { - reportType = tags.filter { it.firstOrNull() == "report" }.mapNotNull { it.getOrNull(1) }.map { ReportType.valueOf(it.toUpperCase()) } - reportedPost = tags.filter { it.firstOrNull() == "e" }.mapNotNull { it.getOrNull(1) } - reportedAuthor = tags.filter { it.firstOrNull() == "p" }.mapNotNull { it.getOrNull(1) } + // Works with old and new structures for report. + + var reportType = tags.filter { it.firstOrNull() == "report" }.mapNotNull { it.getOrNull(1) }.map { ReportType.valueOf(it.toUpperCase()) }.firstOrNull() + if (reportType == null) { + reportType = tags.mapNotNull { it.getOrNull(2) }.map { ReportType.valueOf(it.toUpperCase()) }.firstOrNull() + } + if (reportType == null) { + reportType = ReportType.SPAM + } + + reportedPost = tags + .filter { it.firstOrNull() == "e" && it.getOrNull(1) != null } + .map { + ReportedKey( + it[1], + it.getOrNull(2)?.toUpperCase()?.let { it1 -> ReportType.valueOf(it1) }?: reportType + ) + } + + reportedAuthor = tags + .filter { it.firstOrNull() == "p" && it.getOrNull(1) != null } + .map { + ReportedKey( + it[1], + it.getOrNull(2)?.toUpperCase()?.let { it1 -> ReportType.valueOf(it1) }?: reportType + ) + } } companion object { @@ -31,12 +56,11 @@ class ReportEvent ( fun create(reportedPost: Event, type: ReportType, privateKey: ByteArray, createdAt: Long = Date().time / 1000): ReportEvent { val content = "" - val reportTypeTag = listOf("report", type.name.toLowerCase()) - val reportPostTag = listOf("e", reportedPost.id.toHex()) - val reportAuthorTag = listOf("p", reportedPost.pubKey.toHex()) + val reportPostTag = listOf("e", reportedPost.id.toHex(), type.name.toLowerCase()) + val reportAuthorTag = listOf("p", reportedPost.pubKey.toHex(), type.name.toLowerCase()) val pubKey = Utils.pubkeyCreate(privateKey) - val tags:List> = listOf(reportTypeTag, reportPostTag, reportAuthorTag) + val tags:List> = listOf(reportPostTag, reportAuthorTag) val id = generateId(pubKey, createdAt, kind, tags, content) val sig = Utils.sign(id, privateKey) return ReportEvent(id, pubKey, createdAt, tags, content, sig) @@ -45,11 +69,10 @@ class ReportEvent ( fun create(reportedUser: String, type: ReportType, privateKey: ByteArray, createdAt: Long = Date().time / 1000): ReportEvent { val content = "" - val reportTypeTag = listOf("report", type.name.toLowerCase()) - val reportAuthorTag = listOf("p", reportedUser) + val reportAuthorTag = listOf("p", reportedUser, type.name.toLowerCase()) val pubKey = Utils.pubkeyCreate(privateKey) - val tags:List> = listOf(reportTypeTag, reportAuthorTag) + val tags:List> = listOf(reportAuthorTag) val id = generateId(pubKey, createdAt, kind, tags, content) val sig = Utils.sign(id, privateKey) return ReportEvent(id, pubKey, createdAt, tags, content, sig) @@ -57,9 +80,11 @@ class ReportEvent ( } enum class ReportType() { - EXPLICIT, + EXPLICIT, // Not used anymore. ILLEGAL, SPAM, - IMPERSONATION + IMPERSONATION, + NUDITY, + PROFANITY, } } \ No newline at end of file diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index 368c32ea4..037406030 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -315,22 +315,24 @@ fun NoteCompose( ) } } else if (noteEvent is ReportEvent) { - val reportType = noteEvent.reportType.map { - when (it) { + val reportType = (noteEvent.reportedPost + noteEvent.reportedAuthor).map { + when (it.reportType) { ReportEvent.ReportType.EXPLICIT -> "Explicit Content" + ReportEvent.ReportType.NUDITY -> "Nudity" + ReportEvent.ReportType.PROFANITY -> "Profanity / Hateful speech" ReportEvent.ReportType.SPAM -> "Spam" ReportEvent.ReportType.IMPERSONATION -> "Impersonation" ReportEvent.ReportType.ILLEGAL -> "Illegal Behavior" else -> "Unknown" } - }.joinToString(", ") + }.toSet().joinToString(", ") Text( text = reportType ) Divider( - modifier = Modifier.padding(top = 10.dp), + modifier = Modifier.padding(top = 40.dp), thickness = 0.25.dp ) } else { @@ -602,6 +604,13 @@ fun NoteDropDownMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Unit, }) { Text("Report Spam / Scam") } + DropdownMenuItem(onClick = { + accountViewModel.report(note, ReportEvent.ReportType.PROFANITY); + note.author?.let { accountViewModel.hide(it, context) } + onDismiss() + }) { + Text("Report Hateful Speech") + } DropdownMenuItem(onClick = { accountViewModel.report(note, ReportEvent.ReportType.IMPERSONATION); note.author?.let { accountViewModel.hide(it, context) } @@ -610,11 +619,11 @@ fun NoteDropDownMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Unit, Text("Report Impersonation") } DropdownMenuItem(onClick = { - accountViewModel.report(note, ReportEvent.ReportType.EXPLICIT); + accountViewModel.report(note, ReportEvent.ReportType.NUDITY); note.author?.let { accountViewModel.hide(it, context) } onDismiss() }) { - Text("Report Explicit Content") + Text("Report Nudity") } DropdownMenuItem(onClick = { accountViewModel.report(note, ReportEvent.ReportType.ILLEGAL); diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt index 1dcda0caa..31e4720bf 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt @@ -828,6 +828,13 @@ fun UserProfileDropDownMenu(user: User, popupExpanded: Boolean, onDismiss: () -> }) { Text("Report Spam / Scam") } + DropdownMenuItem(onClick = { + accountViewModel.report(user, ReportEvent.ReportType.PROFANITY); + user.let { accountViewModel.hide(it, context) } + onDismiss() + }) { + Text("Report Hateful speech") + } DropdownMenuItem(onClick = { accountViewModel.report(user, ReportEvent.ReportType.IMPERSONATION); user.let { accountViewModel.hide(it, context) } @@ -836,11 +843,11 @@ fun UserProfileDropDownMenu(user: User, popupExpanded: Boolean, onDismiss: () -> Text("Report Impersonation") } DropdownMenuItem(onClick = { - accountViewModel.report(user, ReportEvent.ReportType.EXPLICIT); + accountViewModel.report(user, ReportEvent.ReportType.NUDITY); user.let { accountViewModel.hide(it, context) } onDismiss() }) { - Text("Report Explicit Content") + Text("Report Nudity / Porn") } DropdownMenuItem(onClick = { accountViewModel.report(user, ReportEvent.ReportType.ILLEGAL); From 3f99b602a7545662f9b992f92f43ab1b6a0fb55e Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 28 Feb 2023 15:27:28 -0500 Subject: [PATCH 02/10] Fixing spacing of the multicard notification --- .../java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt index eb4e9d74c..ca121bb22 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt @@ -193,7 +193,7 @@ fun MultiSetCompose(multiSetCard: MultiSetCard, modifier: Modifier = Modifier, r Row(Modifier.fillMaxWidth()) { Box(modifier = Modifier - .width(55.dp) + .width(65.dp) .padding(0.dp)) { } From ddc1e9fd694994681efa40eb0b523894b4df31c0 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 28 Feb 2023 15:35:41 -0500 Subject: [PATCH 03/10] Reverts to show all replies in Notifications. --- .../amethyst/ui/dal/NotificationFeedFilter.kt | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/NotificationFeedFilter.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/NotificationFeedFilter.kt index 181b975d8..67567ed2e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/NotificationFeedFilter.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/NotificationFeedFilter.kt @@ -23,19 +23,6 @@ object NotificationFeedFilter: FeedFilter() { && it.event !is ChannelMetadataEvent && it.event !is LnZapRequestEvent } - .filter { - it.event !is TextNoteEvent - || - ( - it.event is TextNoteEvent - && - ( - it.replyTo?.lastOrNull()?.author == account.userProfile() - || - account.userProfile() in it.directlyCiteUsers() - ) - ) - } .filter { it.event !is ReactionEvent || From f68f32f6e559bb2afba503e3c321b3f9c650e922 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 28 Feb 2023 16:51:35 -0500 Subject: [PATCH 04/10] Decrypting notes since Notifications can also show Private Message Likes --- .../java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index 037406030..406c2d549 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -45,6 +45,7 @@ import com.vitorpamplona.amethyst.ui.components.TranslateableRichTextViewer import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.Following import kotlin.time.ExperimentalTime +import nostr.postr.events.PrivateDmEvent import nostr.postr.events.TextNoteEvent @OptIn(ExperimentalFoundationApi::class) @@ -336,7 +337,8 @@ fun NoteCompose( thickness = 0.25.dp ) } else { - val eventContent = noteEvent.content + val eventContent = accountViewModel.decrypt(note) + val canPreview = note.author == account.userProfile() || (note.author?.let { account.userProfile().isFollowing(it) } ?: true ) || !noteForReports.hasAnyReports() From a18479e721a3e4a0e0865d0493efdcd8c10528cc Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 28 Feb 2023 18:24:28 -0500 Subject: [PATCH 05/10] Reducing the need to start/stop home and chatroom lists to see if performance increases --- .../vitorpamplona/amethyst/ServiceManager.kt | 1 - .../amethyst/service/NostrDataSource.kt | 2 + .../amethyst/service/NostrGlobalDataSource.kt | 1 - .../ui/note/NIP05VerificationDisplay.kt | 3 +- .../ui/screen/loggedIn/ChatroomListScreen.kt | 46 ++----------------- .../amethyst/ui/screen/loggedIn/HomeScreen.kt | 21 --------- 6 files changed, 7 insertions(+), 67 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt b/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt index bbdac446c..a0cb5de2f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt @@ -33,7 +33,6 @@ object ServiceManager { NostrAccountDataSource.account = myAccount NostrHomeDataSource.account = myAccount NostrChatroomListDataSource.account = myAccount - NostrGlobalDataSource.account = myAccount // Notification Elements NostrAccountDataSource.start() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt index 8f8a66a07..10ac931bf 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt @@ -123,10 +123,12 @@ abstract class NostrDataSource(val debugName: String) { } open fun start() { + println("DataSource: ${this.javaClass.simpleName} Start") resetFilters() } open fun stop() { + println("DataSource: ${this.javaClass.simpleName} Stop") subscriptions.values.forEach { channel -> Client.close(channel.id) channel.typedFilters = null diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrGlobalDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrGlobalDataSource.kt index bd3ec6073..6dbd4cba7 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrGlobalDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrGlobalDataSource.kt @@ -8,7 +8,6 @@ import nostr.postr.JsonFilter import nostr.postr.events.TextNoteEvent object NostrGlobalDataSource: NostrDataSource("GlobalFeed") { - lateinit var account: Account fun createGlobalFilter() = TypedFilter( types = setOf(FeedType.GLOBAL), filter = JsonFilter( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt index b251f5015..f418786d5 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt @@ -94,7 +94,8 @@ fun ObserveDisplayNip05Status(baseUser: User) { user.nip05()?.let { nip05 -> if (nip05.split("@").size == 2) { - val nip05Verified by nip05VerificationAsAState(user.info!!, user.pubkeyHex) + + val nip05Verified by nip05VerificationAsAState(user.info!!, user.pubkeyHex) Row(verticalAlignment = Alignment.CenterVertically) { if (nip05.split("@")[0] != "_") Text( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt index 0501d9b36..e6e9bceaf 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt @@ -87,31 +87,11 @@ fun TabKnown(accountViewModel: AccountViewModel, navController: NavController) { ChatroomListKnownFeedFilter.account = account val feedViewModel: NostrChatroomListKnownFeedViewModel = viewModel() - LaunchedEffect(Unit) { + LaunchedEffect(accountViewModel) { NostrChatroomListDataSource.resetFilters() feedViewModel.invalidateData() } - val lifeCycleOwner = LocalLifecycleOwner.current - DisposableEffect(accountViewModel) { - val observer = LifecycleEventObserver { source, event -> - if (event == Lifecycle.Event.ON_RESUME) { - println("Chatroom List Start") - NostrChatroomListDataSource.start() - feedViewModel.invalidateData() - } - if (event == Lifecycle.Event.ON_PAUSE) { - println("Chatroom List Stop") - NostrChatroomListDataSource.stop() - } - } - - lifeCycleOwner.lifecycle.addObserver(observer) - onDispose { - lifeCycleOwner.lifecycle.removeObserver(observer) - } - } - Column(Modifier.fillMaxHeight()) { Column( modifier = Modifier.padding(vertical = 0.dp) @@ -129,29 +109,9 @@ fun TabNew(accountViewModel: AccountViewModel, navController: NavController) { ChatroomListNewFeedFilter.account = account val feedViewModel: NostrChatroomListNewFeedViewModel = viewModel() - LaunchedEffect(Unit) { + LaunchedEffect(accountViewModel) { NostrChatroomListDataSource.resetFilters() - feedViewModel.refresh() // refresh view - } - - val lifeCycleOwner = LocalLifecycleOwner.current - DisposableEffect(accountViewModel) { - val observer = LifecycleEventObserver { source, event -> - if (event == Lifecycle.Event.ON_RESUME) { - println("Chatroom List Start") - NostrChatroomListDataSource.start() - feedViewModel.invalidateData() - } - if (event == Lifecycle.Event.ON_PAUSE) { - println("Chatroom List Stop") - NostrChatroomListDataSource.stop() - } - } - - lifeCycleOwner.lifecycle.addObserver(observer) - onDispose { - lifeCycleOwner.lifecycle.removeObserver(observer) - } + feedViewModel.invalidateData() // refresh view } Column(Modifier.fillMaxHeight()) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt index 526b8dd93..10c4a6b4e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt @@ -56,27 +56,6 @@ fun HomeScreen(accountViewModel: AccountViewModel, navController: NavController) feedViewModelReplies.invalidateData() } - val lifeCycleOwner = LocalLifecycleOwner.current - DisposableEffect(accountViewModel) { - val observer = LifecycleEventObserver { source, event -> - if (event == Lifecycle.Event.ON_RESUME) { - println("Home Start") - NostrHomeDataSource.start() - feedViewModel.invalidateData() - feedViewModelReplies.invalidateData() - } - if (event == Lifecycle.Event.ON_PAUSE) { - println("Home Stop") - NostrHomeDataSource.stop() - } - } - - lifeCycleOwner.lifecycle.addObserver(observer) - onDispose { - lifeCycleOwner.lifecycle.removeObserver(observer) - } - } - Column(Modifier.fillMaxHeight()) { Column( modifier = Modifier.padding(vertical = 0.dp) From 95423bdd94338b705af315a3952a895bfab62eb8 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 28 Feb 2023 19:50:45 -0500 Subject: [PATCH 06/10] No need for account in search --- .../vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt index b294da5a7..443d78fe1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt @@ -82,7 +82,6 @@ fun SearchScreen(accountViewModel: AccountViewModel, navController: NavControlle val account = accountState?.account ?: return GlobalFeedFilter.account = account - NostrGlobalDataSource.account = account val feedViewModel: NostrGlobalFeedViewModel = viewModel() val lifeCycleOwner = LocalLifecycleOwner.current From df43e730ca9e9f219ec30b083991130f8ec77075 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 28 Feb 2023 19:52:16 -0500 Subject: [PATCH 07/10] Migrating the NostrDataSource to Atomic Boolean --- .../amethyst/service/NostrDataSource.kt | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt index 10ac931bf..b127ca061 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt @@ -17,11 +17,14 @@ import com.vitorpamplona.amethyst.service.relays.Subscription import com.vitorpamplona.amethyst.service.relays.hasValidSignature import java.util.Date import java.util.UUID +import java.util.concurrent.atomic.AtomicBoolean import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job +import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import nostr.postr.events.ContactListEvent import nostr.postr.events.DeletionEvent import nostr.postr.events.Event @@ -42,6 +45,7 @@ abstract class NostrDataSource(val debugName: String) { } } + private val clientListener = object : Client.Listener() { override fun onEvent(event: Event, subscriptionId: String, relay: Relay) { if (subscriptionId in subscriptions.keys) { @@ -91,7 +95,6 @@ abstract class NostrDataSource(val debugName: String) { } catch (e: Exception) { e.printStackTrace() } - } } @@ -146,17 +149,24 @@ abstract class NostrDataSource(val debugName: String) { subscriptions = subscriptions.minus(subscription.id) } - var handlerWaiting = false - @Synchronized - fun invalidateFilters() { - if (handlerWaiting) return + // Refreshes observers in batches. + var handlerWaiting = AtomicBoolean() + + fun invalidateFilters() { + if (handlerWaiting.getAndSet(true)) return + + println("DataSource: ${this.javaClass.simpleName} InvalidateFilters") - handlerWaiting = true val scope = CoroutineScope(Job() + Dispatchers.IO) scope.launch { - delay(200) - resetFiltersSuspend() - handlerWaiting = false + try { + delay(200) + resetFiltersSuspend() + } finally { + withContext(NonCancellable) { + handlerWaiting.set(false) + } + } } } From b6f5cc9ae50161227e4a8e4ac6734e70d38ec8af Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 28 Feb 2023 20:10:52 -0500 Subject: [PATCH 08/10] Activating the Atomic Boolean instead of Synchronized sections --- .../vitorpamplona/amethyst/NotificationCache.kt | 2 -- .../com/vitorpamplona/amethyst/model/Account.kt | 2 -- .../amethyst/model/AntiSpamFilter.kt | 2 -- .../com/vitorpamplona/amethyst/model/Channel.kt | 1 - .../vitorpamplona/amethyst/model/LocalCache.kt | 2 -- .../java/com/vitorpamplona/amethyst/model/Note.kt | 15 ++++++++++----- .../java/com/vitorpamplona/amethyst/model/User.kt | 2 -- .../amethyst/service/relays/RelayPool.kt | 1 - .../amethyst/ui/screen/CardFeedViewModel.kt | 2 -- .../amethyst/ui/screen/FeedViewModel.kt | 3 +-- .../amethyst/ui/screen/LnZapFeedViewModel.kt | 2 -- .../amethyst/ui/screen/RelayFeedView.kt | 2 -- .../amethyst/ui/screen/UserFeedViewModel.kt | 2 -- 13 files changed, 11 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/NotificationCache.kt b/app/src/main/java/com/vitorpamplona/amethyst/NotificationCache.kt index 1f29fd1bc..90018df67 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/NotificationCache.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/NotificationCache.kt @@ -44,12 +44,10 @@ class NotificationLiveData(val cache: NotificationCache): LiveData(AccountState(account)) { var handlerWaiting = AtomicBoolean() - @Synchronized fun invalidateData() { if (handlerWaiting.getAndSet(true)) return - handlerWaiting.set(true) val scope = CoroutineScope(Job() + Dispatchers.Default) scope.launch { try { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt index 32efc9df0..3fec4edf8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt @@ -67,12 +67,10 @@ class AntiSpamLiveData(val cache: AntiSpamFilter): LiveData(AntiS // Refreshes observers in batches. var handlerWaiting = AtomicBoolean() - @Synchronized fun invalidateData() { if (!hasActiveObservers()) return if (handlerWaiting.getAndSet(true)) return - handlerWaiting.set(true) val scope = CoroutineScope(Job() + Dispatchers.Main) scope.launch { try { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt index 648ed5b4a..a24445dcc 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt @@ -23,7 +23,6 @@ class Channel(val idHex: String) { return info.name ?: idDisplayNote() } - @Synchronized fun addNote(note: Note) { notes[note.idHex] = note } 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 e9575eea8..3372b2942 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt @@ -735,12 +735,10 @@ class LocalCacheLiveData(val cache: LocalCache): LiveData(Local // Refreshes observers in batches. var handlerWaiting = AtomicBoolean() - @Synchronized fun invalidateData() { if (!hasActiveObservers()) return if (handlerWaiting.getAndSet(true)) return - handlerWaiting.set(true) val scope = CoroutineScope(Job() + Dispatchers.Main) scope.launch { try { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt index 7c0d517bb..d464fe9e1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt @@ -18,8 +18,10 @@ import java.util.regex.Pattern import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job +import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import nostr.postr.events.Event val tagSearch = Pattern.compile("(?:\\s|\\A)\\#\\[([0-9]+)\\]") @@ -318,17 +320,20 @@ class NoteLiveData(val note: Note): LiveData(NoteState(note)) { // Refreshes observers in batches. var handlerWaiting = AtomicBoolean() - @Synchronized fun invalidateData() { if (!hasActiveObservers()) return if (handlerWaiting.getAndSet(true)) return - handlerWaiting.set(true) val scope = CoroutineScope(Job() + Dispatchers.Main) scope.launch { - delay(100) - refresh() - handlerWaiting.set(false) + try { + delay(100) + refresh() + } finally { + withContext(NonCancellable) { + handlerWaiting.set(false) + } + } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt index 7d9c4925a..0bdfc3356 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt @@ -379,11 +379,9 @@ class UserLiveData(val user: User): LiveData(UserState(user)) { // Refreshes observers in batches. var handlerWaiting = AtomicBoolean() - @Synchronized fun invalidateData() { if (handlerWaiting.getAndSet(true)) return - handlerWaiting.set(true) val scope = CoroutineScope(Job() + Dispatchers.Main) scope.launch { try { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayPool.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayPool.kt index 902034682..7b96ca7ea 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayPool.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayPool.kt @@ -94,7 +94,6 @@ object RelayPool: Relay.Listener { fun onSendResponse(eventId: String, success: Boolean, message: String, relay: Relay) } - @Synchronized override fun onEvent(relay: Relay, subscriptionId: String, event: Event) { listeners.forEach { it.onEvent(event, subscriptionId, relay) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt index ec40daec2..d1c1cfe91 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt @@ -129,11 +129,9 @@ open class CardFeedViewModel(val dataSource: FeedFilter): ViewModel() { var handlerWaiting = AtomicBoolean() - @Synchronized private fun invalidateData() { if (handlerWaiting.getAndSet(true)) return - handlerWaiting.set(true) val scope = CoroutineScope(Job() + Dispatchers.Default) scope.launch { try { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt index d7a0c9d9c..94c8cd364 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt @@ -87,11 +87,10 @@ abstract class FeedViewModel(val localFilter: FeedFilter): ViewModel() { } private var handlerWaiting = AtomicBoolean() - @Synchronized + fun invalidateData() { if (handlerWaiting.getAndSet(true)) return - handlerWaiting.set(true) val scope = CoroutineScope(Job() + Dispatchers.Default) scope.launch { try { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedViewModel.kt index c71ae13bc..b24c82828 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedViewModel.kt @@ -61,11 +61,9 @@ open class LnZapFeedViewModel(val dataSource: FeedFilter>): Vie var handlerWaiting = AtomicBoolean() - @Synchronized private fun invalidateData() { if (handlerWaiting.getAndSet(true)) return - handlerWaiting.set(true) val scope = CoroutineScope(Job() + Dispatchers.Default) scope.launch { try { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt index e66b49931..99e2d40e4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt @@ -83,11 +83,9 @@ class RelayFeedViewModel: ViewModel() { var handlerWaiting = AtomicBoolean() - @Synchronized private fun invalidateData() { if (handlerWaiting.getAndSet(true)) return - handlerWaiting.set(true) val scope = CoroutineScope(Job() + Dispatchers.Default) scope.launch { try { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt index d84e0ef2e..1f6acfccd 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt @@ -65,11 +65,9 @@ open class UserFeedViewModel(val dataSource: FeedFilter): ViewModel() { var handlerWaiting = AtomicBoolean() - @Synchronized private fun invalidateData() { if (handlerWaiting.getAndSet(true)) return - handlerWaiting.set(true) val scope = CoroutineScope(Job() + Dispatchers.Default) scope.launch { try { From 381db713ab3b6ea7cadbbd704c9646e4d78d9d24 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 28 Feb 2023 20:13:36 -0500 Subject: [PATCH 09/10] 0.20.4 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 3b53d3207..87b9ce6f1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,8 +11,8 @@ android { applicationId "com.vitorpamplona.amethyst" minSdk 26 targetSdk 33 - versionCode 77 - versionName "0.20.3" + versionCode 78 + versionName "0.20.4" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { From e0596dc3b958e93d7142558e2257fe5cbcccb824 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 28 Feb 2023 21:24:40 -0500 Subject: [PATCH 10/10] New Version for PlayStore --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 87b9ce6f1..7462fdc63 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,8 +11,8 @@ android { applicationId "com.vitorpamplona.amethyst" minSdk 26 targetSdk 33 - versionCode 78 - versionName "0.20.4" + versionCode 79 + versionName "0.20.5" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables {