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
}
suspend fun updateReportWarningThreshold(threshold: Int): Boolean {
if (settings.updateReportWarningThreshold(threshold.coerceAtLeast(1))) {
sendNewAppSpecificData()
return true
}
return false
}
suspend fun updateSendKind0EventsToLocalRelay(send: Boolean): Boolean {
if (settings.changeSendKind0EventsToLocalRelay(send)) {
sendNewAppSpecificData()
@@ -2905,7 +2913,7 @@ class Account(
return true
}
if (!settings.syncedSettings.security.warnAboutPostsWithReports) {
if (!settings.syncedSettings.security.warnAboutPostsWithReports.value) {
if (isHidden(user)) return false
val reports = user.reportsOrNull() ?: return true
@@ -2916,20 +2924,22 @@ class Account(
if (isHidden(user)) return false
val reports = user.reportsOrNull() ?: return true
val reportWarningThreshold = settings.syncedSettings.security.reportWarningThreshold.value.coerceAtLeast(1)
// if user hasn't hided this author
return reports.reportsBy(userProfile()).isEmpty() &&
// if user has not reported this post
reports.countReportAuthorsBy(followingKeySet()) < 5
reports.countReportAuthorsBy(followingKeySet()) < reportWarningThreshold
}
private fun isAcceptableDirect(note: Note): Boolean {
if (!settings.syncedSettings.security.warnAboutPostsWithReports) {
if (!settings.syncedSettings.security.warnAboutPostsWithReports.value) {
return !note.hasReportsBy(userProfile())
}
val reportWarningThreshold = settings.syncedSettings.security.reportWarningThreshold.value.coerceAtLeast(1)
return !note.hasReportsBy(userProfile()) &&
// 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 =
@@ -1083,6 +1083,14 @@ class AccountSettings(
false
}
fun updateReportWarningThreshold(threshold: Int): Boolean =
if (syncedSettings.security.updateReportWarningThreshold(threshold)) {
saveAccountSettings()
true
} else {
false
}
fun updateFilterSpam(filterSpam: Boolean): Boolean =
if (syncedSettings.security.updateFilterSpam(filterSpam)) {
saveAccountSettings()
@@ -51,7 +51,8 @@ class AccountSyncedSettings(
val security =
AccountSecurityPreferences(
MutableStateFlow(internalSettings.security.showSensitiveContent),
internalSettings.security.warnAboutPostsWithReports,
MutableStateFlow(internalSettings.security.warnAboutPostsWithReports),
MutableStateFlow(internalSettings.security.reportWarningThreshold),
MutableStateFlow(internalSettings.security.filterSpamFromStrangers),
MutableStateFlow(internalSettings.security.maxHashtagLimit),
MutableStateFlow(internalSettings.security.sendKind0EventsToLocalRelay),
@@ -79,7 +80,8 @@ class AccountSyncedSettings(
security =
AccountSecurityPreferencesInternal(
security.showSensitiveContent.value,
security.warnAboutPostsWithReports,
security.warnAboutPostsWithReports.value,
security.reportWarningThreshold.value,
security.filterSpamFromStrangers.value,
security.maxHashtagLimit.value,
security.sendKind0EventsToLocalRelay.value,
@@ -128,8 +130,12 @@ class AccountSyncedSettings(
security.filterSpamFromStrangers.tryEmit(syncedSettingsInternal.security.filterSpamFromStrangers)
}
if (security.warnAboutPostsWithReports != syncedSettingsInternal.security.warnAboutPostsWithReports) {
security.warnAboutPostsWithReports = syncedSettingsInternal.security.warnAboutPostsWithReports
if (security.warnAboutPostsWithReports.value != 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) {
@@ -235,7 +241,8 @@ class AccountLanguagePreferences(
@Stable
class AccountSecurityPreferences(
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),
val maxHashtagLimit: MutableStateFlow<Int> = MutableStateFlow(5),
var sendKind0EventsToLocalRelay: MutableStateFlow<Boolean> = MutableStateFlow(false),
@@ -250,8 +257,16 @@ class AccountSecurityPreferences(
}
fun updateWarnReports(warnReports: Boolean): Boolean =
if (warnAboutPostsWithReports != warnReports) {
warnAboutPostsWithReports = warnReports
if (warnAboutPostsWithReports.value != warnReports) {
warnAboutPostsWithReports.tryEmit(warnReports)
true
} else {
false
}
fun updateReportWarningThreshold(threshold: Int): Boolean =
if (reportWarningThreshold.value != threshold) {
reportWarningThreshold.update { threshold }
true
} else {
false
@@ -38,6 +38,7 @@ val DefaultReactions =
)
val DefaultZapAmounts = listOf(100L, 500L, 1000L)
val DefaultReportWarningThreshold = 5
@Serializable
enum class ReactionRowAction {
@@ -144,6 +145,7 @@ class AccountLanguagePreferencesInternal(
class AccountSecurityPreferencesInternal(
val showSensitiveContent: Boolean? = null,
var warnAboutPostsWithReports: Boolean = true,
val reportWarningThreshold: Int = DefaultReportWarningThreshold,
var filterSpamFromStrangers: Boolean = true,
val maxHashtagLimit: Int = 5,
var sendKind0EventsToLocalRelay: Boolean = false,
@@ -531,7 +531,11 @@ class AccountViewModel(
account.kind3FollowList.flow,
note.flow().author(),
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, _ ->
emit(isNoteAcceptable(metadata.note, hiddenUsers, followingUsers.authors))
}.onStart {
@@ -1152,6 +1156,8 @@ class AccountViewModel(
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 updateFilterSpam(filterSpam: Boolean) =
@@ -341,12 +341,12 @@ private fun HeaderOptions(accountViewModel: AccountViewModel) {
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = spacedBy(10.dp),
) {
var warnAboutReports by remember { mutableStateOf(accountViewModel.account.settings.syncedSettings.security.warnAboutPostsWithReports.value) }
SettingsRow(
R.string.warn_when_posts_have_reports_from_your_follows_title,
R.string.warn_when_posts_have_reports_from_your_follows_explainer,
) {
var warnAboutReports by remember { mutableStateOf(accountViewModel.account.settings.syncedSettings.security.warnAboutPostsWithReports) }
Switch(
checked = warnAboutReports,
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(
R.string.filter_spam_from_strangers_title,
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_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_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_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>