mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-11-10 18:06:53 +01:00
add option to opt-out from automatic spam and report filters
This commit is contained in:
@@ -61,6 +61,7 @@ private object PrefKeys {
|
|||||||
const val USE_PROXY = "use_proxy"
|
const val USE_PROXY = "use_proxy"
|
||||||
const val PROXY_PORT = "proxy_port"
|
const val PROXY_PORT = "proxy_port"
|
||||||
const val SHOW_SENSITIVE_CONTENT = "show_sensitive_content"
|
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" }
|
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.HIDE_BLOCK_ALERT_DIALOG, account.hideBlockAlertDialog)
|
||||||
putBoolean(PrefKeys.USE_PROXY, account.proxy != null)
|
putBoolean(PrefKeys.USE_PROXY, account.proxy != null)
|
||||||
putInt(PrefKeys.PROXY_PORT, account.proxyPort)
|
putInt(PrefKeys.PROXY_PORT, account.proxyPort)
|
||||||
|
putBoolean(PrefKeys.OPT_OUT_FILTERS, account.optOutFromFilters)
|
||||||
|
|
||||||
if (account.showSensitiveContent == null) {
|
if (account.showSensitiveContent == null) {
|
||||||
remove(PrefKeys.SHOW_SENSITIVE_CONTENT)
|
remove(PrefKeys.SHOW_SENSITIVE_CONTENT)
|
||||||
@@ -306,6 +308,7 @@ object LocalPreferences {
|
|||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
val optOutFromFilters = getBoolean(PrefKeys.OPT_OUT_FILTERS, false)
|
||||||
|
|
||||||
val a = Account(
|
val a = Account(
|
||||||
Persona(privKey = privKey?.hexToByteArray(), pubKey = pubKey.hexToByteArray()),
|
Persona(privKey = privKey?.hexToByteArray(), pubKey = pubKey.hexToByteArray()),
|
||||||
@@ -327,7 +330,8 @@ object LocalPreferences {
|
|||||||
latestContactList,
|
latestContactList,
|
||||||
proxy,
|
proxy,
|
||||||
proxyPort,
|
proxyPort,
|
||||||
showSensitiveContent
|
showSensitiveContent,
|
||||||
|
optOutFromFilters
|
||||||
)
|
)
|
||||||
|
|
||||||
return a
|
return a
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.vitorpamplona.amethyst
|
||||||
|
|
||||||
|
object OptOutFromFilters {
|
||||||
|
var optOutFromFilters: Boolean = false
|
||||||
|
|
||||||
|
fun start(optOut: Boolean) {
|
||||||
|
optOutFromFilters = optOut
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,6 +36,7 @@ object ServiceManager {
|
|||||||
|
|
||||||
// Resets Proxy Use
|
// Resets Proxy Use
|
||||||
HttpClient.start(account)
|
HttpClient.start(account)
|
||||||
|
OptOutFromFilters.start(account?.optOutFromFilters ?: false)
|
||||||
Coil.setImageLoader {
|
Coil.setImageLoader {
|
||||||
ImageLoader.Builder(context).components {
|
ImageLoader.Builder(context).components {
|
||||||
if (Build.VERSION.SDK_INT >= 28) {
|
if (Build.VERSION.SDK_INT >= 28) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import androidx.compose.runtime.Immutable
|
|||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import androidx.core.os.ConfigurationCompat
|
import androidx.core.os.ConfigurationCompat
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
|
import com.vitorpamplona.amethyst.OptOutFromFilters
|
||||||
import com.vitorpamplona.amethyst.service.FileHeader
|
import com.vitorpamplona.amethyst.service.FileHeader
|
||||||
import com.vitorpamplona.amethyst.service.NostrLnZapPaymentResponseDataSource
|
import com.vitorpamplona.amethyst.service.NostrLnZapPaymentResponseDataSource
|
||||||
import com.vitorpamplona.amethyst.service.model.*
|
import com.vitorpamplona.amethyst.service.model.*
|
||||||
@@ -66,7 +67,8 @@ class Account(
|
|||||||
var backupContactList: ContactListEvent? = null,
|
var backupContactList: ContactListEvent? = null,
|
||||||
var proxy: Proxy?,
|
var proxy: Proxy?,
|
||||||
var proxyPort: Int,
|
var proxyPort: Int,
|
||||||
var showSensitiveContent: Boolean? = null
|
var showSensitiveContent: Boolean? = null,
|
||||||
|
var optOutFromFilters: Boolean = false
|
||||||
) {
|
) {
|
||||||
var transientHiddenUsers: Set<String> = setOf()
|
var transientHiddenUsers: Set<String> = setOf()
|
||||||
|
|
||||||
@@ -77,6 +79,13 @@ class Account(
|
|||||||
|
|
||||||
var userProfileCache: User? = null
|
var userProfileCache: User? = null
|
||||||
|
|
||||||
|
fun updateOptOutFromFilters(value: Boolean) {
|
||||||
|
optOutFromFilters = value
|
||||||
|
OptOutFromFilters.start(optOutFromFilters)
|
||||||
|
live.invalidateData()
|
||||||
|
saveable.invalidateData()
|
||||||
|
}
|
||||||
|
|
||||||
fun userProfile(): User {
|
fun userProfile(): User {
|
||||||
return userProfileCache ?: run {
|
return userProfileCache ?: run {
|
||||||
val myUser: User = LocalCache.getOrCreateUser(loggedIn.pubKey.toHexKey())
|
val myUser: User = LocalCache.getOrCreateUser(loggedIn.pubKey.toHexKey())
|
||||||
@@ -1057,12 +1066,19 @@ class Account(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun isAcceptable(user: User): Boolean {
|
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
|
return !isHidden(user) && // if user hasn't hided this author
|
||||||
user.reportsBy(userProfile()).isEmpty() && // if user has not reported this post
|
user.reportsBy(userProfile()).isEmpty() && // if user has not reported this post
|
||||||
user.countReportAuthorsBy(followingKeySet()) < 5
|
user.countReportAuthorsBy(followingKeySet()) < 5
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isAcceptableDirect(note: Note): Boolean {
|
fun isAcceptableDirect(note: Note): Boolean {
|
||||||
|
if (optOutFromFilters) {
|
||||||
|
return note.reportsBy(userProfile()).isEmpty()
|
||||||
|
}
|
||||||
return note.reportsBy(userProfile()).isEmpty() && // if user has not reported this post
|
return note.reportsBy(userProfile()).isEmpty() && // if user has not reported this post
|
||||||
note.countReportAuthorsBy(followingKeySet()) < 5 // if it has 5 reports by reliable users
|
note.countReportAuthorsBy(followingKeySet()) < 5 // if it has 5 reports by reliable users
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.vitorpamplona.amethyst.model
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.util.LruCache
|
import android.util.LruCache
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
|
import com.vitorpamplona.amethyst.OptOutFromFilters
|
||||||
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
||||||
import com.vitorpamplona.amethyst.service.model.Event
|
import com.vitorpamplona.amethyst.service.model.Event
|
||||||
import com.vitorpamplona.amethyst.service.nip19.Nip19
|
import com.vitorpamplona.amethyst.service.nip19.Nip19
|
||||||
@@ -20,6 +21,8 @@ class AntiSpamFilter {
|
|||||||
fun isSpam(event: Event, relay: Relay?): Boolean {
|
fun isSpam(event: Event, relay: Relay?): Boolean {
|
||||||
checkNotInMainThread()
|
checkNotInMainThread()
|
||||||
|
|
||||||
|
if (OptOutFromFilters.optOutFromFilters) return false
|
||||||
|
|
||||||
val idHex = event.id
|
val idHex = event.id
|
||||||
|
|
||||||
// if short message, ok
|
// if short message, ok
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn
|
|||||||
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.pager.HorizontalPager
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
|
import androidx.compose.material.Checkbox
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.Tab
|
import androidx.compose.material.Tab
|
||||||
import androidx.compose.material.TabRow
|
import androidx.compose.material.TabRow
|
||||||
@@ -15,7 +17,11 @@ import androidx.compose.runtime.DisposableEffect
|
|||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
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.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@@ -23,6 +29,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.LifecycleEventObserver
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import com.vitorpamplona.amethyst.LocalPreferences
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.ui.screen.NostrHiddenAccountsFeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.NostrHiddenAccountsFeedViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.RefreshingFeedUserFeedView
|
import com.vitorpamplona.amethyst.ui.screen.RefreshingFeedUserFeedView
|
||||||
@@ -67,6 +74,20 @@ fun HiddenUsersScreen(
|
|||||||
Column(modifier = Modifier.padding(start = 10.dp, end = 10.dp)) {
|
Column(modifier = Modifier.padding(start = 10.dp, end = 10.dp)) {
|
||||||
val pagerState = rememberPagerState()
|
val pagerState = rememberPagerState()
|
||||||
val coroutineScope = rememberCoroutineScope()
|
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(
|
TabRow(
|
||||||
backgroundColor = MaterialTheme.colors.background,
|
backgroundColor = MaterialTheme.colors.background,
|
||||||
|
|||||||
@@ -412,4 +412,5 @@
|
|||||||
<string name="content_warning_see_warnings">Always show content warnings</string>
|
<string name="content_warning_see_warnings">Always show content warnings</string>
|
||||||
|
|
||||||
<string name="recommended_apps">Recommends: </string>
|
<string name="recommended_apps">Recommends: </string>
|
||||||
|
<string name="opt_out_from_filters">Opt-out from automatic filters</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user