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 2cd3422a8..40d011339 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt @@ -2,6 +2,7 @@ package com.vitorpamplona.amethyst.model import android.util.Log import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.service.model.* import com.vitorpamplona.amethyst.service.nip19.Nip19 import com.vitorpamplona.amethyst.service.relays.Relay @@ -850,6 +851,8 @@ object LocalCache { } fun findUsersStartingWith(username: String): List { + checkNotInMainThread() + val key = decodePublicKeyAsHexOrNull(username) if (key != null && users[key] != null) { @@ -864,6 +867,8 @@ object LocalCache { } fun findNotesStartingWith(text: String): List { + checkNotInMainThread() + val key = try { Nip19.uriToRoute(text)?.hex ?: Hex.decode(text).toHexKey() } catch (e: Exception) { @@ -889,6 +894,8 @@ object LocalCache { } fun findChannelsStartingWith(text: String): List { + checkNotInMainThread() + val key = try { Nip19.uriToRoute(text)?.hex ?: Hex.decode(text).toHexKey() } catch (e: Exception) { @@ -917,6 +924,8 @@ object LocalCache { } fun pruneOldAndHiddenMessages(account: Account) { + checkNotInMainThread() + channels.forEach { it -> val toBeRemoved = it.value.pruneOldAndHiddenMessages(account) @@ -935,6 +944,8 @@ object LocalCache { } fun pruneHiddenMessages(account: Account) { + checkNotInMainThread() + val toBeRemoved = account.hiddenUsers.map { (users[it]?.notes ?: emptySet()) }.flatten() @@ -962,6 +973,8 @@ object LocalCache { } fun pruneContactLists(userAccount: Account) { + checkNotInMainThread() + var removingContactList = 0 users.values.forEach { if (it != userAccount.userProfile() && (it.liveSet == null || it.liveSet?.isInUse() == false) && it.latestContactList != null) { @@ -981,6 +994,8 @@ object LocalCache { } fun consume(event: Event, relay: Relay?) { + checkNotInMainThread() + if (!event.hasValidSignature()) return try { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/BlurHashImage.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/BlurHashImage.kt index 8e6ae470d..5f4765b5e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/BlurHashImage.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/BlurHashImage.kt @@ -20,6 +20,8 @@ class BlurHashFetcher( ) : Fetcher { override suspend fun fetch(): FetchResult { + checkNotInMainThread() + val encodedHash = data.toString().removePrefix("bluehash:") val hash = URLDecoder.decode(encodedHash, "utf-8") diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/MainThreadChecker.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/MainThreadChecker.kt new file mode 100644 index 000000000..a1903785b --- /dev/null +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/MainThreadChecker.kt @@ -0,0 +1,11 @@ +package com.vitorpamplona.amethyst.service + +import android.os.Looper + +fun checkNotInMainThread() { + if (isMainThread()) throw OnMainThreadException("It should not be in the MainThread") +} + +fun isMainThread() = Looper.myLooper() == Looper.getMainLooper() + +class OnMainThreadException(str: String) : RuntimeException(str) 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 c2463d51d..c154723a4 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 @@ -10,6 +10,7 @@ import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User +import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.service.model.BadgeAwardEvent import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent import com.vitorpamplona.amethyst.service.model.ChannelMetadataEvent @@ -79,6 +80,8 @@ open class CardFeedViewModel(val localFilter: FeedFilter) : ViewModel() { @Synchronized private fun refreshSuspended() { + checkNotInMainThread() + val notes = localFilter.feed() val thisAccount = (localFilter as? NotificationFeedFilter)?.account @@ -117,6 +120,8 @@ open class CardFeedViewModel(val localFilter: FeedFilter) : ViewModel() { } private fun convertToCard(notes: Collection): List { + checkNotInMainThread() + val reactionsPerEvent = mutableMapOf>() notes .filter { it.event is ReactionEvent } 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 9422e4c6f..48b8ea54f 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 @@ -9,6 +9,7 @@ import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User +import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.ui.components.BundledInsert import com.vitorpamplona.amethyst.ui.components.BundledUpdate import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter @@ -148,6 +149,8 @@ abstract class FeedViewModel(val localFilter: FeedFilter) : ViewModel() { } fun refreshSuspended() { + checkNotInMainThread() + val notes = newListFromDataSource() val oldNotesState = _feedContent.value 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 b05c3f0df..afc273e86 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 @@ -5,6 +5,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.ui.components.BundledUpdate import com.vitorpamplona.amethyst.ui.dal.FeedFilter import com.vitorpamplona.amethyst.ui.dal.UserProfileZapsFeedFilter @@ -30,6 +31,7 @@ open class LnZapFeedViewModel(val dataSource: FeedFilter>) : Vi } private fun refreshSuspended() { + checkNotInMainThread() val notes = dataSource.loadTop() val oldNotesState = _feedContent.value 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 8783471af..a82145806 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 @@ -7,6 +7,7 @@ import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.User +import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.ui.components.BundledUpdate import com.vitorpamplona.amethyst.ui.dal.FeedFilter import com.vitorpamplona.amethyst.ui.dal.HiddenAccountsFeedFilter @@ -58,6 +59,8 @@ open class UserFeedViewModel(val dataSource: FeedFilter) : ViewModel() { } private fun refreshSuspended() { + checkNotInMainThread() + val notes = dataSource.loadTop().toImmutableList() val oldNotesState = _feedContent.value