feat(settings): add options to manage nsfw

This commit is contained in:
Diego Beraldin 2023-09-03 22:53:04 +02:00
parent a7120f1617
commit 376f84cfef
23 changed files with 109 additions and 12 deletions

View File

@ -27,6 +27,7 @@ interface CommunityDetailMviModel :
val canFetchMore: Boolean = true,
val sortType: SortType = SortType.Active,
val posts: List<PostModel> = emptyList(),
val blurNsfw: Boolean = true,
)
sealed interface Effect

View File

@ -331,7 +331,7 @@ class CommunityDetailScreen(
}
}
}
items(uiState.posts, key = { "${it.id}+${it.myVote}" }) { post ->
items(uiState.posts) { post ->
SwipeableCard(
modifier = Modifier.fillMaxWidth(),
directions = if (isOnOtherInstance) {
@ -432,7 +432,7 @@ class CommunityDetailScreen(
post = post,
blurNsfw = when {
community.nsfw -> false
else -> true
else -> uiState.blurNsfw
},
onUpVote = if (isOnOtherInstance) {
null

View File

@ -38,6 +38,7 @@ class CommunityDetailViewModel(
it.copy(
community = community,
sortType = sortType,
blurNsfw = keyStore[KeyStoreKeys.BlurNsfw, true],
)
}

View File

@ -62,6 +62,7 @@ val commonUiModule = module {
userRepository = get(),
postsRepository = get(),
hapticFeedback = get(),
keyStore = get(),
)
}
factory {

View File

@ -129,7 +129,7 @@ class InstanceInfoScreen(
)
}
}
items(uiState.communities, key = { it.id }) {
items(uiState.communities) {
val themeRepository = remember { getThemeRepository() }
val fontScale by themeRepository.contentFontScale.collectAsState()
CompositionLocalProvider(

View File

@ -205,7 +205,7 @@ class PostDetailScreen(
)
}
}
items(uiState.comments, key = { "${it.id}+${it.myVote}" }) { comment ->
items(uiState.comments) { comment ->
SwipeableCard(
modifier = Modifier.fillMaxWidth(),
backgroundColor = {

View File

@ -112,7 +112,7 @@ internal class UserDetailCommentsScreen(
)
}
}
items(uiState.comments, key = { "${it.id}+${it.myVote}" }) { comment ->
items(uiState.comments) { comment ->
SwipeableCard(
modifier = Modifier.fillMaxWidth(),
backgroundColor = {

View File

@ -121,7 +121,7 @@ internal class UserDetailPostsScreen(
)
}
}
items(uiState.posts, key = { "${it.id}+${it.myVote}" }) { post ->
items(uiState.posts) { post ->
SwipeableCard(
modifier = Modifier.fillMaxWidth(),
backgroundColor = {
@ -193,7 +193,7 @@ internal class UserDetailPostsScreen(
content = {
PostCard(
post = post,
blurNsfw = true,
blurNsfw = uiState.blurNsfw,
onUpVote = {
model.reduce(
UserPostsMviModel.Intent.UpVotePost(

View File

@ -25,6 +25,7 @@ interface UserPostsMviModel :
val posts: List<PostModel> = emptyList(),
val user: UserModel = UserModel(),
val sortType: SortType = SortType.Active,
val blurNsfw: Boolean = true,
)
sealed interface Effect

View File

@ -4,6 +4,8 @@ import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.racconforlemmy.core.utils.HapticFeedback
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.KeyStoreKeys
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.TemporaryKeyStore
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType
@ -21,6 +23,7 @@ class UserPostsViewModel(
private val userRepository: UserRepository,
private val postsRepository: PostsRepository,
private val hapticFeedback: HapticFeedback,
private val keyStore: TemporaryKeyStore,
) : ScreenModel,
MviModel<UserPostsMviModel.Intent, UserPostsMviModel.UiState, UserPostsMviModel.Effect> by mvi {
@ -31,7 +34,12 @@ class UserPostsViewModel(
mvi.scope.launch(Dispatchers.IO) {
val user = userRepository.get(user.id)
if (user != null) {
mvi.updateState { it.copy(user = user) }
mvi.updateState {
it.copy(
user = user,
blurNsfw = keyStore[KeyStoreKeys.BlurNsfw, true],
)
}
}
}
}

View File

@ -9,4 +9,6 @@ object KeyStoreKeys {
const val DefaultListingType = "defaultListingType"
const val DefaultPostSortType = "defaultPostSortType"
const val DefaultCommentSortType = "defaultCommentSortType"
const val IncludeNsfw = "includeNsfw"
const val BlurNsfw = "blurNsfw"
}

View File

@ -28,6 +28,7 @@ interface PostListMviModel :
val listingType: ListingType = ListingType.Local,
val sortType: SortType = SortType.Active,
val posts: List<PostModel> = emptyList(),
val blurNsfw: Boolean = true,
)
sealed interface Effect

View File

@ -105,7 +105,7 @@ class PostListScreen : Screen {
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(Spacing.xs),
) {
items(uiState.posts, key = { "${it.id}+${it.myVote}" }) { post ->
items(uiState.posts) { post ->
SwipeableCard(
modifier = Modifier.fillMaxWidth(),
onGestureBegin = {
@ -178,7 +178,7 @@ class PostListScreen : Screen {
)
},
post = post,
blurNsfw = true,
blurNsfw = uiState.blurNsfw,
onOpenCommunity = { community ->
navigator.push(
CommunityDetailScreen(

View File

@ -74,6 +74,7 @@ class PostListViewModel(
instance = apiConfigRepository.getInstance(),
listingType = listingType,
sortType = sortType,
blurNsfw = keyStore[KeyStoreKeys.BlurNsfw, true],
)
}
@ -123,6 +124,7 @@ class PostListViewModel(
val type = currentState.listingType
val sort = currentState.sortType
val refreshing = currentState.refreshing
val includeNsfw = keyStore[KeyStoreKeys.IncludeNsfw, true]
val postList = postsRepository.getAll(
auth = auth,
page = currentPage,
@ -136,6 +138,12 @@ class PostListViewModel(
postList
} else {
it.posts + postList
}.filter { post ->
if (includeNsfw) {
true
} else {
!post.nsfw
}
}
it.copy(
posts = newPosts,

View File

@ -91,7 +91,7 @@ class InboxMentionsScreen(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(Spacing.xs),
) {
items(uiState.mentions, key = { it.id }) { mention ->
items(uiState.mentions) { mention ->
SwipeableCard(
modifier = Modifier.fillMaxWidth(),
backgroundColor = {

View File

@ -91,7 +91,7 @@ class InboxRepliesScreen(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(Spacing.xs),
) {
items(uiState.mentions, key = { it.id }) { mention ->
items(uiState.mentions) { mention ->
SwipeableCard(
modifier = Modifier.fillMaxWidth(),
backgroundColor = {

View File

@ -51,6 +51,7 @@ kotlin {
implementation(projects.coreArchitecture)
implementation(projects.coreAppearance)
implementation(projects.coreUtils)
implementation(projects.corePreferences)
implementation(projects.coreCommonui)
implementation(projects.domainIdentity)

View File

@ -3,6 +3,8 @@ package com.github.diegoberaldin.raccoonforlemmy.feature.search.communitylist
import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.KeyStoreKeys
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.TemporaryKeyStore
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.ApiConfigurationRepository
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.ListingType
@ -22,6 +24,7 @@ class CommunityListViewModel(
private val apiConfigRepository: ApiConfigurationRepository,
private val identityRepository: IdentityRepository,
private val communityRepository: CommunityRepository,
private val keyStore: TemporaryKeyStore,
) : ScreenModel,
MviModel<CommunityListMviModel.Intent, CommunityListMviModel.UiState, CommunityListMviModel.Effect> by mvi {
@ -102,6 +105,7 @@ class CommunityListViewModel(
val refreshing = currentState.refreshing
val listingType = currentState.listingType
val sortType = currentState.sortType
val inclueNsfw = keyStore[KeyStoreKeys.IncludeNsfw, true]
val items = communityRepository.getAll(
query = searchText,
auth = auth,
@ -116,6 +120,12 @@ class CommunityListViewModel(
items
} else {
it.communities + items
}.filter { community ->
if (inclueNsfw) {
true
} else {
!community.nsfw
}
}
it.copy(
communities = newItems,

View File

@ -12,6 +12,7 @@ val searchTabModule = module {
apiConfigRepository = get(),
identityRepository = get(),
communityRepository = get(),
keyStore = get(),
)
}
}

View File

@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
@ -36,3 +37,26 @@ internal fun SettingsRow(
)
}
}
@Composable
internal fun SettingsSwitchRow(
title: String,
value: Boolean,
onValueChanged: (Boolean) -> Unit,
) {
Row(
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = title,
style = MaterialTheme.typography.bodyMedium,
)
Spacer(modifier = Modifier.weight(1f))
Switch(
checked = value,
onCheckedChange = {
onValueChanged(it)
}
)
}
}

View File

@ -209,6 +209,21 @@ class SettingsScreen : Screen {
)
},
)
// TODO!
SettingsSwitchRow(
title = "Include NSFW contents",
value = uiState.includeNsfw,
onValueChanged = { value ->
model.reduce(SettingsScreenMviModel.Intent.ChangeIncludeNsfw(value))
}
)
SettingsSwitchRow(
title = "Blur NSFW",
value = uiState.blurNsfw,
onValueChanged = { value ->
model.reduce(SettingsScreenMviModel.Intent.ChangeBlurNsfw(value))
}
)
}
}
}

View File

@ -16,6 +16,8 @@ interface SettingsScreenMviModel :
data class ChangeDefaultListingType(val value: ListingType) : Intent
data class ChangeDefaultPostSortType(val value: SortType) : Intent
data class ChangeDefaultCommentSortType(val value: SortType) : Intent
data class ChangeIncludeNsfw(val value: Boolean) : Intent
data class ChangeBlurNsfw(val value: Boolean) : Intent
}
data class UiState(
@ -26,6 +28,8 @@ interface SettingsScreenMviModel :
val defaultListingType: ListingType = ListingType.Local,
val defaultPostSortType: SortType = SortType.Active,
val defaultCommentSortType: SortType = SortType.New,
val includeNsfw: Boolean = true,
val blurNsfw: Boolean = true,
)
sealed interface Effect

View File

@ -55,6 +55,8 @@ class SettingsScreenViewModel(
defaultListingType = listingType,
defaultPostSortType = postSortType,
defaultCommentSortType = commentSortType,
includeNsfw = keyStore[KeyStoreKeys.IncludeNsfw, true],
blurNsfw = keyStore[KeyStoreKeys.BlurNsfw, true],
)
}
}
@ -75,6 +77,9 @@ class SettingsScreenViewModel(
is SettingsScreenMviModel.Intent.ChangeDefaultPostSortType -> changeDefaultPostSortType(
intent.value,
)
is SettingsScreenMviModel.Intent.ChangeBlurNsfw -> changeBlurNsfw(intent.value)
is SettingsScreenMviModel.Intent.ChangeIncludeNsfw -> changeIncludeNsfw(intent.value)
}
}
@ -119,4 +124,18 @@ class SettingsScreenViewModel(
keyStore.save(KeyStoreKeys.DefaultCommentSortType, value.toInt())
}
}
private fun changeIncludeNsfw(value: Boolean) {
mvi.updateState { it.copy(includeNsfw = value) }
mvi.scope.launch(Dispatchers.Main) {
keyStore.save(KeyStoreKeys.IncludeNsfw, value)
}
}
private fun changeBlurNsfw(value: Boolean) {
mvi.updateState { it.copy(blurNsfw = value) }
mvi.scope.launch(Dispatchers.Main) {
keyStore.save(KeyStoreKeys.BlurNsfw, value)
}
}
}