Merge pull request #449 from greenart7c3/main
add option to opt-out from automatic spam and report filters
This commit is contained in:
@@ -61,6 +61,8 @@ 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 WARN_ABOUT_REPORTS = "warn_about_reports"
|
||||||
|
const val FILTER_SPAM_FROM_STRANGERS = "filter_spam_from_strangers"
|
||||||
val LAST_READ: (String) -> String = { route -> "last_read_route_$route" }
|
val LAST_READ: (String) -> String = { route -> "last_read_route_$route" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,6 +219,8 @@ 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.WARN_ABOUT_REPORTS, account.warnAboutPostsWithReports)
|
||||||
|
putBoolean(PrefKeys.FILTER_SPAM_FROM_STRANGERS, account.filterSpamFromStrangers)
|
||||||
|
|
||||||
if (account.showSensitiveContent == null) {
|
if (account.showSensitiveContent == null) {
|
||||||
remove(PrefKeys.SHOW_SENSITIVE_CONTENT)
|
remove(PrefKeys.SHOW_SENSITIVE_CONTENT)
|
||||||
@@ -306,6 +310,8 @@ object LocalPreferences {
|
|||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
val filterSpam = getBoolean(PrefKeys.FILTER_SPAM_FROM_STRANGERS, true)
|
||||||
|
val warnAboutReports = getBoolean(PrefKeys.WARN_ABOUT_REPORTS, true)
|
||||||
|
|
||||||
val a = Account(
|
val a = Account(
|
||||||
Persona(privKey = privKey?.hexToByteArray(), pubKey = pubKey.hexToByteArray()),
|
Persona(privKey = privKey?.hexToByteArray(), pubKey = pubKey.hexToByteArray()),
|
||||||
@@ -327,7 +333,9 @@ object LocalPreferences {
|
|||||||
latestContactList,
|
latestContactList,
|
||||||
proxy,
|
proxy,
|
||||||
proxyPort,
|
proxyPort,
|
||||||
showSensitiveContent
|
showSensitiveContent,
|
||||||
|
warnAboutReports,
|
||||||
|
filterSpam
|
||||||
)
|
)
|
||||||
|
|
||||||
return a
|
return a
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.vitorpamplona.amethyst
|
||||||
|
|
||||||
|
object OptOutFromFilters {
|
||||||
|
var warnAboutPostsWithReports: Boolean = true
|
||||||
|
var filterSpamFromStrangers: Boolean = true
|
||||||
|
|
||||||
|
fun start(warnAboutReports: Boolean, filterSpam: Boolean) {
|
||||||
|
warnAboutPostsWithReports = warnAboutReports
|
||||||
|
filterSpamFromStrangers = filterSpam
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,6 +40,7 @@ object ServiceManager {
|
|||||||
|
|
||||||
// Resets Proxy Use
|
// Resets Proxy Use
|
||||||
HttpClient.start(account)
|
HttpClient.start(account)
|
||||||
|
OptOutFromFilters.start(account?.warnAboutPostsWithReports ?: true, account?.filterSpamFromStrangers ?: true)
|
||||||
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,9 @@ 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 warnAboutPostsWithReports: Boolean = true,
|
||||||
|
var filterSpamFromStrangers: Boolean = true
|
||||||
) {
|
) {
|
||||||
var transientHiddenUsers: Set<String> = setOf()
|
var transientHiddenUsers: Set<String> = setOf()
|
||||||
|
|
||||||
@@ -77,6 +80,17 @@ class Account(
|
|||||||
|
|
||||||
var userProfileCache: User? = null
|
var userProfileCache: User? = null
|
||||||
|
|
||||||
|
fun updateOptOutOptions(warnReports: Boolean, filterSpam: Boolean) {
|
||||||
|
warnAboutPostsWithReports = warnReports
|
||||||
|
filterSpamFromStrangers = filterSpam
|
||||||
|
OptOutFromFilters.start(warnAboutPostsWithReports, filterSpamFromStrangers)
|
||||||
|
if (!filterSpamFromStrangers) {
|
||||||
|
transientHiddenUsers = setOf()
|
||||||
|
}
|
||||||
|
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 +1071,19 @@ class Account(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun isAcceptable(user: User): Boolean {
|
fun isAcceptable(user: User): Boolean {
|
||||||
|
if (!warnAboutPostsWithReports) {
|
||||||
|
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 (!warnAboutPostsWithReports) {
|
||||||
|
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.filterSpamFromStrangers) 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,34 @@ 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 warnAboutReports by remember { mutableStateOf(accountViewModel.account.warnAboutPostsWithReports) }
|
||||||
|
var filterSpam by remember { mutableStateOf(accountViewModel.account.filterSpamFromStrangers) }
|
||||||
|
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Checkbox(
|
||||||
|
checked = warnAboutReports,
|
||||||
|
onCheckedChange = {
|
||||||
|
warnAboutReports = it
|
||||||
|
accountViewModel.account.updateOptOutOptions(warnAboutReports, filterSpam)
|
||||||
|
LocalPreferences.saveToEncryptedStorage(accountViewModel.account)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(stringResource(R.string.warn_when_posts_have_reports_from_your_follows))
|
||||||
|
}
|
||||||
|
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Checkbox(
|
||||||
|
checked = filterSpam,
|
||||||
|
onCheckedChange = {
|
||||||
|
filterSpam = it
|
||||||
|
accountViewModel.account.updateOptOutOptions(warnAboutReports, filterSpam)
|
||||||
|
LocalPreferences.saveToEncryptedStorage(accountViewModel.account)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(stringResource(R.string.filter_spam_from_strangers))
|
||||||
|
}
|
||||||
|
|
||||||
TabRow(
|
TabRow(
|
||||||
backgroundColor = MaterialTheme.colors.background,
|
backgroundColor = MaterialTheme.colors.background,
|
||||||
|
|||||||
@@ -412,4 +412,6 @@
|
|||||||
<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="filter_spam_from_strangers">Filter spam from strangers</string>
|
||||||
|
<string name="warn_when_posts_have_reports_from_your_follows">Warn when posts have reports from your follows</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user