diff --git a/app/build.gradle b/app/build.gradle index 3b53d3207..7462fdc63 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 79 + versionName "0.20.5" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { 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 7d040a53e..3372b2942 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) @@ -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 64139fdce..0bdfc3356 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 } @@ -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/NostrDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt index 8f8a66a07..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() } - } } @@ -123,10 +126,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 @@ -144,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) + } + } } } 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/service/model/ReportEvent.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/model/ReportEvent.kt index 3d5f5a720..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,11 +80,11 @@ class ReportEvent ( } enum class ReportType() { - EXPLICIT, + EXPLICIT, // Not used anymore. ILLEGAL, SPAM, IMPERSONATION, NUDITY, - PROFANITY + PROFANITY, } } \ No newline at end of file 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/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 || 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)) { } 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/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index a86e9dfe7..161149203 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 @@ -46,6 +46,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) @@ -319,25 +320,26 @@ fun NoteCompose( val reportType = noteEvent.reportType.map { when (it) { ReportEvent.ReportType.EXPLICIT -> stringResource(R.string.explicit_content) + ReportEvent.ReportType.NUDITY -> stringResource(R.string.nudity) + ReportEvent.ReportType.PROFANITY -> stringResource(R.string.profanity_hateful_speech) ReportEvent.ReportType.SPAM -> stringResource(R.string.spam) ReportEvent.ReportType.IMPERSONATION -> stringResource(R.string.impersonation) ReportEvent.ReportType.ILLEGAL -> stringResource(R.string.illegal_behavior) - ReportEvent.ReportType.NUDITY -> stringResource(R.string.nudity) - ReportEvent.ReportType.PROFANITY -> stringResource(R.string.profanity_hateful_speech) else -> stringResource(R.string.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 { - 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() @@ -605,6 +607,13 @@ fun NoteDropDownMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Unit, }) { Text(stringResource(R.string.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) } @@ -613,11 +622,11 @@ fun NoteDropDownMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Unit, Text(stringResource(R.string.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(stringResource(R.string.report_explicit_content)) + Text(stringResource(R.string.report_nudity_porn)) } DropdownMenuItem(onClick = { accountViewModel.report(note, ReportEvent.ReportType.ILLEGAL); 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 { 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 a61140141..4572dabd9 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 @@ -89,31 +89,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) @@ -131,29 +111,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 36fbc20bd..ba0586e0b 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 @@ -58,27 +58,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) 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 31d5b4a3b..179d99abf 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 @@ -836,7 +836,6 @@ fun UserProfileDropDownMenu(user: User, popupExpanded: Boolean, onDismiss: () -> }) { Text(stringResource(R.string.report_hateful_speech)) } - DropdownMenuItem(onClick = { accountViewModel.report(user, ReportEvent.ReportType.IMPERSONATION); user.let { accountViewModel.hide(it, context) } 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 d40d9a9e4..b90293bf6 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 @@ -83,7 +83,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