diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index b8aba0e2d..8c539ab7f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -61,6 +61,7 @@ private object PrefKeys { const val USE_PROXY = "use_proxy" const val PROXY_PORT = "proxy_port" const val SHOW_SENSITIVE_CONTENT = "show_sensitive_content" + const val OPT_OUT_FILTERS = "opt_out_filters" val LAST_READ: (String) -> String = { route -> "last_read_route_$route" } } @@ -217,6 +218,7 @@ object LocalPreferences { putBoolean(PrefKeys.HIDE_BLOCK_ALERT_DIALOG, account.hideBlockAlertDialog) putBoolean(PrefKeys.USE_PROXY, account.proxy != null) putInt(PrefKeys.PROXY_PORT, account.proxyPort) + putBoolean(PrefKeys.OPT_OUT_FILTERS, account.optOutFromFilters) if (account.showSensitiveContent == null) { remove(PrefKeys.SHOW_SENSITIVE_CONTENT) @@ -306,6 +308,7 @@ object LocalPreferences { } else { null } + val optOutFromFilters = getBoolean(PrefKeys.OPT_OUT_FILTERS, false) val a = Account( Persona(privKey = privKey?.hexToByteArray(), pubKey = pubKey.hexToByteArray()), @@ -327,7 +330,8 @@ object LocalPreferences { latestContactList, proxy, proxyPort, - showSensitiveContent + showSensitiveContent, + optOutFromFilters ) return a diff --git a/app/src/main/java/com/vitorpamplona/amethyst/OptOutFromFilters.kt b/app/src/main/java/com/vitorpamplona/amethyst/OptOutFromFilters.kt new file mode 100644 index 000000000..736be2916 --- /dev/null +++ b/app/src/main/java/com/vitorpamplona/amethyst/OptOutFromFilters.kt @@ -0,0 +1,9 @@ +package com.vitorpamplona.amethyst + +object OptOutFromFilters { + var optOutFromFilters: Boolean = false + + fun start(optOut: Boolean) { + optOutFromFilters = optOut + } +} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt b/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt index 9acaa0d60..a85741a2e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt @@ -36,6 +36,7 @@ object ServiceManager { // Resets Proxy Use HttpClient.start(account) + OptOutFromFilters.start(account?.optOutFromFilters ?: false) Coil.setImageLoader { ImageLoader.Builder(context).components { if (Build.VERSION.SDK_INT >= 28) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index d90f42cc4..3205b8009 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -6,6 +6,7 @@ import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable import androidx.core.os.ConfigurationCompat import androidx.lifecycle.LiveData +import com.vitorpamplona.amethyst.OptOutFromFilters import com.vitorpamplona.amethyst.service.FileHeader import com.vitorpamplona.amethyst.service.NostrLnZapPaymentResponseDataSource import com.vitorpamplona.amethyst.service.model.* @@ -66,7 +67,8 @@ class Account( var backupContactList: ContactListEvent? = null, var proxy: Proxy?, var proxyPort: Int, - var showSensitiveContent: Boolean? = null + var showSensitiveContent: Boolean? = null, + var optOutFromFilters: Boolean = false ) { var transientHiddenUsers: Set = setOf() @@ -77,6 +79,13 @@ class Account( var userProfileCache: User? = null + fun updateOptOutFromFilters(value: Boolean) { + optOutFromFilters = value + OptOutFromFilters.start(optOutFromFilters) + live.invalidateData() + saveable.invalidateData() + } + fun userProfile(): User { return userProfileCache ?: run { val myUser: User = LocalCache.getOrCreateUser(loggedIn.pubKey.toHexKey()) @@ -1057,12 +1066,19 @@ class Account( } fun isAcceptable(user: User): Boolean { + if (optOutFromFilters) { + return !isHidden(user) && // if user hasn't hided this author + user.reportsBy(userProfile()).isEmpty() // if user has not reported this post + } return !isHidden(user) && // if user hasn't hided this author user.reportsBy(userProfile()).isEmpty() && // if user has not reported this post user.countReportAuthorsBy(followingKeySet()) < 5 } fun isAcceptableDirect(note: Note): Boolean { + if (optOutFromFilters) { + return note.reportsBy(userProfile()).isEmpty() + } return note.reportsBy(userProfile()).isEmpty() && // if user has not reported this post note.countReportAuthorsBy(followingKeySet()) < 5 // if it has 5 reports by reliable users } 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 32d258fb0..4686bcfb5 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt @@ -3,6 +3,7 @@ package com.vitorpamplona.amethyst.model import android.util.Log import android.util.LruCache import androidx.lifecycle.LiveData +import com.vitorpamplona.amethyst.OptOutFromFilters import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.service.model.Event import com.vitorpamplona.amethyst.service.nip19.Nip19 @@ -20,6 +21,8 @@ class AntiSpamFilter { fun isSpam(event: Event, relay: Relay?): Boolean { checkNotInMainThread() + if (OptOutFromFilters.optOutFromFilters) return false + val idHex = event.id // if short message, ok diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt index 58c5d628a..9a2d84954 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt @@ -2,10 +2,12 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.padding import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.material.Checkbox import androidx.compose.material.MaterialTheme import androidx.compose.material.Tab import androidx.compose.material.TabRow @@ -15,7 +17,11 @@ import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.res.stringResource @@ -23,6 +29,7 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.viewmodel.compose.viewModel +import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.screen.NostrHiddenAccountsFeedViewModel import com.vitorpamplona.amethyst.ui.screen.RefreshingFeedUserFeedView @@ -67,6 +74,20 @@ fun HiddenUsersScreen( Column(modifier = Modifier.padding(start = 10.dp, end = 10.dp)) { val pagerState = rememberPagerState() val coroutineScope = rememberCoroutineScope() + var checked by remember { mutableStateOf(accountViewModel.account.optOutFromFilters) } + + Row(verticalAlignment = Alignment.CenterVertically) { + Checkbox( + checked = checked, + onCheckedChange = { + checked = it + accountViewModel.account.updateOptOutFromFilters(checked) + LocalPreferences.saveToEncryptedStorage(accountViewModel.account) + } + ) + + Text(stringResource(R.string.opt_out_from_filters)) + } TabRow( backgroundColor = MaterialTheme.colors.background, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5666371e1..9aa32df18 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -412,4 +412,5 @@ Always show content warnings Recommends: + Opt-out from automatic filters