diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt
index ca2657137..655ef6cfa 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt
@@ -1144,11 +1144,16 @@ class Account(
fun isWriteable(): Boolean = settings.isWriteable()
- fun updateOptOutOptions(
- warnReports: Boolean,
- filterSpam: Boolean,
- ): Boolean {
- if (settings.updateOptOutOptions(warnReports, filterSpam)) {
+ fun updateWarnReports(warnReports: Boolean): Boolean {
+ if (settings.updateWarnReports(warnReports)) {
+ sendNewAppSpecificData()
+ return true
+ }
+ return false
+ }
+
+ fun updateFilterSpam(filterSpam: Boolean): Boolean {
+ if (settings.updateFilterSpam(filterSpam)) {
if (!settings.syncedSettings.security.filterSpamFromStrangers.value) {
transientHiddenUsers.update {
emptySet()
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSettings.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSettings.kt
index a901ab19d..a913cc07f 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSettings.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSettings.kt
@@ -538,11 +538,16 @@ class AccountSettings(
return false
}
- fun updateOptOutOptions(
- warnReports: Boolean,
- filterSpam: Boolean,
- ): Boolean =
- if (syncedSettings.security.updateOptOutOptions(warnReports, filterSpam)) {
+ fun updateWarnReports(warnReports: Boolean): Boolean =
+ if (syncedSettings.security.updateWarnReports(warnReports)) {
+ saveAccountSettings()
+ true
+ } else {
+ false
+ }
+
+ fun updateFilterSpam(filterSpam: Boolean): Boolean =
+ if (syncedSettings.security.updateFilterSpam(filterSpam)) {
saveAccountSettings()
true
} else {
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSyncedSettings.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSyncedSettings.kt
index 7aa0fef4b..58facacd4 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSyncedSettings.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSyncedSettings.kt
@@ -190,17 +190,17 @@ class AccountSecurityPreferences(
return false
}
- // ---
- // filters
- // ---
- fun updateOptOutOptions(
- warnReports: Boolean,
- filterSpam: Boolean,
- ): Boolean =
- if (warnAboutPostsWithReports != warnReports || filterSpam != filterSpamFromStrangers.value) {
+ fun updateWarnReports(warnReports: Boolean): Boolean =
+ if (warnAboutPostsWithReports != warnReports) {
warnAboutPostsWithReports = warnReports
- filterSpamFromStrangers.tryEmit(filterSpam)
+ true
+ } else {
+ false
+ }
+ fun updateFilterSpam(filterSpam: Boolean): Boolean =
+ if (filterSpam != filterSpamFromStrangers.value) {
+ filterSpamFromStrangers.tryEmit(filterSpam)
true
} else {
false
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt
index cc722dc75..b00ffdbae 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt
@@ -149,3 +149,33 @@ fun parseBooleanType(screenCode: Int): BooleanType =
BooleanType.ALWAYS
}
}
+
+enum class WarningType(
+ val prefCode: Boolean?,
+ val screenCode: Int,
+ val resourceId: Int,
+) {
+ WARN(null, 0, R.string.content_warning_see_warnings_option),
+ SHOW(true, 1, R.string.content_warning_show_all_sensitive_content_option),
+ HIDE(false, 2, R.string.content_warning_hide_all_sensitive_content_option),
+}
+
+fun parseWarningType(screenCode: Int): WarningType =
+ when (screenCode) {
+ WarningType.WARN.screenCode -> WarningType.WARN
+ WarningType.SHOW.screenCode -> WarningType.SHOW
+ WarningType.HIDE.screenCode -> WarningType.HIDE
+ else -> {
+ WarningType.WARN
+ }
+ }
+
+fun parseWarningType(code: Boolean?): WarningType =
+ when (code) {
+ WarningType.WARN.prefCode -> WarningType.WARN
+ WarningType.HIDE.prefCode -> WarningType.HIDE
+ WarningType.SHOW.prefCode -> WarningType.SHOW
+ else -> {
+ WarningType.WARN
+ }
+ }
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt
index 10b77f9db..c93d892d8 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt
@@ -324,34 +324,6 @@ fun NoteDropDownMenu(
)
}
HorizontalDivider(thickness = DividerThickness)
- if (state.showSensitiveContent == null || state.showSensitiveContent == true) {
- DropdownMenuItem(
- text = { Text(stringRes(R.string.content_warning_hide_all_sensitive_content)) },
- onClick = {
- accountViewModel.hideSensitiveContent()
- onDismiss()
- },
- )
- }
- if (state.showSensitiveContent == null || state.showSensitiveContent == false) {
- DropdownMenuItem(
- text = { Text(stringRes(R.string.content_warning_show_all_sensitive_content)) },
- onClick = {
- accountViewModel.disableContentWarnings()
- onDismiss()
- },
- )
- }
- if (state.showSensitiveContent != null) {
- DropdownMenuItem(
- text = { Text(stringRes(R.string.content_warning_see_warnings)) },
- onClick = {
- accountViewModel.seeContentWarnings()
- onDismiss()
- },
- )
- }
- HorizontalDivider(thickness = DividerThickness)
if (state.isLoggedUser) {
DropdownMenuItem(
text = { Text(stringRes(R.string.request_deletion)) },
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt
index 6b60abcfb..9fbd8ebd3 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt
@@ -52,6 +52,7 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.PublicChatChannel
import com.vitorpamplona.amethyst.model.UrlCachedPreviewer
import com.vitorpamplona.amethyst.model.User
+import com.vitorpamplona.amethyst.model.WarningType
import com.vitorpamplona.amethyst.model.observables.CreatedAtComparator
import com.vitorpamplona.amethyst.service.CashuProcessor
import com.vitorpamplona.amethyst.service.CashuToken
@@ -886,21 +887,9 @@ class AccountViewModel(
fun isFollowing(user: HexKey): Boolean = account.isFollowing(user)
- fun hideSensitiveContent() {
+ fun updateContentWarnings(value: WarningType) {
viewModelScope.launch(Dispatchers.IO) {
- account.updateShowSensitiveContent(false)
- }
- }
-
- fun disableContentWarnings() {
- viewModelScope.launch(Dispatchers.IO) {
- account.updateShowSensitiveContent(true)
- }
- }
-
- fun seeContentWarnings() {
- viewModelScope.launch(Dispatchers.IO) {
- account.updateShowSensitiveContent(null)
+ account.updateShowSensitiveContent(value.prefCode)
}
}
@@ -924,12 +913,15 @@ class AccountViewModel(
fun filterSpamFromStrangers() = account.settings.syncedSettings.security.filterSpamFromStrangers
- fun updateOptOutOptions(
- warnReports: Boolean,
- filterSpam: Boolean,
- ) {
+ fun updateWarnReports(warnReports: Boolean) {
viewModelScope.launch(Dispatchers.IO) {
- if (account.updateOptOutOptions(warnReports, filterSpam)) {
+ account.updateWarnReports(warnReports)
+ }
+ }
+
+ fun updateFilterSpam(filterSpam: Boolean) {
+ viewModelScope.launch(Dispatchers.IO) {
+ if (account.updateFilterSpam(filterSpam)) {
LocalCache.antiSpam.active = filterSpamFromStrangers().value
}
}
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SecurityFiltersScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SecurityFiltersScreen.kt
index 751161ed4..f86d72bcb 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SecurityFiltersScreen.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SecurityFiltersScreen.kt
@@ -22,6 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
@@ -33,11 +34,11 @@ import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
-import androidx.compose.material3.Checkbox
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.ScrollableTabRow
+import androidx.compose.material3.Switch
import androidx.compose.material3.Tab
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -64,6 +65,8 @@ import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
+import com.vitorpamplona.amethyst.model.WarningType
+import com.vitorpamplona.amethyst.model.parseWarningType
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.observeAccountIsHiddenWord
import com.vitorpamplona.amethyst.ui.feeds.RefresheableBox
import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold
@@ -72,6 +75,8 @@ import com.vitorpamplona.amethyst.ui.navigation.TopBarWithBackButton
import com.vitorpamplona.amethyst.ui.note.elements.AddButton
import com.vitorpamplona.amethyst.ui.screen.RefreshingFeedUserFeedView
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
+import com.vitorpamplona.amethyst.ui.screen.loggedIn.TextSpinner
+import com.vitorpamplona.amethyst.ui.screen.loggedIn.TitleExplainer
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.dal.HiddenAccountsFeedViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.dal.HiddenWordsFeedViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.dal.SpammerAccountsFeedViewModel
@@ -80,9 +85,12 @@ import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
import com.vitorpamplona.amethyst.ui.theme.ButtonPadding
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
import com.vitorpamplona.amethyst.ui.theme.HorzPadding
+import com.vitorpamplona.amethyst.ui.theme.Size10dp
+import com.vitorpamplona.amethyst.ui.theme.Size15dp
import com.vitorpamplona.amethyst.ui.theme.StdPadding
import com.vitorpamplona.amethyst.ui.theme.TabRowHeight
import com.vitorpamplona.amethyst.ui.theme.placeholderText
+import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.launch
@Composable
@@ -153,35 +161,17 @@ fun SecurityFiltersScreen(
},
accountViewModel = accountViewModel,
) {
- Column(Modifier.padding(it).fillMaxHeight()) {
+ Column(
+ Modifier
+ .padding(it)
+ .fillMaxHeight(),
+ ) {
val pagerState = rememberPagerState { 3 }
val coroutineScope = rememberCoroutineScope()
- var warnAboutReports by remember { mutableStateOf(accountViewModel.account.settings.syncedSettings.security.warnAboutPostsWithReports) }
- var filterSpam by remember { mutableStateOf(accountViewModel.account.settings.syncedSettings.security.filterSpamFromStrangers.value) }
- Row(verticalAlignment = Alignment.CenterVertically) {
- Checkbox(
- checked = warnAboutReports,
- onCheckedChange = {
- warnAboutReports = it
- accountViewModel.updateOptOutOptions(warnAboutReports, filterSpam)
- },
- )
+ HeaderOptions(accountViewModel)
- Text(stringRes(R.string.warn_when_posts_have_reports_from_your_follows))
- }
-
- Row(verticalAlignment = Alignment.CenterVertically) {
- Checkbox(
- checked = filterSpam,
- onCheckedChange = {
- filterSpam = it
- accountViewModel.updateOptOutOptions(warnAboutReports, filterSpam)
- },
- )
-
- Text(stringRes(R.string.filter_spam_from_strangers))
- }
+ HorizontalDivider()
ScrollableTabRow(
containerColor = MaterialTheme.colorScheme.background,
@@ -218,6 +208,69 @@ fun SecurityFiltersScreen(
}
}
+@Composable
+private fun HeaderOptions(accountViewModel: AccountViewModel) {
+ Column(
+ Modifier
+ .padding(top = Size10dp, bottom = Size10dp, start = Size15dp, end = Size15dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = spacedBy(10.dp),
+ ) {
+ 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 = {
+ warnAboutReports = it
+ accountViewModel.updateWarnReports(warnAboutReports)
+ },
+ )
+ }
+
+ SettingsRow(
+ R.string.filter_spam_from_strangers_title,
+ R.string.filter_spam_from_strangers_explainer,
+ ) {
+ var filterSpam by remember { mutableStateOf(accountViewModel.account.settings.syncedSettings.security.filterSpamFromStrangers.value) }
+
+ Switch(
+ checked = filterSpam,
+ onCheckedChange = {
+ filterSpam = it
+ accountViewModel.updateFilterSpam(filterSpam)
+ },
+ )
+ }
+
+ SettingsRow(
+ R.string.show_sensitive_content_title,
+ R.string.show_sensitive_content_explainer,
+ ) {
+ var sensitive by remember { mutableStateOf(accountViewModel.account.settings.syncedSettings.security.showSensitiveContent.value) }
+
+ val selectedItens =
+ persistentListOf(
+ TitleExplainer(stringRes(WarningType.WARN.resourceId)),
+ TitleExplainer(stringRes(WarningType.SHOW.resourceId)),
+ TitleExplainer(stringRes(WarningType.HIDE.resourceId)),
+ )
+
+ TextSpinner(
+ label = "",
+ placeholder = selectedItens[parseWarningType(sensitive).screenCode].title,
+ options = selectedItens,
+ onSelect = {
+ accountViewModel.updateContentWarnings(parseWarningType(it))
+ },
+ )
+ }
+ }
+}
+
@Composable
private fun HiddenWordsFeed(
hiddenWordsViewModel: HiddenWordsFeedViewModel,
diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml
index 5646d9b57..bca4d2e09 100644
--- a/amethyst/src/main/res/values/strings.xml
+++ b/amethyst/src/main/res/values/strings.xml
@@ -585,10 +585,21 @@
Always show sensitive content
Always show content warnings
+ Hide
+ Show
+ Warn
+
Recommends:
Filter spam from strangers
Warn when posts have reports from your follows
+ Filter spam
+ Hides posts from strangers that were exactly the same for 5 or more times
+ Warn on reports
+ Shows a warning message when posts have 5 or more reports your follows
+ Show sensitive content
+ Shows a warning message when the author of the post marked it as sensitive
+
New Reaction Symbol
No reaction types pre-selected for this user. Long press on the heart button to change