Merge pull request #2830 from skotchdopolepet/codex/report-warning-threshold

Configure report warning threshold
This commit is contained in:
Vitor Pamplona
2026-05-11 08:27:13 -04:00
committed by GitHub
7 changed files with 85 additions and 15 deletions
@@ -525,6 +525,14 @@ class Account(
return false return false
} }
suspend fun updateReportWarningThreshold(threshold: Int): Boolean {
if (settings.updateReportWarningThreshold(threshold.coerceAtLeast(1))) {
sendNewAppSpecificData()
return true
}
return false
}
suspend fun updateSendKind0EventsToLocalRelay(send: Boolean): Boolean { suspend fun updateSendKind0EventsToLocalRelay(send: Boolean): Boolean {
if (settings.changeSendKind0EventsToLocalRelay(send)) { if (settings.changeSendKind0EventsToLocalRelay(send)) {
sendNewAppSpecificData() sendNewAppSpecificData()
@@ -2905,7 +2913,7 @@ class Account(
return true return true
} }
if (!settings.syncedSettings.security.warnAboutPostsWithReports) { if (!settings.syncedSettings.security.warnAboutPostsWithReports.value) {
if (isHidden(user)) return false if (isHidden(user)) return false
val reports = user.reportsOrNull() ?: return true val reports = user.reportsOrNull() ?: return true
@@ -2916,20 +2924,22 @@ class Account(
if (isHidden(user)) return false if (isHidden(user)) return false
val reports = user.reportsOrNull() ?: return true val reports = user.reportsOrNull() ?: return true
val reportWarningThreshold = settings.syncedSettings.security.reportWarningThreshold.value.coerceAtLeast(1)
// if user hasn't hided this author // if user hasn't hided this author
return reports.reportsBy(userProfile()).isEmpty() && return reports.reportsBy(userProfile()).isEmpty() &&
// if user has not reported this post // if user has not reported this post
reports.countReportAuthorsBy(followingKeySet()) < 5 reports.countReportAuthorsBy(followingKeySet()) < reportWarningThreshold
} }
private fun isAcceptableDirect(note: Note): Boolean { private fun isAcceptableDirect(note: Note): Boolean {
if (!settings.syncedSettings.security.warnAboutPostsWithReports) { if (!settings.syncedSettings.security.warnAboutPostsWithReports.value) {
return !note.hasReportsBy(userProfile()) return !note.hasReportsBy(userProfile())
} }
val reportWarningThreshold = settings.syncedSettings.security.reportWarningThreshold.value.coerceAtLeast(1)
return !note.hasReportsBy(userProfile()) && return !note.hasReportsBy(userProfile()) &&
// if user has not reported this post // if user has not reported this post
note.countReportAuthorsBy(followingKeySet()) < 5 // if it has 5 reports by reliable users note.countReportAuthorsBy(followingKeySet()) < reportWarningThreshold
} }
fun isDecryptedContentHidden(noteEvent: PrivateDmEvent): Boolean = fun isDecryptedContentHidden(noteEvent: PrivateDmEvent): Boolean =
@@ -1083,6 +1083,14 @@ class AccountSettings(
false false
} }
fun updateReportWarningThreshold(threshold: Int): Boolean =
if (syncedSettings.security.updateReportWarningThreshold(threshold)) {
saveAccountSettings()
true
} else {
false
}
fun updateFilterSpam(filterSpam: Boolean): Boolean = fun updateFilterSpam(filterSpam: Boolean): Boolean =
if (syncedSettings.security.updateFilterSpam(filterSpam)) { if (syncedSettings.security.updateFilterSpam(filterSpam)) {
saveAccountSettings() saveAccountSettings()
@@ -51,7 +51,8 @@ class AccountSyncedSettings(
val security = val security =
AccountSecurityPreferences( AccountSecurityPreferences(
MutableStateFlow(internalSettings.security.showSensitiveContent), MutableStateFlow(internalSettings.security.showSensitiveContent),
internalSettings.security.warnAboutPostsWithReports, MutableStateFlow(internalSettings.security.warnAboutPostsWithReports),
MutableStateFlow(internalSettings.security.reportWarningThreshold),
MutableStateFlow(internalSettings.security.filterSpamFromStrangers), MutableStateFlow(internalSettings.security.filterSpamFromStrangers),
MutableStateFlow(internalSettings.security.maxHashtagLimit), MutableStateFlow(internalSettings.security.maxHashtagLimit),
MutableStateFlow(internalSettings.security.sendKind0EventsToLocalRelay), MutableStateFlow(internalSettings.security.sendKind0EventsToLocalRelay),
@@ -79,7 +80,8 @@ class AccountSyncedSettings(
security = security =
AccountSecurityPreferencesInternal( AccountSecurityPreferencesInternal(
security.showSensitiveContent.value, security.showSensitiveContent.value,
security.warnAboutPostsWithReports, security.warnAboutPostsWithReports.value,
security.reportWarningThreshold.value,
security.filterSpamFromStrangers.value, security.filterSpamFromStrangers.value,
security.maxHashtagLimit.value, security.maxHashtagLimit.value,
security.sendKind0EventsToLocalRelay.value, security.sendKind0EventsToLocalRelay.value,
@@ -128,8 +130,12 @@ class AccountSyncedSettings(
security.filterSpamFromStrangers.tryEmit(syncedSettingsInternal.security.filterSpamFromStrangers) security.filterSpamFromStrangers.tryEmit(syncedSettingsInternal.security.filterSpamFromStrangers)
} }
if (security.warnAboutPostsWithReports != syncedSettingsInternal.security.warnAboutPostsWithReports) { if (security.warnAboutPostsWithReports.value != syncedSettingsInternal.security.warnAboutPostsWithReports) {
security.warnAboutPostsWithReports = syncedSettingsInternal.security.warnAboutPostsWithReports security.warnAboutPostsWithReports.tryEmit(syncedSettingsInternal.security.warnAboutPostsWithReports)
}
if (security.reportWarningThreshold.value != syncedSettingsInternal.security.reportWarningThreshold) {
security.reportWarningThreshold.tryEmit(syncedSettingsInternal.security.reportWarningThreshold)
} }
if (security.maxHashtagLimit.value != syncedSettingsInternal.security.maxHashtagLimit) { if (security.maxHashtagLimit.value != syncedSettingsInternal.security.maxHashtagLimit) {
@@ -235,7 +241,8 @@ class AccountLanguagePreferences(
@Stable @Stable
class AccountSecurityPreferences( class AccountSecurityPreferences(
val showSensitiveContent: MutableStateFlow<Boolean?> = MutableStateFlow(null), val showSensitiveContent: MutableStateFlow<Boolean?> = MutableStateFlow(null),
var warnAboutPostsWithReports: Boolean = true, val warnAboutPostsWithReports: MutableStateFlow<Boolean> = MutableStateFlow(true),
val reportWarningThreshold: MutableStateFlow<Int> = MutableStateFlow(DefaultReportWarningThreshold),
var filterSpamFromStrangers: MutableStateFlow<Boolean> = MutableStateFlow(true), var filterSpamFromStrangers: MutableStateFlow<Boolean> = MutableStateFlow(true),
val maxHashtagLimit: MutableStateFlow<Int> = MutableStateFlow(5), val maxHashtagLimit: MutableStateFlow<Int> = MutableStateFlow(5),
var sendKind0EventsToLocalRelay: MutableStateFlow<Boolean> = MutableStateFlow(false), var sendKind0EventsToLocalRelay: MutableStateFlow<Boolean> = MutableStateFlow(false),
@@ -250,8 +257,16 @@ class AccountSecurityPreferences(
} }
fun updateWarnReports(warnReports: Boolean): Boolean = fun updateWarnReports(warnReports: Boolean): Boolean =
if (warnAboutPostsWithReports != warnReports) { if (warnAboutPostsWithReports.value != warnReports) {
warnAboutPostsWithReports = warnReports warnAboutPostsWithReports.tryEmit(warnReports)
true
} else {
false
}
fun updateReportWarningThreshold(threshold: Int): Boolean =
if (reportWarningThreshold.value != threshold) {
reportWarningThreshold.update { threshold }
true true
} else { } else {
false false
@@ -38,6 +38,7 @@ val DefaultReactions =
) )
val DefaultZapAmounts = listOf(100L, 500L, 1000L) val DefaultZapAmounts = listOf(100L, 500L, 1000L)
val DefaultReportWarningThreshold = 5
@Serializable @Serializable
enum class ReactionRowAction { enum class ReactionRowAction {
@@ -144,6 +145,7 @@ class AccountLanguagePreferencesInternal(
class AccountSecurityPreferencesInternal( class AccountSecurityPreferencesInternal(
val showSensitiveContent: Boolean? = null, val showSensitiveContent: Boolean? = null,
var warnAboutPostsWithReports: Boolean = true, var warnAboutPostsWithReports: Boolean = true,
val reportWarningThreshold: Int = DefaultReportWarningThreshold,
var filterSpamFromStrangers: Boolean = true, var filterSpamFromStrangers: Boolean = true,
val maxHashtagLimit: Int = 5, val maxHashtagLimit: Int = 5,
var sendKind0EventsToLocalRelay: Boolean = false, var sendKind0EventsToLocalRelay: Boolean = false,
@@ -531,7 +531,11 @@ class AccountViewModel(
account.kind3FollowList.flow, account.kind3FollowList.flow,
note.flow().author(), note.flow().author(),
note.flow().metadata.stateFlow, note.flow().metadata.stateFlow,
note.flow().reports.stateFlow, combine(
note.flow().reports.stateFlow,
account.settings.syncedSettings.security.warnAboutPostsWithReports,
account.settings.syncedSettings.security.reportWarningThreshold,
) { reports, _, _ -> reports },
) { hiddenUsers, followingUsers, _, metadata, _ -> ) { hiddenUsers, followingUsers, _, metadata, _ ->
emit(isNoteAcceptable(metadata.note, hiddenUsers, followingUsers.authors)) emit(isNoteAcceptable(metadata.note, hiddenUsers, followingUsers.authors))
}.onStart { }.onStart {
@@ -1152,6 +1156,8 @@ class AccountViewModel(
fun updateWarnReports(warnReports: Boolean) = launchSigner { account.updateWarnReports(warnReports) } fun updateWarnReports(warnReports: Boolean) = launchSigner { account.updateWarnReports(warnReports) }
fun updateReportWarningThreshold(threshold: Int) = launchSigner { account.updateReportWarningThreshold(threshold) }
fun updateDisableClientTag(disable: Boolean) = launchSigner { account.updateDisableClientTag(disable) } fun updateDisableClientTag(disable: Boolean) = launchSigner { account.updateDisableClientTag(disable) }
fun updateFilterSpam(filterSpam: Boolean) = fun updateFilterSpam(filterSpam: Boolean) =
@@ -341,12 +341,12 @@ private fun HeaderOptions(accountViewModel: AccountViewModel) {
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = spacedBy(10.dp), verticalArrangement = spacedBy(10.dp),
) { ) {
var warnAboutReports by remember { mutableStateOf(accountViewModel.account.settings.syncedSettings.security.warnAboutPostsWithReports.value) }
SettingsRow( SettingsRow(
R.string.warn_when_posts_have_reports_from_your_follows_title, R.string.warn_when_posts_have_reports_from_your_follows_title,
R.string.warn_when_posts_have_reports_from_your_follows_explainer, R.string.warn_when_posts_have_reports_from_your_follows_explainer,
) { ) {
var warnAboutReports by remember { mutableStateOf(accountViewModel.account.settings.syncedSettings.security.warnAboutPostsWithReports) }
Switch( Switch(
checked = warnAboutReports, checked = warnAboutReports,
onCheckedChange = { onCheckedChange = {
@@ -356,6 +356,33 @@ private fun HeaderOptions(accountViewModel: AccountViewModel) {
) )
} }
if (warnAboutReports) {
SettingsRow(
R.string.report_warning_threshold_title,
R.string.report_warning_threshold_explainer,
) {
var reportWarningThreshold by remember {
mutableStateOf(accountViewModel.account.settings.syncedSettings.security.reportWarningThreshold.value.coerceAtLeast(1).toString())
}
OutlinedTextField(
value = reportWarningThreshold,
onValueChange = {
val updatedThreshold = (it.toIntOrNull() ?: 1).coerceAtLeast(1)
reportWarningThreshold = updatedThreshold.toString()
accountViewModel.updateReportWarningThreshold(updatedThreshold)
},
keyboardOptions =
KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done,
),
singleLine = true,
modifier = Modifier.padding(start = 8.dp),
)
}
}
SettingsRow( SettingsRow(
R.string.filter_spam_from_strangers_title, R.string.filter_spam_from_strangers_title,
R.string.filter_spam_from_strangers_explainer, R.string.filter_spam_from_strangers_explainer,
+3 -1
View File
@@ -1219,7 +1219,9 @@
<string name="disable_client_tag_title">Don\'t add client tag to my events</string> <string name="disable_client_tag_title">Don\'t add client tag to my events</string>
<string name="disable_client_tag_explainer">When enabled, Amethyst will not append a NIP-89 client tag to events you publish.</string> <string name="disable_client_tag_explainer">When enabled, Amethyst will not append a NIP-89 client tag to events you publish.</string>
<string name="warn_when_posts_have_reports_from_your_follows_title">Warn on reports</string> <string name="warn_when_posts_have_reports_from_your_follows_title">Warn on reports</string>
<string name="warn_when_posts_have_reports_from_your_follows_explainer">Shows a warning message when posts have 5 or more reports from your follows</string> <string name="warn_when_posts_have_reports_from_your_follows_explainer">Shows a warning message when posts or profiles have reports from your follows</string>
<string name="report_warning_threshold_title">Report warning threshold</string>
<string name="report_warning_threshold_explainer">Warns when posts or profiles reach this many reports from people you follow</string>
<string name="show_sensitive_content_title">Show sensitive content</string> <string name="show_sensitive_content_title">Show sensitive content</string>
<string name="show_sensitive_content_explainer">Shows a warning message when the author of the post marked it as sensitive</string> <string name="show_sensitive_content_explainer">Shows a warning message when the author of the post marked it as sensitive</string>
<string name="max_hashtag_limit_title">Max hashtags per post</string> <string name="max_hashtag_limit_title">Max hashtags per post</string>