feat: cross-post (#117)

* feat: cross-post

* refactor: id-based options

* fix: show actions only for logged users
This commit is contained in:
Diego Beraldin 2023-11-09 19:40:27 +01:00 committed by GitHub
parent a4971ac670
commit 5d032fd583
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 1172 additions and 263 deletions

View File

@ -20,6 +20,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.Navigat
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailMviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateReportMviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateReportMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.saveditems.SavedItemsMviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.saveditems.SavedItemsMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.selectcommunity.SelectCommunityMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailMviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailMviModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
@ -108,9 +109,9 @@ actual fun getCreateCommentViewModel(
return res return res
} }
actual fun getCreatePostViewModel(communityId: Int?, editedPostId: Int?): CreatePostMviModel { actual fun getCreatePostViewModel(editedPostId: Int?): CreatePostMviModel {
val res: CreatePostMviModel by inject(clazz = CreatePostMviModel::class.java, val res: CreatePostMviModel by inject(clazz = CreatePostMviModel::class.java,
parameters = { parametersOf(communityId, editedPostId) }) parameters = { parametersOf(editedPostId) })
return res return res
} }
@ -151,6 +152,11 @@ actual fun getCreateReportViewModel(
return res return res
} }
actual fun getSelectCommunityViewModel(): SelectCommunityMviModel {
val res: SelectCommunityMviModel by inject(SelectCommunityMviModel::class.java)
return res
}
@Composable @Composable
actual fun getCustomTextToolbar( actual fun getCustomTextToolbar(

View File

@ -72,6 +72,8 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communityInfo.Comm
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CommunityHeader import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CommunityHeader
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenu import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenu
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenuItem import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenuItem
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Option
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.OptionId
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCardPlaceholder import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCardPlaceholder
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.ProgressHud import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.ProgressHud
@ -321,6 +323,7 @@ class CommunityDetailScreen(
} }
}, },
) )
if (uiState.currentUserId != null) {
this += FloatingActionButtonMenuItem( this += FloatingActionButtonMenuItem(
icon = Icons.Default.ClearAll, icon = Icons.Default.ClearAll,
text = stringResource(MR.strings.action_clear_read), text = stringResource(MR.strings.action_clear_read),
@ -331,6 +334,7 @@ class CommunityDetailScreen(
} }
}, },
) )
}
if (!isOnOtherInstance) { if (!isOnOtherInstance) {
this += FloatingActionButtonMenuItem( this += FloatingActionButtonMenuItem(
icon = Icons.Default.Create, icon = Icons.Default.Create,
@ -378,21 +382,36 @@ class CommunityDetailScreen(
community = uiState.community, community = uiState.community,
autoLoadImages = uiState.autoLoadImages, autoLoadImages = uiState.autoLoadImages,
options = listOf( options = listOf(
stringResource(MR.strings.community_detail_info), Option(
stringResource(MR.strings.community_detail_instance_info), OptionId.Info,
stringResource(MR.strings.community_detail_block), stringResource(MR.strings.community_detail_info)
stringResource(MR.strings.community_detail_block_instance), ),
Option(
OptionId.InfoInstance,
stringResource(MR.strings.community_detail_instance_info)
),
Option(
OptionId.Block,
stringResource(MR.strings.community_detail_block)
),
Option(
OptionId.BlockInstance,
stringResource(MR.strings.community_detail_block_instance)
),
), ),
onOpenImage = rememberCallbackArgs { url -> onOpenImage = rememberCallbackArgs { url ->
navigationCoordinator.getRootNavigator() navigationCoordinator.getRootNavigator()
?.push(ZoomableImageScreen(url)) ?.push(ZoomableImageScreen(url))
}, },
onOptionSelected = rememberCallbackArgs { optionIdx -> onOptionSelected = rememberCallbackArgs { optionId ->
when (optionIdx) { when (optionId) {
3 -> model.reduce(CommunityDetailMviModel.Intent.BlockInstance) OptionId.BlockInstance -> model.reduce(
2 -> model.reduce(CommunityDetailMviModel.Intent.Block) CommunityDetailMviModel.Intent.BlockInstance
)
1 -> { OptionId.Block -> model.reduce(CommunityDetailMviModel.Intent.Block)
OptionId.InfoInstance -> {
navigationCoordinator.getRootNavigator()?.push( navigationCoordinator.getRootNavigator()?.push(
InstanceInfoScreen( InstanceInfoScreen(
url = uiState.community.instanceUrl, url = uiState.community.instanceUrl,
@ -400,11 +419,13 @@ class CommunityDetailScreen(
) )
} }
else -> { OptionId.Info -> {
navigationCoordinator.getBottomNavigator()?.show( navigationCoordinator.getBottomNavigator()?.show(
CommunityInfoScreen(uiState.community), CommunityInfoScreen(uiState.community),
) )
} }
else -> Unit
} }
}, },
) )
@ -544,54 +565,95 @@ class CommunityDetailScreen(
) )
}, },
options = buildList { options = buildList {
add(stringResource(MR.strings.post_action_share)) add(
add(stringResource(MR.strings.post_action_hide)) Option(
add(stringResource(MR.strings.post_action_see_raw)) OptionId.Share,
add(stringResource(MR.strings.post_action_report)) stringResource(MR.strings.post_action_share)
)
)
if (uiState.currentUserId != null) {
add(
Option(
OptionId.Hide,
stringResource(MR.strings.post_action_hide)
)
)
}
add(
Option(
OptionId.SeeRaw,
stringResource(MR.strings.post_action_see_raw)
)
)
if (uiState.currentUserId != null) {
add(
Option(
OptionId.CrossPost,
stringResource(MR.strings.post_action_cross_post)
)
)
add(
Option(
OptionId.Report,
stringResource(MR.strings.post_action_report)
)
)
}
if (post.creator?.id == uiState.currentUserId && !isOnOtherInstance) { if (post.creator?.id == uiState.currentUserId && !isOnOtherInstance) {
add(stringResource(MR.strings.post_action_edit)) add(
add(stringResource(MR.strings.comment_action_delete)) Option(
OptionId.Edit,
stringResource(MR.strings.post_action_edit)
)
)
add(
Option(
OptionId.Delete,
stringResource(MR.strings.comment_action_delete)
)
)
} }
}, },
onOptionSelected = rememberCallbackArgs(model) { optionIdx -> onOptionSelected = rememberCallbackArgs(model) { optionId ->
when (optionIdx) { when (optionId) {
5 -> model.reduce( OptionId.Delete -> model.reduce(
CommunityDetailMviModel.Intent.DeletePost( CommunityDetailMviModel.Intent.DeletePost(post.id)
post.id
)
) )
4 -> { OptionId.Edit -> {
navigationCoordinator.getBottomNavigator() navigationCoordinator.getBottomNavigator()
?.show( ?.show(
CreatePostScreen( CreatePostScreen(editedPost = post)
editedPost = post,
)
) )
} }
3 -> { OptionId.Report -> {
navigationCoordinator.getBottomNavigator() navigationCoordinator.getBottomNavigator()
?.show( ?.show(
CreateReportScreen( CreateReportScreen(postId = post.id)
postId = post.id
)
) )
} }
2 -> { OptionId.CrossPost -> {
navigationCoordinator.getBottomNavigator()
?.show(
CreatePostScreen(crossPost = post)
)
}
OptionId.SeeRaw -> {
rawContent = post rawContent = post
} }
1 -> model.reduce( OptionId.Hide -> model.reduce(
CommunityDetailMviModel.Intent.Hide( CommunityDetailMviModel.Intent.Hide(post.id)
post.id
)
) )
else -> model.reduce( OptionId.Share -> model.reduce(
CommunityDetailMviModel.Intent.SharePost(post.id) CommunityDetailMviModel.Intent.SharePost(post.id)
) )
else -> Unit
} }
}) })
}, },

View File

@ -31,13 +31,13 @@ fun CollapsedCommentCard(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
separateUpAndDownVotes: Boolean = false, separateUpAndDownVotes: Boolean = false,
autoLoadImages: Boolean = true, autoLoadImages: Boolean = true,
options: List<String> = emptyList(), options: List<Option> = emptyList(),
onOpenCreator: ((UserModel) -> Unit)? = null, onOpenCreator: ((UserModel) -> Unit)? = null,
onUpVote: (() -> Unit)? = null, onUpVote: (() -> Unit)? = null,
onDownVote: (() -> Unit)? = null, onDownVote: (() -> Unit)? = null,
onSave: (() -> Unit)? = null, onSave: (() -> Unit)? = null,
onReply: (() -> Unit)? = null, onReply: (() -> Unit)? = null,
onOptionSelected: ((Int) -> Unit)? = null, onOptionSelected: ((OptionId) -> Unit)? = null,
onToggleExpanded: (() -> Unit)? = null, onToggleExpanded: (() -> Unit)? = null,
) { ) {
val themeRepository = remember { getThemeRepository() } val themeRepository = remember { getThemeRepository() }

View File

@ -40,7 +40,7 @@ fun CommentCard(
hideCommunity: Boolean = true, hideCommunity: Boolean = true,
hideIndent: Boolean = false, hideIndent: Boolean = false,
autoLoadImages: Boolean = true, autoLoadImages: Boolean = true,
options: List<String> = emptyList(), options: List<Option> = emptyList(),
onClick: (() -> Unit)? = null, onClick: (() -> Unit)? = null,
onUpVote: (() -> Unit)? = null, onUpVote: (() -> Unit)? = null,
onDownVote: (() -> Unit)? = null, onDownVote: (() -> Unit)? = null,
@ -48,7 +48,7 @@ fun CommentCard(
onReply: (() -> Unit)? = null, onReply: (() -> Unit)? = null,
onOpenCommunity: ((CommunityModel) -> Unit)? = null, onOpenCommunity: ((CommunityModel) -> Unit)? = null,
onOpenCreator: ((UserModel) -> Unit)? = null, onOpenCreator: ((UserModel) -> Unit)? = null,
onOptionSelected: ((Int) -> Unit)? = null, onOptionSelected: ((OptionId) -> Unit)? = null,
onToggleExpanded: (() -> Unit)? = null, onToggleExpanded: (() -> Unit)? = null,
) { ) {
val themeRepository = remember { getThemeRepository() } val themeRepository = remember { getThemeRepository() }

View File

@ -51,8 +51,8 @@ fun CommunityHeader(
community: CommunityModel, community: CommunityModel,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
autoLoadImages: Boolean = true, autoLoadImages: Boolean = true,
options: List<String> = emptyList(), options: List<Option> = emptyList(),
onOptionSelected: ((Int) -> Unit)? = null, onOptionSelected: ((OptionId) -> Unit)? = null,
onOpenImage: ((String) -> Unit)? = null, onOpenImage: ((String) -> Unit)? = null,
) { ) {
Box( Box(
@ -114,7 +114,7 @@ fun CommunityHeader(
// y = (-50).dp, // y = (-50).dp,
), ),
) { ) {
options.forEachIndexed { idx, option -> options.forEach { option ->
Text( Text(
modifier = Modifier.padding( modifier = Modifier.padding(
horizontal = Spacing.m, horizontal = Spacing.m,
@ -122,10 +122,10 @@ fun CommunityHeader(
).onClick( ).onClick(
rememberCallback { rememberCallback {
optionsExpanded = false optionsExpanded = false
onOptionSelected?.invoke(idx) onOptionSelected?.invoke(option.id)
}, },
), ),
text = option, text = option.text,
) )
} }
} }

View File

@ -13,7 +13,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.IconSize
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
@ -28,7 +28,7 @@ fun CommunityItem(
val communityName = community.name val communityName = community.name
val communityIcon = community.icon.orEmpty() val communityIcon = community.icon.orEmpty()
val communityHost = community.host val communityHost = community.host
val iconSize = if (small) 24.dp else 30.dp val iconSize = if (small) IconSize.m else IconSize.l
Row( Row(
modifier = modifier.padding( modifier = modifier.padding(
vertical = Spacing.xs, vertical = Spacing.xs,
@ -62,6 +62,7 @@ fun CommunityItem(
append(title) append(title)
}, },
style = MaterialTheme.typography.bodyLarge, style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onBackground,
) )
Text( Text(
text = buildString { text = buildString {

View File

@ -13,7 +13,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.IconSize
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.MultiCommunityModel import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.MultiCommunityModel
@ -26,7 +26,7 @@ fun MultiCommunityItem(
) { ) {
val title = community.name val title = community.name
val communityIcon = community.icon.orEmpty() val communityIcon = community.icon.orEmpty()
val iconSize = if (small) 24.dp else 30.dp val iconSize = if (small) IconSize.m else IconSize.l
Row( Row(
modifier = modifier.padding( modifier = modifier.padding(
vertical = Spacing.xs, vertical = Spacing.xs,

View File

@ -0,0 +1,20 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.components
data class Option(
val id: OptionId,
val text: String,
)
sealed class OptionId(val value: Int) {
data object Share : OptionId(0)
data object Hide : OptionId(1)
data object SeeRaw : OptionId(2)
data object CrossPost : OptionId(3)
data object Report : OptionId(4)
data object Edit : OptionId(5)
data object Delete : OptionId(6)
data object Info : OptionId(7)
data object InfoInstance : OptionId(8)
data object Block : OptionId(9)
data object BlockInstance : OptionId(10)
}

View File

@ -53,7 +53,7 @@ fun PostCard(
fullHeightImage: Boolean = true, fullHeightImage: Boolean = true,
limitBodyHeight: Boolean = false, limitBodyHeight: Boolean = false,
blurNsfw: Boolean = true, blurNsfw: Boolean = true,
options: List<String> = emptyList(), options: List<Option> = emptyList(),
onOpenCommunity: ((CommunityModel) -> Unit)? = null, onOpenCommunity: ((CommunityModel) -> Unit)? = null,
onOpenCreator: ((UserModel) -> Unit)? = null, onOpenCreator: ((UserModel) -> Unit)? = null,
onUpVote: (() -> Unit)? = null, onUpVote: (() -> Unit)? = null,
@ -61,7 +61,7 @@ fun PostCard(
onSave: (() -> Unit)? = null, onSave: (() -> Unit)? = null,
onReply: (() -> Unit)? = null, onReply: (() -> Unit)? = null,
onImageClick: ((String) -> Unit)? = null, onImageClick: ((String) -> Unit)? = null,
onOptionSelected: ((Int) -> Unit)? = null, onOptionSelected: ((OptionId) -> Unit)? = null,
onClick: (() -> Unit)? = null, onClick: (() -> Unit)? = null,
) { ) {
Box( Box(
@ -132,7 +132,7 @@ private fun CompactPost(
hideAuthor: Boolean, hideAuthor: Boolean,
blurNsfw: Boolean, blurNsfw: Boolean,
separateUpAndDownVotes: Boolean, separateUpAndDownVotes: Boolean,
options: List<String> = emptyList(), options: List<Option> = emptyList(),
onOpenCommunity: ((CommunityModel) -> Unit)? = null, onOpenCommunity: ((CommunityModel) -> Unit)? = null,
onOpenCreator: ((UserModel) -> Unit)? = null, onOpenCreator: ((UserModel) -> Unit)? = null,
onUpVote: (() -> Unit)? = null, onUpVote: (() -> Unit)? = null,
@ -140,7 +140,7 @@ private fun CompactPost(
onSave: (() -> Unit)? = null, onSave: (() -> Unit)? = null,
onReply: (() -> Unit)? = null, onReply: (() -> Unit)? = null,
onImageClick: ((String) -> Unit)? = null, onImageClick: ((String) -> Unit)? = null,
onOptionSelected: ((Int) -> Unit)? = null, onOptionSelected: ((OptionId) -> Unit)? = null,
onClick: (() -> Unit)? = null, onClick: (() -> Unit)? = null,
) { ) {
Column( Column(
@ -215,7 +215,7 @@ private fun ExtendedPost(
fullHeightImage: Boolean = true, fullHeightImage: Boolean = true,
roundedCornerImage: Boolean = true, roundedCornerImage: Boolean = true,
backgroundColor: Color = MaterialTheme.colorScheme.background, backgroundColor: Color = MaterialTheme.colorScheme.background,
options: List<String> = emptyList(), options: List<Option> = emptyList(),
onOpenCommunity: ((CommunityModel) -> Unit)? = null, onOpenCommunity: ((CommunityModel) -> Unit)? = null,
onOpenCreator: ((UserModel) -> Unit)? = null, onOpenCreator: ((UserModel) -> Unit)? = null,
onUpVote: (() -> Unit)? = null, onUpVote: (() -> Unit)? = null,
@ -223,7 +223,7 @@ private fun ExtendedPost(
onSave: (() -> Unit)? = null, onSave: (() -> Unit)? = null,
onReply: (() -> Unit)? = null, onReply: (() -> Unit)? = null,
onImageClick: ((String) -> Unit)? = null, onImageClick: ((String) -> Unit)? = null,
onOptionSelected: ((Int) -> Unit)? = null, onOptionSelected: ((OptionId) -> Unit)? = null,
onClick: (() -> Unit)? = null, onClick: (() -> Unit)? = null,
) { ) {
Column( Column(

View File

@ -54,12 +54,12 @@ fun PostCardFooter(
saved: Boolean = false, saved: Boolean = false,
upVoted: Boolean = false, upVoted: Boolean = false,
downVoted: Boolean = false, downVoted: Boolean = false,
options: List<String> = emptyList(), options: List<Option> = emptyList(),
onUpVote: (() -> Unit)? = null, onUpVote: (() -> Unit)? = null,
onDownVote: (() -> Unit)? = null, onDownVote: (() -> Unit)? = null,
onSave: (() -> Unit)? = null, onSave: (() -> Unit)? = null,
onReply: (() -> Unit)? = null, onReply: (() -> Unit)? = null,
onOptionSelected: ((Int) -> Unit)? = null, onOptionSelected: ((OptionId) -> Unit)? = null,
) { ) {
var optionsExpanded by remember { mutableStateOf(false) } var optionsExpanded by remember { mutableStateOf(false) }
var optionsOffset by remember { mutableStateOf(Offset.Zero) } var optionsOffset by remember { mutableStateOf(Offset.Zero) }
@ -232,7 +232,7 @@ fun PostCardFooter(
y = optionsOffset.y.toLocalDp(), y = optionsOffset.y.toLocalDp(),
), ),
) { ) {
options.forEachIndexed { idx, text -> options.forEach { option ->
Text( Text(
modifier = Modifier.padding( modifier = Modifier.padding(
horizontal = Spacing.m, horizontal = Spacing.m,
@ -240,10 +240,10 @@ fun PostCardFooter(
).onClick( ).onClick(
rememberCallback { rememberCallback {
optionsExpanded = false optionsExpanded = false
onOptionSelected?.invoke(idx) onOptionSelected?.invoke(option.id)
}, },
), ),
text = text, text = option.text,
) )
} }
} }

View File

@ -55,8 +55,8 @@ fun UserHeader(
user: UserModel, user: UserModel,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
autoLoadImages: Boolean = true, autoLoadImages: Boolean = true,
options: List<String> = emptyList(), options: List<Option> = emptyList(),
onOptionSelected: ((Int) -> Unit)? = null, onOptionSelected: ((OptionId) -> Unit)? = null,
onOpenImage: ((String) -> Unit)? = null, onOpenImage: ((String) -> Unit)? = null,
) { ) {
Box( Box(
@ -117,7 +117,7 @@ fun UserHeader(
y = optionsOffset.y.toLocalDp(), y = optionsOffset.y.toLocalDp(),
), ),
) { ) {
options.forEachIndexed { idx, option -> options.forEach { option ->
Text( Text(
modifier = Modifier.padding( modifier = Modifier.padding(
horizontal = Spacing.m, horizontal = Spacing.m,
@ -125,10 +125,10 @@ fun UserHeader(
).onClick( ).onClick(
rememberCallback { rememberCallback {
optionsExpanded = false optionsExpanded = false
onOptionSelected?.invoke(idx) onOptionSelected?.invoke(option.id)
}, },
), ),
text = option, text = option.text,
) )
} }
} }

View File

@ -49,6 +49,8 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CommentCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CommentCard
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Option
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.OptionId
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCardBody import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCardBody
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.ProgressHud import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.ProgressHud
@ -170,7 +172,12 @@ class CreateCommentScreen(
separateUpAndDownVotes = uiState.separateUpAndDownVotes, separateUpAndDownVotes = uiState.separateUpAndDownVotes,
autoLoadImages = uiState.autoLoadImages, autoLoadImages = uiState.autoLoadImages,
options = buildList { options = buildList {
add(stringResource(MR.strings.post_action_see_raw)) add(
Option(
OptionId.SeeRaw,
stringResource(MR.strings.post_action_see_raw)
)
)
}, },
onOptionSelected = { onOptionSelected = {
rawContent = originalComment rawContent = originalComment
@ -192,7 +199,12 @@ class CreateCommentScreen(
separateUpAndDownVotes = uiState.separateUpAndDownVotes, separateUpAndDownVotes = uiState.separateUpAndDownVotes,
autoLoadImages = uiState.autoLoadImages, autoLoadImages = uiState.autoLoadImages,
options = buildList { options = buildList {
add(stringResource(MR.strings.post_action_see_raw)) add(
Option(
OptionId.SeeRaw,
stringResource(MR.strings.post_action_see_raw)
)
)
}, },
onOptionSelected = { onOptionSelected = {
rawContent = originalPost rawContent = originalPost

View File

@ -4,6 +4,7 @@ import androidx.compose.runtime.Stable
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
import dev.icerock.moko.resources.desc.StringDesc import dev.icerock.moko.resources.desc.StringDesc
@Stable @Stable
@ -12,6 +13,7 @@ interface CreatePostMviModel :
ScreenModel { ScreenModel {
sealed interface Intent { sealed interface Intent {
data class SetCommunity(val value: CommunityModel) : Intent
data class SetTitle(val value: String) : Intent data class SetTitle(val value: String) : Intent
data class SetUrl(val value: String) : Intent data class SetUrl(val value: String) : Intent
data class ChangeNsfw(val value: Boolean) : Intent data class ChangeNsfw(val value: Boolean) : Intent
@ -54,6 +56,9 @@ interface CreatePostMviModel :
} }
data class UiState( data class UiState(
val communityInfo: String = "",
val communityId: Int? = null,
val communityError: StringDesc? = null,
val title: String = "", val title: String = "",
val titleError: StringDesc? = null, val titleError: StringDesc? = null,
val bodyError: StringDesc? = null, val bodyError: StringDesc? = null,

View File

@ -6,13 +6,13 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Groups
import androidx.compose.material.icons.filled.Image import androidx.compose.material.icons.filled.Image
import androidx.compose.material.icons.filled.Send import androidx.compose.material.icons.filled.Send
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
@ -28,6 +28,7 @@ import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@ -38,6 +39,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
@ -60,12 +62,16 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Section
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.TextFormattingBar import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.TextFormattingBar
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getCreatePostViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getCreatePostViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.selectcommunity.SelectCommunityDialog
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.utils.getGalleryHelper import com.github.diegoberaldin.raccoonforlemmy.core.utils.getGalleryHelper
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallbackArgs
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.shareUrl
import com.github.diegoberaldin.raccoonforlemmy.resources.MR import com.github.diegoberaldin.raccoonforlemmy.resources.MR
import dev.icerock.moko.resources.compose.localized import dev.icerock.moko.resources.compose.localized
import dev.icerock.moko.resources.compose.stringResource import dev.icerock.moko.resources.compose.stringResource
@ -75,15 +81,13 @@ import kotlinx.coroutines.flow.onEach
class CreatePostScreen( class CreatePostScreen(
private val communityId: Int? = null, private val communityId: Int? = null,
private val editedPost: PostModel? = null, private val editedPost: PostModel? = null,
private val crossPost: PostModel? = null,
) : Screen { ) : Screen {
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
override fun Content() { override fun Content() {
val model = rememberScreenModel { val model = rememberScreenModel {
getCreatePostViewModel( getCreatePostViewModel(editedPostId = editedPost?.id)
communityId = communityId,
editedPostId = editedPost?.id,
)
} }
model.bindToLifecycle(key) model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
@ -91,17 +95,63 @@ class CreatePostScreen(
val genericError = stringResource(MR.strings.message_generic_error) val genericError = stringResource(MR.strings.message_generic_error)
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
val galleryHelper = remember { getGalleryHelper() } val galleryHelper = remember { getGalleryHelper() }
val crossPostText = stringResource(MR.strings.create_post_cross_post_text)
var bodyTextFieldValue by remember { var bodyTextFieldValue by remember {
mutableStateOf(TextFieldValue(text = editedPost?.text.orEmpty())) val text = when {
crossPost != null -> buildString {
append(crossPostText)
append(" ")
append(crossPost.shareUrl)
}
editedPost != null -> {
editedPost.text
}
else -> ""
}
mutableStateOf(TextFieldValue(text = text))
} }
val bodyFocusRequester = remember { FocusRequester() } val bodyFocusRequester = remember { FocusRequester() }
val urlFocusRequester = remember { FocusRequester() } val urlFocusRequester = remember { FocusRequester() }
val focusManager = LocalFocusManager.current val focusManager = LocalFocusManager.current
val navigationCoordinator = remember { getNavigationCoordinator() } val navigationCoordinator = remember { getNavigationCoordinator() }
var openImagePicker by remember { mutableStateOf(false) }
var openImagePickerInBody by remember { mutableStateOf(false) }
if (openImagePicker) {
galleryHelper.getImageFromGallery { bytes ->
openImagePicker = false
model.reduce(CreatePostMviModel.Intent.ImageSelected(bytes))
}
}
if (openImagePickerInBody) {
galleryHelper.getImageFromGallery { bytes ->
openImagePickerInBody = false
model.reduce(CreatePostMviModel.Intent.InsertImageInBody(bytes))
}
}
var openSelectCommunity by remember { mutableStateOf(false) }
val keyboardScrollConnection = remember {
object : NestedScrollConnection {
override fun onPreScroll(
available: Offset,
source: NestedScrollSource,
): Offset {
focusManager.clearFocus()
return Offset.Zero
}
}
}
LaunchedEffect(model) { LaunchedEffect(model) {
model.reduce(CreatePostMviModel.Intent.SetTitle(editedPost?.title.orEmpty())) val referencePost = editedPost ?: crossPost
model.reduce(CreatePostMviModel.Intent.SetUrl(editedPost?.url.orEmpty())) model.reduce(CreatePostMviModel.Intent.SetTitle(referencePost?.title.orEmpty()))
model.reduce(CreatePostMviModel.Intent.SetUrl(referencePost?.url.orEmpty()))
if (communityId != null) {
model.reduce(
CreatePostMviModel.Intent.SetCommunity(CommunityModel(id = communityId))
)
}
model.effects.onEach { effect -> model.effects.onEach { effect ->
when (effect) { when (effect) {
@ -123,15 +173,26 @@ class CreatePostScreen(
} }
}.launchIn(this) }.launchIn(this)
} }
val keyboardScrollConnection = remember { DisposableEffect(key) {
object : NestedScrollConnection { notificationCenter.addObserver(
override fun onPreScroll( {
available: Offset, (it as CommunityModel)?.also { community ->
source: NestedScrollSource, model.reduce(CreatePostMviModel.Intent.SetCommunity(community))
): Offset {
focusManager.clearFocus() focusManager.clearFocus()
return Offset.Zero
} }
}, key, NotificationCenterContractKeys.SelectCommunity
)
notificationCenter.addObserver(
{
if (openSelectCommunity) {
openSelectCommunity = false
}
}, key, NotificationCenterContractKeys.CloseDialog
)
onDispose {
notificationCenter.removeObserver(key)
} }
} }
@ -147,7 +208,10 @@ class CreatePostScreen(
) { ) {
BottomSheetHandle() BottomSheetHandle()
Text( Text(
text = stringResource(MR.strings.create_post_title), text = when {
else ->
stringResource(MR.strings.create_post_title)
},
style = MaterialTheme.typography.titleLarge, style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.onBackground, color = MaterialTheme.colorScheme.onBackground,
) )
@ -164,8 +228,52 @@ class CreatePostScreen(
.padding(padding) .padding(padding)
.verticalScroll(rememberScrollState()), .verticalScroll(rememberScrollState()),
) { ) {
// community
if (crossPost != null) {
TextField( TextField(
modifier = Modifier.fillMaxWidth().heightIn(max = 300.dp), modifier = Modifier
.fillMaxWidth()
.onFocusChanged(
rememberCallbackArgs {
if (it.hasFocus) {
openSelectCommunity = true
}
},
),
colors = TextFieldDefaults.colors(
focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent,
disabledContainerColor = Color.Transparent,
),
label = {
Text(text = stringResource(MR.strings.create_post_community))
},
trailingIcon = {
Icon(
imageVector = Icons.Default.Groups,
contentDescription = null,
)
},
textStyle = MaterialTheme.typography.bodyMedium,
value = uiState.communityInfo,
readOnly = true,
singleLine = true,
onValueChange = {},
isError = uiState.communityError != null,
supportingText = {
if (uiState.communityError != null) {
Text(
text = uiState.communityError?.localized().orEmpty(),
color = MaterialTheme.colorScheme.error,
)
}
},
)
}
// title
TextField(
modifier = Modifier.fillMaxWidth(),
colors = TextFieldDefaults.colors( colors = TextFieldDefaults.colors(
focusedContainerColor = Color.Transparent, focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent, unfocusedContainerColor = Color.Transparent,
@ -199,21 +307,7 @@ class CreatePostScreen(
}, },
) )
var openImagePicker by remember { mutableStateOf(false) } // image
var openImagePickerInBody by remember { mutableStateOf(false) }
if (openImagePicker) {
galleryHelper.getImageFromGallery { bytes ->
openImagePicker = false
model.reduce(CreatePostMviModel.Intent.ImageSelected(bytes))
}
}
if (openImagePickerInBody) {
galleryHelper.getImageFromGallery { bytes ->
openImagePickerInBody = false
model.reduce(CreatePostMviModel.Intent.InsertImageInBody(bytes))
}
}
TextField( TextField(
modifier = Modifier.fillMaxWidth().focusRequester(urlFocusRequester), modifier = Modifier.fillMaxWidth().focusRequester(urlFocusRequester),
colors = TextFieldDefaults.colors( colors = TextFieldDefaults.colors(
@ -262,6 +356,7 @@ class CreatePostScreen(
}, },
) )
// NSFW
Row( Row(
modifier = Modifier.fillMaxWidth().padding( modifier = Modifier.fillMaxWidth().padding(
vertical = Spacing.s, horizontal = Spacing.m vertical = Spacing.s, horizontal = Spacing.m
@ -377,5 +472,9 @@ class CreatePostScreen(
if (uiState.loading) { if (uiState.loading) {
ProgressHud() ProgressHud()
} }
if (openSelectCommunity) {
SelectCommunityDialog().Content()
}
} }
} }

View File

@ -17,7 +17,6 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class CreatePostViewModel( class CreatePostViewModel(
private val communityId: Int?,
private val editedPostId: Int?, private val editedPostId: Int?,
private val mvi: DefaultMviModel<CreatePostMviModel.Intent, CreatePostMviModel.UiState, CreatePostMviModel.Effect>, private val mvi: DefaultMviModel<CreatePostMviModel.Intent, CreatePostMviModel.UiState, CreatePostMviModel.Effect>,
private val identityRepository: IdentityRepository, private val identityRepository: IdentityRepository,
@ -47,6 +46,20 @@ class CreatePostViewModel(
override fun reduce(intent: CreatePostMviModel.Intent) { override fun reduce(intent: CreatePostMviModel.Intent) {
when (intent) { when (intent) {
is CreatePostMviModel.Intent.SetCommunity -> {
val community = intent.value
mvi.updateState {
it.copy(
communityId = community.id,
communityInfo = buildString {
append(community.name)
append("@")
append(community.host)
},
)
}
}
is CreatePostMviModel.Intent.SetTitle -> { is CreatePostMviModel.Intent.SetTitle -> {
mvi.updateState { mvi.updateState {
it.copy(title = intent.value) it.copy(title = intent.value)
@ -132,6 +145,8 @@ class CreatePostViewModel(
bodyError = null, bodyError = null,
) )
} }
val communityId = uiState.value.communityId
val title = uiState.value.title val title = uiState.value.title
val url = uiState.value.url val url = uiState.value.url
val nsfw = uiState.value.nsfw val nsfw = uiState.value.nsfw
@ -160,6 +175,15 @@ class CreatePostViewModel(
} }
valid = false valid = false
} }
if (communityId == null) {
mvi.updateState {
it.copy(
communityError = message_missing_field.desc(),
)
}
valid = false
}
if (!valid) { if (!valid) {
return return
} }
@ -169,9 +193,9 @@ class CreatePostViewModel(
try { try {
val auth = identityRepository.authToken.value.orEmpty() val auth = identityRepository.authToken.value.orEmpty()
when { when {
communityId != null -> { editedPostId != null -> {
postRepository.create( postRepository.edit(
communityId = communityId, postId = editedPostId,
title = title, title = title,
body = body, body = body,
url = url, url = url,
@ -180,9 +204,9 @@ class CreatePostViewModel(
) )
} }
editedPostId != null -> { communityId != null -> {
postRepository.edit( postRepository.create(
postId = editedPostId, communityId = communityId,
title = title, title = title,
body = body, body = body,
url = url, url = url,

View File

@ -29,6 +29,8 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateRepor
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateReportViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateReportViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.saveditems.SavedItemsMviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.saveditems.SavedItemsMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.saveditems.SavedItemsViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.saveditems.SavedItemsViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.selectcommunity.SelectCommunityMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.selectcommunity.SelectCommunityViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailMviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.utils.di.utilsModule import com.github.diegoberaldin.raccoonforlemmy.core.utils.di.utilsModule
@ -134,8 +136,7 @@ val commonUiModule = module {
factory<CreatePostMviModel> { params -> factory<CreatePostMviModel> { params ->
CreatePostViewModel( CreatePostViewModel(
mvi = DefaultMviModel(CreatePostMviModel.UiState()), mvi = DefaultMviModel(CreatePostMviModel.UiState()),
communityId = params[0], editedPostId = params[0],
editedPostId = params[1],
identityRepository = get(), identityRepository = get(),
postRepository = get(), postRepository = get(),
themeRepository = get(), themeRepository = get(),
@ -199,4 +200,13 @@ val commonUiModule = module {
commentRepository = get(), commentRepository = get(),
) )
} }
factory<SelectCommunityMviModel> {
SelectCommunityViewModel(
mvi = DefaultMviModel(SelectCommunityMviModel.UiState()),
identityRepository = get(),
communityRepository = get(),
settingsRepository = get(),
notificationCenter = get(),
)
}
} }

View File

@ -16,6 +16,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.Navigat
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailMviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateReportMviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateReportMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.saveditems.SavedItemsMviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.saveditems.SavedItemsMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.selectcommunity.SelectCommunityMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailMviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailMviModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
@ -61,7 +62,6 @@ expect fun getCreateCommentViewModel(
): CreateCommentMviModel ): CreateCommentMviModel
expect fun getCreatePostViewModel( expect fun getCreatePostViewModel(
communityId: Int?,
editedPostId: Int?, editedPostId: Int?,
): CreatePostMviModel ): CreatePostMviModel
@ -82,3 +82,5 @@ expect fun getCreateReportViewModel(
expect fun getCustomTextToolbar( expect fun getCustomTextToolbar(
onSearch: () -> Unit, onSearch: () -> Unit,
): TextToolbar ): TextToolbar
expect fun getSelectCommunityViewModel(): SelectCommunityMviModel

View File

@ -81,6 +81,8 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Comment
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CommentCardPlaceholder import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CommentCardPlaceholder
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenu import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenu
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenuItem import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenuItem
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Option
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.OptionId
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SwipeableCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SwipeableCard
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentScreen
@ -407,37 +409,76 @@ class PostDetailScreen(
} }
}, },
options = buildList { options = buildList {
add(stringResource(MR.strings.post_action_share)) add(
add(stringResource(MR.strings.post_action_see_raw)) Option(
add(stringResource(MR.strings.post_action_report)) OptionId.Share,
stringResource(MR.strings.post_action_share)
)
)
add(
Option(
OptionId.SeeRaw,
stringResource(MR.strings.post_action_see_raw)
)
)
if (uiState.currentUserId != null) {
add(
Option(
OptionId.CrossPost,
stringResource(MR.strings.post_action_cross_post)
)
)
add(
Option(
OptionId.Report,
stringResource(MR.strings.post_action_report)
)
)
}
if (uiState.post.creator?.id == uiState.currentUserId && !isOnOtherInstance) { if (uiState.post.creator?.id == uiState.currentUserId && !isOnOtherInstance) {
add(stringResource(MR.strings.post_action_edit)) add(
add(stringResource(MR.strings.comment_action_delete)) Option(
OptionId.Edit,
stringResource(MR.strings.post_action_edit)
)
)
add(
Option(
OptionId.Delete,
stringResource(MR.strings.comment_action_delete)
)
)
} }
}, },
onOptionSelected = rememberCallbackArgs(model) { idx -> onOptionSelected = rememberCallbackArgs(model) { idx ->
when (idx) { when (idx) {
4 -> model.reduce(PostDetailMviModel.Intent.DeletePost) OptionId.Delete -> model.reduce(PostDetailMviModel.Intent.DeletePost)
3 -> { OptionId.Edit -> {
navigationCoordinator.getBottomNavigator()?.show( navigationCoordinator.getBottomNavigator()?.show(
CreatePostScreen( CreatePostScreen(editedPost = uiState.post)
editedPost = uiState.post,
)
) )
} }
2 -> { OptionId.Report -> {
navigationCoordinator.getBottomNavigator()?.show( navigationCoordinator.getBottomNavigator()?.show(
CreateReportScreen(postId = uiState.post.id) CreateReportScreen(postId = uiState.post.id)
) )
} }
1 -> { OptionId.CrossPost -> {
navigationCoordinator.getBottomNavigator()?.show(
CreatePostScreen(crossPost = uiState.post)
)
}
OptionId.SeeRaw -> {
rawContent = uiState.post rawContent = uiState.post
} }
else -> model.reduce(PostDetailMviModel.Intent.SharePost) OptionId.Share -> model.reduce(PostDetailMviModel.Intent.SharePost)
else -> Unit
} }
}, },
onImageClick = rememberCallbackArgs { url -> onImageClick = rememberCallbackArgs { url ->
@ -657,24 +698,44 @@ class PostDetailScreen(
} }
}, },
options = buildList { options = buildList {
add(stringResource(MR.strings.post_action_see_raw)) add(
add(stringResource(MR.strings.post_action_report)) Option(
OptionId.SeeRaw,
stringResource(MR.strings.post_action_see_raw)
)
)
add(
Option(
OptionId.Report,
stringResource(MR.strings.post_action_report)
)
)
if (comment.creator?.id == uiState.currentUserId) { if (comment.creator?.id == uiState.currentUserId) {
add(stringResource(MR.strings.post_action_edit)) add(
add(stringResource(MR.strings.comment_action_delete)) Option(
OptionId.Edit,
stringResource(MR.strings.post_action_edit)
)
)
add(
Option(
OptionId.Delete,
stringResource(MR.strings.comment_action_delete)
)
)
} }
}, },
onOptionSelected = rememberCallbackArgs( onOptionSelected = rememberCallbackArgs(
model model
) { optionId -> ) { optionId ->
when (optionId) { when (optionId) {
3 -> model.reduce( OptionId.Delete -> model.reduce(
PostDetailMviModel.Intent.DeleteComment( PostDetailMviModel.Intent.DeleteComment(
comment.id comment.id
) )
) )
2 -> { OptionId.Edit -> {
navigationCoordinator.getBottomNavigator() navigationCoordinator.getBottomNavigator()
?.show( ?.show(
CreateCommentScreen( CreateCommentScreen(
@ -683,7 +744,7 @@ class PostDetailScreen(
) )
} }
1 -> { OptionId.Report -> {
navigationCoordinator.getBottomNavigator() navigationCoordinator.getBottomNavigator()
?.show( ?.show(
CreateReportScreen( CreateReportScreen(
@ -692,9 +753,11 @@ class PostDetailScreen(
) )
} }
else -> { OptionId.SeeRaw -> {
rawContent = comment rawContent = comment
} }
else -> Unit
} }
}, },
) )
@ -762,22 +825,42 @@ class PostDetailScreen(
} }
}, },
options = buildList { options = buildList {
add(stringResource(MR.strings.post_action_see_raw)) add(
add(stringResource(MR.strings.post_action_report)) Option(
OptionId.SeeRaw,
stringResource(MR.strings.post_action_see_raw)
)
)
add(
Option(
OptionId.Report,
stringResource(MR.strings.post_action_report)
)
)
if (comment.creator?.id == uiState.currentUserId) { if (comment.creator?.id == uiState.currentUserId) {
add(stringResource(MR.strings.post_action_edit)) add(
add(stringResource(MR.strings.comment_action_delete)) Option(
OptionId.Edit,
stringResource(MR.strings.post_action_edit)
)
)
add(
Option(
OptionId.Delete,
stringResource(MR.strings.comment_action_delete)
)
)
} }
}, },
onOptionSelected = rememberCallbackArgs(model) { optionId -> onOptionSelected = rememberCallbackArgs(model) { optionId ->
when (optionId) { when (optionId) {
3 -> model.reduce( OptionId.Delete -> model.reduce(
PostDetailMviModel.Intent.DeleteComment( PostDetailMviModel.Intent.DeleteComment(
comment.id comment.id
) )
) )
2 -> { OptionId.Edit -> {
navigationCoordinator.getBottomNavigator() navigationCoordinator.getBottomNavigator()
?.show( ?.show(
CreateCommentScreen( CreateCommentScreen(
@ -786,7 +869,7 @@ class PostDetailScreen(
) )
} }
1 -> { OptionId.Report -> {
navigationCoordinator.getBottomNavigator() navigationCoordinator.getBottomNavigator()
?.show( ?.show(
CreateReportScreen( CreateReportScreen(
@ -795,9 +878,11 @@ class PostDetailScreen(
) )
} }
else -> { OptionId.SeeRaw -> {
rawContent = comment rawContent = comment
} }
else -> Unit
} }
}, },
) )

View File

@ -55,6 +55,8 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.Co
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CommentCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CommentCard
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenu import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenu
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenuItem import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenuItem
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Option
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.OptionId
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SectionSelector import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SectionSelector
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentScreen
@ -299,13 +301,28 @@ class SavedItemsScreen : Screen {
) )
}, },
options = buildList { options = buildList {
add(stringResource(MR.strings.post_action_share)) add(
add(stringResource(MR.strings.post_action_see_raw)) Option(
add(stringResource(MR.strings.post_action_report)) OptionId.Share,
stringResource(MR.strings.post_action_share)
)
)
add(
Option(
OptionId.SeeRaw,
stringResource(MR.strings.post_action_see_raw)
)
)
add(
Option(
OptionId.Report,
stringResource(MR.strings.post_action_report)
)
)
}, },
onOptionSelected = { optionIndex -> onOptionSelected = { optionIndex ->
when (optionIndex) { when (optionIndex) {
2 -> { OptionId.Report -> {
navigatorCoordinator.getBottomNavigator()?.show( navigatorCoordinator.getBottomNavigator()?.show(
CreateReportScreen( CreateReportScreen(
postId = post.id postId = post.id
@ -313,17 +330,19 @@ class SavedItemsScreen : Screen {
) )
} }
1 -> { OptionId.SeeRaw -> {
rawContent = post rawContent = post
} }
else -> { OptionId.Share -> {
model.reduce( model.reduce(
SavedItemsMviModel.Intent.SharePost( SavedItemsMviModel.Intent.SharePost(
post.id post.id
) )
) )
} }
else -> Unit
} }
}, },
) )
@ -393,12 +412,22 @@ class SavedItemsScreen : Screen {
navigatorCoordinator.getBottomNavigator()?.show(screen) navigatorCoordinator.getBottomNavigator()?.show(screen)
}, },
options = buildList { options = buildList {
add(stringResource(MR.strings.post_action_see_raw)) add(
add(stringResource(MR.strings.post_action_report)) Option(
OptionId.SeeRaw,
stringResource(MR.strings.post_action_see_raw)
)
)
add(
Option(
OptionId.Report,
stringResource(MR.strings.post_action_report)
)
)
}, },
onOptionSelected = { optionIndex -> onOptionSelected = { optionIndex ->
when (optionIndex) { when (optionIndex) {
1 -> { OptionId.Report -> {
navigatorCoordinator.getBottomNavigator()?.show( navigatorCoordinator.getBottomNavigator()?.show(
CreateReportScreen( CreateReportScreen(
commentId = comment.id commentId = comment.id
@ -406,9 +435,11 @@ class SavedItemsScreen : Screen {
) )
} }
else -> { OptionId.SeeRaw -> {
rawContent = comment rawContent = comment
} }
else -> Unit
} }
}, },
) )

View File

@ -0,0 +1,57 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.selectcommunity
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.CornerSize
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.IconSize
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.utils.shimmerEffect
@Composable
fun CommunityItemPlaceholder() {
Row(
modifier = Modifier.padding(
vertical = Spacing.xs,
horizontal = Spacing.s,
),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(Spacing.xs),
) {
Box(
modifier = Modifier
.height(IconSize.m)
.fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.s))
.shimmerEffect()
)
Column(
modifier = Modifier.padding(start = Spacing.xs),
) {
Box(
modifier = Modifier
.height(50.dp)
.fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.s))
.shimmerEffect()
)
Box(
modifier = Modifier
.height(30.dp)
.fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.s))
.shimmerEffect()
)
}
}
}

View File

@ -0,0 +1,159 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.selectcommunity
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Clear
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.core.screen.Screen
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CommunityItem
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getSelectCommunityViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
import dev.icerock.moko.resources.compose.stringResource
class SelectCommunityDialog : Screen {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
override fun Content() {
val model = rememberScreenModel { getSelectCommunityViewModel() }
model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState()
val notificationCenter = remember { getNotificationCenter() }
AlertDialog(
onDismissRequest = rememberCallback {
model.reduce(SelectCommunityMviModel.Intent.SetSearch(""))
notificationCenter.getObserver(NotificationCenterContractKeys.CloseDialog)
?.invoke(Unit)
},
) {
Column(
modifier = Modifier
.background(color = MaterialTheme.colorScheme.surface)
.padding(vertical = Spacing.s),
verticalArrangement = Arrangement.spacedBy(Spacing.s),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = stringResource(MR.strings.dialog_title_select_community),
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.onBackground,
)
Spacer(modifier = Modifier.height(Spacing.s))
TextField(
modifier = Modifier.fillMaxWidth(),
colors = TextFieldDefaults.colors(
focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent,
disabledContainerColor = Color.Transparent,
),
label = {
Text(text = stringResource(MR.strings.explore_search_placeholder))
},
singleLine = true,
value = uiState.searchText,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
),
onValueChange = { value ->
model.reduce(SelectCommunityMviModel.Intent.SetSearch(value))
},
trailingIcon = {
Icon(
modifier = Modifier.onClick(
rememberCallback {
if (uiState.searchText.isNotEmpty()) {
model.reduce(SelectCommunityMviModel.Intent.SetSearch(""))
}
},
),
imageVector = if (uiState.searchText.isEmpty()) Icons.Default.Search else Icons.Default.Clear,
contentDescription = null,
)
},
)
Box(
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 500.dp, max = 500.dp)
.padding(horizontal = Spacing.m)
) {
LazyColumn(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(Spacing.xxs),
) {
if (uiState.communities.isEmpty() && uiState.initial) {
items(5) {
CommunityItemPlaceholder()
}
}
items(uiState.communities, { it.id }) { community ->
CommunityItem(
modifier = Modifier.fillMaxWidth()
.background(MaterialTheme.colorScheme.background)
.onClick(rememberCallback {
notificationCenter.getObserver(
NotificationCenterContractKeys.SelectCommunity
)
?.invoke(community)
notificationCenter.getObserver(
NotificationCenterContractKeys.CloseDialog
)
?.invoke(Unit)
}),
autoLoadImages = uiState.autoLoadImages,
community = community,
)
}
}
}
Button(
onClick = {
model.reduce(SelectCommunityMviModel.Intent.SetSearch(""))
notificationCenter.getObserver(NotificationCenterContractKeys.CloseDialog)
?.invoke(Unit)
},
) {
Text(text = stringResource(MR.strings.button_close))
}
}
}
}
}

View File

@ -0,0 +1,22 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.selectcommunity
import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
interface SelectCommunityMviModel :
MviModel<SelectCommunityMviModel.Intent, SelectCommunityMviModel.UiState, SelectCommunityMviModel.Effect>,
ScreenModel {
sealed interface Intent {
data class SetSearch(val value: String) : Intent
}
data class UiState(
val initial: Boolean = true,
val communities: List<CommunityModel> = emptyList(),
val searchText: String = "",
val autoLoadImages: Boolean = true,
)
sealed interface Effect
}

View File

@ -0,0 +1,82 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.selectcommunity
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.SettingsRepository
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommunityRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
class SelectCommunityViewModel(
private val mvi: DefaultMviModel<SelectCommunityMviModel.Intent, SelectCommunityMviModel.UiState, SelectCommunityMviModel.Effect>,
private val identityRepository: IdentityRepository,
private val communityRepository: CommunityRepository,
private val settingsRepository: SettingsRepository,
private val notificationCenter: NotificationCenter,
) : SelectCommunityMviModel,
MviModel<SelectCommunityMviModel.Intent, SelectCommunityMviModel.UiState, SelectCommunityMviModel.Effect> by mvi {
private var communities: List<CommunityModel> = emptyList()
private var debounceJob: Job? = null
override fun onStarted() {
mvi.onStarted()
mvi.scope?.launch {
settingsRepository.currentSettings.onEach { settings ->
mvi.updateState { it.copy(autoLoadImages = settings.autoLoadImages) }
}.launchIn(this)
}
if (communities.isEmpty()) {
populate()
}
}
override fun reduce(intent: SelectCommunityMviModel.Intent) {
when (intent) {
is SelectCommunityMviModel.Intent.SetSearch -> setSearch(intent.value)
}
}
private fun setSearch(value: String) {
debounceJob?.cancel()
mvi.updateState { it.copy(searchText = value) }
debounceJob = mvi.scope?.launch(Dispatchers.IO) {
delay(1_000)
mvi.updateState {
val filtered = filterCommunities()
it.copy(communities = filtered)
}
}
}
private fun populate() {
mvi.scope?.launch(Dispatchers.IO) {
val auth = identityRepository.authToken.value
communities = communityRepository.getSubscribed(auth).sortedBy { it.name }
mvi.updateState {
it.copy(
initial = false,
communities = communities,
)
}
}
}
private fun filterCommunities(): List<CommunityModel> {
val searchText = uiState.value.searchText
val res = if (searchText.isNotEmpty()) {
communities.filter { it.name.contains(searchText) }
} else {
communities
}
return res
}
}

View File

@ -32,6 +32,7 @@ interface UserDetailMviModel :
} }
data class UiState( data class UiState(
val currentUserId: Int? = null,
val section: UserDetailSection = UserDetailSection.Posts, val section: UserDetailSection = UserDetailSection.Posts,
val sortType: SortType = SortType.Active, val sortType: SortType = SortType.Active,
val refreshing: Boolean = false, val refreshing: Boolean = false,

View File

@ -69,6 +69,8 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Comment
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CommentCardPlaceholder import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CommentCardPlaceholder
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenu import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenu
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenuItem import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenuItem
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Option
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.OptionId
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCardPlaceholder import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCardPlaceholder
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.ProgressHud import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.ProgressHud
@ -76,6 +78,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Section
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SwipeableCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SwipeableCard
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.UserHeader import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.UserHeader
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentScreen
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost.CreatePostScreen
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getDrawerCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getDrawerCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getFabNestedScrollConnection import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getFabNestedScrollConnection
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
@ -317,17 +320,24 @@ class UserDetailScreen(
user = uiState.user, user = uiState.user,
autoLoadImages = uiState.autoLoadImages, autoLoadImages = uiState.autoLoadImages,
options = listOf( options = listOf(
stringResource(MR.strings.community_detail_block), Option(
stringResource(MR.strings.community_detail_block_instance), OptionId.Block,
stringResource(MR.strings.community_detail_block)
),
Option(
OptionId.BlockInstance,
stringResource(MR.strings.community_detail_block_instance)
),
), ),
onOpenImage = rememberCallbackArgs { url -> onOpenImage = rememberCallbackArgs { url ->
navigationCoordinator.getRootNavigator() navigationCoordinator.getRootNavigator()
?.push(ZoomableImageScreen(url)) ?.push(ZoomableImageScreen(url))
}, },
onOptionSelected = rememberCallbackArgs { optionIdx -> onOptionSelected = rememberCallbackArgs { optionId ->
when (optionIdx) { when (optionId) {
1 -> model.reduce(UserDetailMviModel.Intent.BlockInstance) OptionId.BlockInstance -> model.reduce(UserDetailMviModel.Intent.BlockInstance)
else -> model.reduce(UserDetailMviModel.Intent.Block) OptionId.Block -> model.reduce(UserDetailMviModel.Intent.Block)
else -> Unit
} }
}, },
) )
@ -482,13 +492,36 @@ class UserDetailScreen(
) )
}, },
options = buildList { options = buildList {
add(stringResource(MR.strings.post_action_share)) add(
add(stringResource(MR.strings.post_action_see_raw)) Option(
add(stringResource(MR.strings.post_action_report)) OptionId.Share,
stringResource(MR.strings.post_action_share)
)
)
add(
Option(
OptionId.SeeRaw,
stringResource(MR.strings.post_action_see_raw)
)
)
if (uiState.currentUserId != null) {
add(
Option(
OptionId.CrossPost,
stringResource(MR.strings.post_action_cross_post)
)
)
add(
Option(
OptionId.Report,
stringResource(MR.strings.post_action_report)
)
)
}
}, },
onOptionSelected = rememberCallbackArgs { optionIdx -> onOptionSelected = rememberCallbackArgs { optionId ->
when (optionIdx) { when (optionId) {
2 -> { OptionId.Report -> {
navigationCoordinator.getBottomNavigator() navigationCoordinator.getBottomNavigator()
?.show( ?.show(
CreateReportScreen( CreateReportScreen(
@ -497,13 +530,22 @@ class UserDetailScreen(
) )
} }
1 -> { OptionId.CrossPost -> {
navigationCoordinator.getBottomNavigator()
?.show(
CreatePostScreen(crossPost = post)
)
}
OptionId.SeeRaw -> {
rawContent = post rawContent = post
} }
else -> model.reduce( OptionId.Share -> model.reduce(
UserDetailMviModel.Intent.SharePost(post.id) UserDetailMviModel.Intent.SharePost(post.id)
) )
else -> Unit
} }
}) })
}, },
@ -653,12 +695,24 @@ class UserDetailScreen(
?.push(CommunityDetailScreen(community)) ?.push(CommunityDetailScreen(community))
}, },
options = buildList { options = buildList {
add(stringResource(MR.strings.post_action_see_raw)) add(
add(stringResource(MR.strings.post_action_report)) Option(
OptionId.SeeRaw,
stringResource(MR.strings.post_action_see_raw)
)
)
if (uiState.currentUserId != null) {
add(
Option(
OptionId.Report,
stringResource(MR.strings.post_action_report)
)
)
}
}, },
onOptionSelected = rememberCallbackArgs { optionId -> onOptionSelected = rememberCallbackArgs { optionId ->
when (optionId) { when (optionId) {
1 -> { OptionId.Report -> {
navigationCoordinator.getBottomNavigator() navigationCoordinator.getBottomNavigator()
?.show( ?.show(
CreateReportScreen( CreateReportScreen(
@ -667,9 +721,11 @@ class UserDetailScreen(
) )
} }
else -> { OptionId.SeeRaw -> {
rawContent = comment rawContent = comment
} }
else -> Unit
} }
}, },
) )

View File

@ -86,6 +86,11 @@ class UserDetailViewModel(
) )
} }
}.launchIn(this) }.launchIn(this)
if (uiState.value.currentUserId == null) {
val auth = identityRepository.authToken.value.orEmpty()
val user = siteRepository.getCurrentUser(auth)
mvi.updateState { it.copy(currentUserId = user?.id ?: 0) }
}
} }
if (uiState.value.posts.isEmpty()) { if (uiState.value.posts.isEmpty()) {
refresh(initial = true) refresh(initial = true)

View File

@ -19,6 +19,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.Navigat
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailMviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateReportMviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateReportMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.saveditems.SavedItemsMviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.saveditems.SavedItemsMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.selectcommunity.SelectCommunityMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailMviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailMviModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
@ -71,10 +72,9 @@ actual fun getCreateCommentViewModel(
CommonUiViewModelHelper.getCreateCommentModel(postId, parentId, editedCommentId) CommonUiViewModelHelper.getCreateCommentModel(postId, parentId, editedCommentId)
actual fun getCreatePostViewModel( actual fun getCreatePostViewModel(
communityId: Int?,
editedPostId: Int?, editedPostId: Int?,
): CreatePostMviModel = ): CreatePostMviModel =
CommonUiViewModelHelper.getCreatePostModel(communityId, editedPostId) CommonUiViewModelHelper.getCreatePostModel(editedPostId)
actual fun getZoomableImageViewModel(): ZoomableImageMviModel = actual fun getZoomableImageViewModel(): ZoomableImageMviModel =
CommonUiViewModelHelper.zoomableImageModel CommonUiViewModelHelper.zoomableImageModel
@ -93,6 +93,9 @@ actual fun getCreateReportViewModel(
commentId: Int?, commentId: Int?,
): CreateReportMviModel = CommonUiViewModelHelper.getCreateReportModel(postId, commentId) ): CreateReportMviModel = CommonUiViewModelHelper.getCreateReportModel(postId, commentId)
actual fun getSelectCommunityViewModel(): SelectCommunityMviModel =
CommonUiViewModelHelper.selectCommunityViewModel
object CommonUiViewModelHelper : KoinComponent { object CommonUiViewModelHelper : KoinComponent {
val navigationCoordinator: NavigationCoordinator by inject() val navigationCoordinator: NavigationCoordinator by inject()
@ -101,6 +104,7 @@ object CommonUiViewModelHelper : KoinComponent {
val zoomableImageModel: ZoomableImageMviModel by inject() val zoomableImageModel: ZoomableImageMviModel by inject()
val savedItemsViewModel: SavedItemsMviModel by inject() val savedItemsViewModel: SavedItemsMviModel by inject()
val modalDrawerViewModel: ModalDrawerMviModel by inject() val modalDrawerViewModel: ModalDrawerMviModel by inject()
val selectCommunityViewModel: SelectCommunityMviModel by inject()
fun getPostDetailModel( fun getPostDetailModel(
post: PostModel, post: PostModel,
@ -155,9 +159,9 @@ object CommonUiViewModelHelper : KoinComponent {
return model return model
} }
fun getCreatePostModel(communityId: Int?, editedPostId: Int?): CreatePostMviModel { fun getCreatePostModel(editedPostId: Int?): CreatePostMviModel {
val model: CreatePostMviModel by inject( val model: CreatePostMviModel by inject(
parameters = { parametersOf(communityId, editedPostId) } parameters = { parametersOf(editedPostId) }
) )
return model return model
} }

View File

@ -22,4 +22,5 @@ object NotificationCenterContractKeys {
const val MultiCommunityCreated = "multiCommunityCreated" const val MultiCommunityCreated = "multiCommunityCreated"
const val ResetContents = "resetContents" const val ResetContents = "resetContents"
const val CloseDialog = "closeDialog" const val CloseDialog = "closeDialog"
const val SelectCommunity = "selectCommunity"
} }

View File

@ -60,6 +60,8 @@ import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycl
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreen
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenu import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenu
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenuItem import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenuItem
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Option
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.OptionId
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCardPlaceholder import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCardPlaceholder
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SwipeableCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SwipeableCard
@ -247,6 +249,7 @@ class PostListScreen : Screen {
} }
}, },
) )
if (uiState.currentUserId != null) {
this += FloatingActionButtonMenuItem( this += FloatingActionButtonMenuItem(
icon = Icons.Default.ClearAll, icon = Icons.Default.ClearAll,
text = stringResource(MR.strings.action_clear_read), text = stringResource(MR.strings.action_clear_read),
@ -258,6 +261,7 @@ class PostListScreen : Screen {
}, },
) )
} }
}
) )
} }
} }
@ -403,44 +407,97 @@ class PostListScreen : Screen {
) )
}, },
options = buildList { options = buildList {
add(stringResource(MR.strings.post_action_share)) add(
add(stringResource(MR.strings.post_action_hide)) Option(
add(stringResource(MR.strings.post_action_see_raw)) OptionId.Share,
add(stringResource(MR.strings.post_action_report)) stringResource(MR.strings.post_action_share)
)
)
if (uiState.currentUserId != null) {
add(
Option(
OptionId.Hide,
stringResource(MR.strings.post_action_hide)
)
)
}
add(
Option(
OptionId.SeeRaw,
stringResource(MR.strings.post_action_see_raw)
)
)
if (uiState.currentUserId != null) {
add(
Option(
OptionId.CrossPost,
stringResource(MR.strings.post_action_cross_post)
)
)
add(
Option(
OptionId.Report,
stringResource(MR.strings.post_action_report)
)
)
}
if (post.creator?.id == uiState.currentUserId) { if (post.creator?.id == uiState.currentUserId) {
add(stringResource(MR.strings.post_action_edit)) add(
add(stringResource(MR.strings.comment_action_delete)) Option(
OptionId.Edit,
stringResource(MR.strings.post_action_edit)
)
)
add(
Option(
OptionId.Delete,
stringResource(MR.strings.comment_action_delete)
)
)
} }
}, },
onOptionSelected = rememberCallbackArgs(model) { optionIdx -> onOptionSelected = rememberCallbackArgs(model) { optinId ->
when (optionIdx) { when (optinId) {
5 -> model.reduce( OptionId.Delete -> model.reduce(
PostListMviModel.Intent.DeletePost(post.id) PostListMviModel.Intent.DeletePost(post.id)
) )
4 -> { OptionId.Edit -> {
navigationCoordinator.getBottomNavigator() navigationCoordinator.getBottomNavigator()
?.show( ?.show(
CreatePostScreen(editedPost = post) CreatePostScreen(editedPost = post)
) )
} }
3 -> { OptionId.Report -> {
navigationCoordinator.getBottomNavigator() navigationCoordinator.getBottomNavigator()
?.show( ?.show(
CreateReportScreen(postId = post.id) CreateReportScreen(postId = post.id)
) )
} }
2 -> { OptionId.CrossPost -> {
navigationCoordinator.getBottomNavigator()
?.show(
CreatePostScreen(crossPost = post)
)
}
OptionId.SeeRaw -> {
rawContent = post rawContent = post
} }
1 -> model.reduce(PostListMviModel.Intent.Hide(post.id)) OptionId.Hide -> model.reduce(
PostListMviModel.Intent.Hide(
post.id
)
)
else -> model.reduce( OptionId.Share -> model.reduce(
PostListMviModel.Intent.SharePost(post.id) PostListMviModel.Intent.SharePost(post.id)
) )
else -> Unit
} }
} }
) )

View File

@ -17,7 +17,7 @@ import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.unit.dp import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.IconSize
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback
@ -70,7 +70,7 @@ internal fun PostsTopBar(
} }
else -> { else -> {
Box(modifier = Modifier.size(24.dp)) Box(modifier = Modifier.size(IconSize.m))
} }
} }
}, },

View File

@ -19,6 +19,7 @@ import androidx.compose.ui.graphics.FilterQuality
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.IconSize
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CustomImage import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CustomImage
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PlaceholderImage import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PlaceholderImage
@ -118,7 +119,7 @@ internal fun ChatCard(
horizontalArrangement = Arrangement.spacedBy(Spacing.xxs), horizontalArrangement = Arrangement.spacedBy(Spacing.xxs),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
val buttonModifier = Modifier.size(24.dp).padding(3.25.dp) val buttonModifier = Modifier.size(IconSize.m).padding(3.25.dp)
Icon( Icon(
modifier = buttonModifier.padding(1.dp), modifier = buttonModifier.padding(1.dp),
imageVector = Icons.Default.Schedule, imageVector = Icons.Default.Schedule,

View File

@ -42,6 +42,8 @@ import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycl
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreen
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CommentCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CommentCard
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CommentCardPlaceholder import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CommentCardPlaceholder
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Option
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.OptionId
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCardPlaceholder import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCardPlaceholder
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SectionSelector import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SectionSelector
@ -230,18 +232,38 @@ internal object ProfileLoggedScreen : Tab {
) )
}, },
options = buildList { options = buildList {
add(stringResource(MR.strings.post_action_share)) add(
add(stringResource(MR.strings.post_action_see_raw)) Option(
add(stringResource(MR.strings.post_action_edit)) OptionId.Share,
add(stringResource(MR.strings.comment_action_delete)) stringResource(MR.strings.post_action_share)
)
)
add(
Option(
OptionId.SeeRaw,
stringResource(MR.strings.post_action_see_raw)
)
)
add(
Option(
OptionId.Edit,
stringResource(MR.strings.post_action_edit)
)
)
add(
Option(
OptionId.Delete,
stringResource(MR.strings.comment_action_delete)
)
)
}, },
onOptionSelected = rememberCallbackArgs(model) { optionIdx -> onOptionSelected = rememberCallbackArgs(model) { optionId ->
when (optionIdx) { when (optionId) {
3 -> model.reduce( OptionId.Delete -> model.reduce(
ProfileLoggedMviModel.Intent.DeletePost(post.id) ProfileLoggedMviModel.Intent.DeletePost(post.id)
) )
2 -> { OptionId.Edit -> {
navigationCoordinator.getBottomNavigator()?.show( navigationCoordinator.getBottomNavigator()?.show(
CreatePostScreen( CreatePostScreen(
editedPost = post, editedPost = post,
@ -249,13 +271,15 @@ internal object ProfileLoggedScreen : Tab {
) )
} }
1 -> { OptionId.SeeRaw -> {
rawContent = post rawContent = post
} }
else -> model.reduce( OptionId.Share -> model.reduce(
ProfileLoggedMviModel.Intent.SharePost(post.id) ProfileLoggedMviModel.Intent.SharePost(post.id)
) )
else -> Unit
} }
}, },
) )
@ -330,13 +354,28 @@ internal object ProfileLoggedScreen : Tab {
) )
}, },
options = buildList { options = buildList {
add(stringResource(MR.strings.post_action_see_raw)) add(
add(stringResource(MR.strings.post_action_edit)) Option(
add(stringResource(MR.strings.comment_action_delete)) OptionId.SeeRaw,
stringResource(MR.strings.post_action_see_raw)
)
)
add(
Option(
OptionId.Edit,
stringResource(MR.strings.post_action_edit)
)
)
add(
Option(
OptionId.Delete,
stringResource(MR.strings.comment_action_delete)
)
)
}, },
onOptionSelected = rememberCallbackArgs(model) { optionIdx -> onOptionSelected = rememberCallbackArgs(model) { optionId ->
when (optionIdx) { when (optionId) {
2 -> { OptionId.Delete -> {
model.reduce( model.reduce(
ProfileLoggedMviModel.Intent.DeleteComment( ProfileLoggedMviModel.Intent.DeleteComment(
comment.id comment.id
@ -344,7 +383,7 @@ internal object ProfileLoggedScreen : Tab {
) )
} }
1 -> { OptionId.Edit -> {
navigationCoordinator.getBottomNavigator()?.show( navigationCoordinator.getBottomNavigator()?.show(
CreateCommentScreen( CreateCommentScreen(
editedComment = comment, editedComment = comment,
@ -352,9 +391,11 @@ internal object ProfileLoggedScreen : Tab {
) )
} }
else -> { OptionId.SeeRaw -> {
rawContent = comment rawContent = comment
} }
else -> Unit
} }
} }
) )

View File

@ -46,6 +46,7 @@ val exploreTabModule = module {
community = params[0], community = params[0],
postRepository = get(), postRepository = get(),
identityRepository = get(), identityRepository = get(),
siteRepository = get(),
themeRepository = get(), themeRepository = get(),
shareHelper = get(), shareHelper = get(),
settingsRepository = get(), settingsRepository = get(),

View File

@ -17,7 +17,7 @@ import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.unit.dp import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.IconSize
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback
@ -69,7 +69,7 @@ internal fun ExploreTopBar(
} }
else -> { else -> {
Box(modifier = Modifier.size(24.dp)) Box(modifier = Modifier.size(IconSize.m))
} }
} }
}, },

View File

@ -24,6 +24,7 @@ interface MultiCommunityMviModel :
} }
data class UiState( data class UiState(
val currentUserId: Int? = null,
val refreshing: Boolean = false, val refreshing: Boolean = false,
val loading: Boolean = false, val loading: Boolean = false,
val canFetchMore: Boolean = true, val canFetchMore: Boolean = true,

View File

@ -61,6 +61,8 @@ import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycl
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreen
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenu import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenu
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenuItem import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenuItem
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Option
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.OptionId
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCardPlaceholder import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCardPlaceholder
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SwipeableCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SwipeableCard
@ -375,13 +377,30 @@ class MultiCommunityScreen(
) )
}, },
options = buildList { options = buildList {
add(stringResource(MR.strings.post_action_share)) add(
add(stringResource(MR.strings.post_action_hide)) Option(
add(stringResource(MR.strings.post_action_report)) OptionId.Share,
stringResource(MR.strings.post_action_share)
)
)
if (uiState.currentUserId != null) {
add(
Option(
OptionId.Hide,
stringResource(MR.strings.post_action_hide)
)
)
add(
Option(
OptionId.Report,
stringResource(MR.strings.post_action_report)
)
)
}
}, },
onOptionSelected = { optionIdx -> onOptionSelected = { optionId ->
when (optionIdx) { when (optionId) {
2 -> { OptionId.Report -> {
navigationCoordinator.getBottomNavigator()?.show( navigationCoordinator.getBottomNavigator()?.show(
CreateReportScreen( CreateReportScreen(
postId = post.id postId = post.id
@ -389,15 +408,17 @@ class MultiCommunityScreen(
) )
} }
1 -> model.reduce( OptionId.Hide -> model.reduce(
MultiCommunityMviModel.Intent.Hide( MultiCommunityMviModel.Intent.Hide(
post.id post.id
) )
) )
else -> model.reduce( OptionId.Share -> model.reduce(
MultiCommunityMviModel.Intent.SharePost(post.id) MultiCommunityMviModel.Intent.SharePost(post.id)
) )
else -> Unit
} }
} }
) )

View File

@ -17,6 +17,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.imageUrl
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.shareUrl import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.shareUrl
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.toSortType import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.toSortType
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostRepository import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostRepository
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.SiteRepository
import com.github.diegoberaldin.raccoonforlemmy.feature.search.multicommunity.utils.MultiCommunityPaginator import com.github.diegoberaldin.raccoonforlemmy.feature.search.multicommunity.utils.MultiCommunityPaginator
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO import kotlinx.coroutines.IO
@ -29,6 +30,7 @@ class MultiCommunityViewModel(
private val community: MultiCommunityModel, private val community: MultiCommunityModel,
private val postRepository: PostRepository, private val postRepository: PostRepository,
private val identityRepository: IdentityRepository, private val identityRepository: IdentityRepository,
private val siteRepository: SiteRepository,
private val themeRepository: ThemeRepository, private val themeRepository: ThemeRepository,
private val shareHelper: ShareHelper, private val shareHelper: ShareHelper,
private val settingsRepository: SettingsRepository, private val settingsRepository: SettingsRepository,
@ -72,6 +74,11 @@ class MultiCommunityViewModel(
) )
} }
}.launchIn(this) }.launchIn(this)
if (uiState.value.currentUserId == null) {
val auth = identityRepository.authToken.value.orEmpty()
val user = siteRepository.getCurrentUser(auth)
mvi.updateState { it.copy(currentUserId = user?.id ?: 0) }
}
} }
mvi.scope?.launch(Dispatchers.IO) { mvi.scope?.launch(Dispatchers.IO) {

View File

@ -11,7 +11,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.IconSize
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
@Composable @Composable
@ -32,7 +32,7 @@ internal fun SettingsHeader(
) { ) {
if (icon != null) { if (icon != null) {
Icon( Icon(
modifier = Modifier.size(24.dp), modifier = Modifier.size(IconSize.m),
imageVector = icon, imageVector = icon,
contentDescription = null, contentDescription = null,
) )

View File

@ -26,6 +26,8 @@
<string name="create_comment_body">Comment body</string> <string name="create_comment_body">Comment body</string>
<string name="create_comment_title">New comment</string> <string name="create_comment_title">New comment</string>
<string name="create_post_body">Post body</string> <string name="create_post_body">Post body</string>
<string name="create_post_community">Community</string>
<string name="create_post_cross_post_text">Cross posted from:</string>
<string name="create_post_name">Post title</string> <string name="create_post_name">Post title</string>
<string name="create_post_nsfw">NSFW</string> <string name="create_post_nsfw">NSFW</string>
<string name="create_post_tab_editor">Editor</string> <string name="create_post_tab_editor">Editor</string>
@ -40,6 +42,7 @@
<string name="dialog_raw_content_url">URL</string> <string name="dialog_raw_content_url">URL</string>
<string name="dialog_title_change_instance">Change instance</string> <string name="dialog_title_change_instance">Change instance</string>
<string name="dialog_title_raw_content">Raw content</string> <string name="dialog_title_raw_content">Raw content</string>
<string name="dialog_title_select_community">Select a community</string>
<string name="explore_result_type_all">All</string> <string name="explore_result_type_all">All</string>
<string name="explore_result_type_comments">Comments</string> <string name="explore_result_type_comments">Comments</string>
<string name="explore_result_type_communities">Communities</string> <string name="explore_result_type_communities">Communities</string>
@ -131,7 +134,8 @@
<string name="navigation_profile">Profile</string> <string name="navigation_profile">Profile</string>
<string name="navigation_search">Explore</string> <string name="navigation_search">Explore</string>
<string name="navigation_settings">Settings</string> <string name="navigation_settings">Settings</string>
<string name="post_action_edit">Edit</string> <string name="post_action_cross_post">Cross-post…</string>
<string name="post_action_edit">Edit…</string>
<string name="post_action_hide">Hide</string> <string name="post_action_hide">Hide</string>
<string name="post_action_report">Report…</string> <string name="post_action_report">Report…</string>
<string name="post_action_see_raw">View raw…</string> <string name="post_action_see_raw">View raw…</string>

View File

@ -26,6 +26,8 @@
<string name="create_comment_body">Kommentartext</string> <string name="create_comment_body">Kommentartext</string>
<string name="create_comment_title">Neuer Kommentar</string> <string name="create_comment_title">Neuer Kommentar</string>
<string name="create_post_body">Beitragstext</string> <string name="create_post_body">Beitragstext</string>
<string name="create_post_community">Community</string>
<string name="create_post_cross_post_text">Cross-gepostet von:</string>
<string name="create_post_name">Beitragstitel</string> <string name="create_post_name">Beitragstitel</string>
<string name="create_post_nsfw">NSFW</string> <string name="create_post_nsfw">NSFW</string>
<string name="create_post_tab_editor">Redakteur</string> <string name="create_post_tab_editor">Redakteur</string>
@ -40,6 +42,7 @@
<string name="dialog_raw_content_url">URL</string> <string name="dialog_raw_content_url">URL</string>
<string name="dialog_title_change_instance">Instanz ändern</string> <string name="dialog_title_change_instance">Instanz ändern</string>
<string name="dialog_title_raw_content">Rohinhalt</string> <string name="dialog_title_raw_content">Rohinhalt</string>
<string name="dialog_title_select_community">Wählen Sie eine Community aus</string>
<string name="explore_result_type_all">Alle</string> <string name="explore_result_type_all">Alle</string>
<string name="explore_result_type_comments">Kommentare</string> <string name="explore_result_type_comments">Kommentare</string>
<string name="explore_result_type_communities">Communitys</string> <string name="explore_result_type_communities">Communitys</string>
@ -124,7 +127,8 @@
<string name="navigation_profile">Profil</string> <string name="navigation_profile">Profil</string>
<string name="navigation_search">Erkunden</string> <string name="navigation_search">Erkunden</string>
<string name="navigation_settings">Einstellungen</string> <string name="navigation_settings">Einstellungen</string>
<string name="post_action_edit">Bearbeiten</string> <string name="post_action_cross_post">Cross-post</string>
<string name="post_action_edit">Bearbeiten…</string>
<string name="post_action_hide">Verstecken</string> <string name="post_action_hide">Verstecken</string>
<string name="post_action_report">Bericht…</string> <string name="post_action_report">Bericht…</string>
<string name="post_action_see_raw">Roh ansehen…</string> <string name="post_action_see_raw">Roh ansehen…</string>

View File

@ -24,6 +24,8 @@
<string name="community_info_subscribers">συνδρομητές</string> <string name="community_info_subscribers">συνδρομητές</string>
<string name="community_info_weekly_active_users">ενεργοί χρήστες (εβδομάδα)</string> <string name="community_info_weekly_active_users">ενεργοί χρήστες (εβδομάδα)</string>
<string name="create_comment_body">Κείμενο σχολίου</string> <string name="create_comment_body">Κείμενο σχολίου</string>
<string name="create_post_community">Κοινότητα</string>
<string name="create_post_cross_post_text">Διασταυρούμενη από:</string>
<string name="create_comment_title">Νέο σχόλιο</string> <string name="create_comment_title">Νέο σχόλιο</string>
<string name="create_post_body">Κείμενο ανάρτησης</string> <string name="create_post_body">Κείμενο ανάρτησης</string>
<string name="create_post_name">Τίτλος ανάρτησης</string> <string name="create_post_name">Τίτλος ανάρτησης</string>
@ -40,6 +42,7 @@
<string name="dialog_raw_content_url">URL</string> <string name="dialog_raw_content_url">URL</string>
<string name="dialog_title_change_instance">Αλλαγή παραδείγματος</string> <string name="dialog_title_change_instance">Αλλαγή παραδείγματος</string>
<string name="dialog_title_raw_content">Ακατέργαστο περιεχόμενο</string> <string name="dialog_title_raw_content">Ακατέργαστο περιεχόμενο</string>
<string name="dialog_title_select_community">Επιλέξε μια κοινότητα</string>
<string name="explore_result_type_all">Όλα</string> <string name="explore_result_type_all">Όλα</string>
<string name="explore_result_type_comments">Σχόλια</string> <string name="explore_result_type_comments">Σχόλια</string>
<string name="explore_result_type_communities">Κοινότητες</string> <string name="explore_result_type_communities">Κοινότητες</string>
@ -124,11 +127,12 @@
<string name="navigation_profile">Προφίλ</string> <string name="navigation_profile">Προφίλ</string>
<string name="navigation_search">Εξερεύνηση</string> <string name="navigation_search">Εξερεύνηση</string>
<string name="navigation_settings">Ρυθμίσεις</string> <string name="navigation_settings">Ρυθμίσεις</string>
<string name="post_action_edit">Επεξεργασία</string> <string name="post_action_cross_post">Διασταύρωσε ανάρτηση…</string>
<string name="post_action_hide">Απόκρυψη</string> <string name="post_action_edit">Επεξεργασία…</string>
<string name="post_action_report">Αναφορά…</string> <string name="post_action_hide">Απόκρυψε</string>
<string name="post_action_report">Αναφόρησε…</string>
<string name="post_action_see_raw">Προβολή ακατέργαστου…</string> <string name="post_action_see_raw">Προβολή ακατέργαστου…</string>
<string name="post_action_share">Κοινοποίηση</string> <string name="post_action_share">Κοινοποίησε</string>
<string name="post_detail_cross_posts">επίσης αναρτήθηκε σε:</string> <string name="post_detail_cross_posts">επίσης αναρτήθηκε σε:</string>
<string name="post_detail_load_more_comments">Φόρτωση περισσότερων σχολίων…</string> <string name="post_detail_load_more_comments">Φόρτωση περισσότερων σχολίων…</string>
<string name="post_hour_short">ώρ</string> <string name="post_hour_short">ώρ</string>

View File

@ -26,6 +26,8 @@
<string name="create_comment_body">Texto comentario</string> <string name="create_comment_body">Texto comentario</string>
<string name="create_comment_title">Nuevo comentario</string> <string name="create_comment_title">Nuevo comentario</string>
<string name="create_post_body">Texto publicación</string> <string name="create_post_body">Texto publicación</string>
<string name="create_post_community">Comunidad</string>
<string name="create_post_cross_post_text">Publicación cruzada desde:</string>
<string name="create_post_name">Título publicación</string> <string name="create_post_name">Título publicación</string>
<string name="create_post_nsfw">NSFW</string> <string name="create_post_nsfw">NSFW</string>
<string name="create_post_tab_editor">Editor</string> <string name="create_post_tab_editor">Editor</string>
@ -40,6 +42,7 @@
<string name="dialog_raw_content_url">URL</string> <string name="dialog_raw_content_url">URL</string>
<string name="dialog_title_change_instance">Cambiar de instancia</string> <string name="dialog_title_change_instance">Cambiar de instancia</string>
<string name="dialog_title_raw_content">Contenido raw</string> <string name="dialog_title_raw_content">Contenido raw</string>
<string name="dialog_title_select_community">Seleccionar una comunidad</string>
<string name="explore_result_type_all">Todos</string> <string name="explore_result_type_all">Todos</string>
<string name="explore_result_type_comments">Comentarios</string> <string name="explore_result_type_comments">Comentarios</string>
<string name="explore_result_type_communities">Comunidades</string> <string name="explore_result_type_communities">Comunidades</string>
@ -124,7 +127,8 @@
<string name="navigation_profile">Perfil</string> <string name="navigation_profile">Perfil</string>
<string name="navigation_search">Descubre</string> <string name="navigation_search">Descubre</string>
<string name="navigation_settings">Ajustes</string> <string name="navigation_settings">Ajustes</string>
<string name="post_action_edit">Modificar</string> <string name="post_action_cross_post">Publicación cruzada…</string>
<string name="post_action_edit">Modificar…</string>
<string name="post_action_hide">Esconder</string> <string name="post_action_hide">Esconder</string>
<string name="post_action_report">Crear informe…</string> <string name="post_action_report">Crear informe…</string>
<string name="post_action_see_raw">Ver raw…</string> <string name="post_action_see_raw">Ver raw…</string>

View File

@ -26,6 +26,8 @@
<string name="create_comment_body">Texte du commentaire</string> <string name="create_comment_body">Texte du commentaire</string>
<string name="create_comment_title">Nouveau commentaire</string> <string name="create_comment_title">Nouveau commentaire</string>
<string name="create_post_body">Texte de la publication</string> <string name="create_post_body">Texte de la publication</string>
<string name="create_post_community">Communauté</string>
<string name="create_post_cross_post_text">Publication croisée à partir de:</string>
<string name="create_post_name">Titre de la publication</string> <string name="create_post_name">Titre de la publication</string>
<string name="create_post_nsfw">NSFW</string> <string name="create_post_nsfw">NSFW</string>
<string name="create_post_tab_editor">Éditeur</string> <string name="create_post_tab_editor">Éditeur</string>
@ -40,6 +42,7 @@
<string name="dialog_raw_content_url">URL</string> <string name="dialog_raw_content_url">URL</string>
<string name="dialog_title_change_instance">Changer d\'instance</string> <string name="dialog_title_change_instance">Changer d\'instance</string>
<string name="dialog_title_raw_content">Contenu brut</string> <string name="dialog_title_raw_content">Contenu brut</string>
<string name="dialog_title_select_community">Sélectionner une communauté</string>
<string name="explore_result_type_all">Tous</string> <string name="explore_result_type_all">Tous</string>
<string name="explore_result_type_comments">Commentaires</string> <string name="explore_result_type_comments">Commentaires</string>
<string name="explore_result_type_communities">Communautés</string> <string name="explore_result_type_communities">Communautés</string>
@ -124,7 +127,8 @@
<string name="navigation_profile">Profil</string> <string name="navigation_profile">Profil</string>
<string name="navigation_search">Explorer</string> <string name="navigation_search">Explorer</string>
<string name="navigation_settings">Réglages</string> <string name="navigation_settings">Réglages</string>
<string name="post_action_edit">Éditer</string> <string name="post_action_cross_post">Publication croisée…</string>
<string name="post_action_edit">Éditer…</string>
<string name="post_action_hide">Cacher</string> <string name="post_action_hide">Cacher</string>
<string name="post_action_report">Signaler</string> <string name="post_action_report">Signaler</string>
<string name="post_action_see_raw">Voir brut…</string> <string name="post_action_see_raw">Voir brut…</string>

View File

@ -26,6 +26,8 @@
<string name="create_comment_body">Testo commento</string> <string name="create_comment_body">Testo commento</string>
<string name="create_comment_title">Nuovo commento</string> <string name="create_comment_title">Nuovo commento</string>
<string name="create_post_body">Testo post</string> <string name="create_post_body">Testo post</string>
<string name="create_post_community">Comunità</string>
<string name="create_post_cross_post_text">Cross-post da:</string>
<string name="create_post_name">Titolo post</string> <string name="create_post_name">Titolo post</string>
<string name="create_post_nsfw">NSFW</string> <string name="create_post_nsfw">NSFW</string>
<string name="create_post_tab_editor">Editor</string> <string name="create_post_tab_editor">Editor</string>
@ -40,6 +42,7 @@
<string name="dialog_raw_content_url">URL</string> <string name="dialog_raw_content_url">URL</string>
<string name="dialog_title_change_instance">Cambia istanza</string> <string name="dialog_title_change_instance">Cambia istanza</string>
<string name="dialog_title_raw_content">Contenuto grezzo</string> <string name="dialog_title_raw_content">Contenuto grezzo</string>
<string name="dialog_title_select_community">Seleziona comunità</string>
<string name="explore_result_type_all">Tutti</string> <string name="explore_result_type_all">Tutti</string>
<string name="explore_result_type_comments">Commenti</string> <string name="explore_result_type_comments">Commenti</string>
<string name="explore_result_type_communities">Comunità</string> <string name="explore_result_type_communities">Comunità</string>
@ -124,7 +127,8 @@
<string name="navigation_profile">Profilo</string> <string name="navigation_profile">Profilo</string>
<string name="navigation_search">Esplora</string> <string name="navigation_search">Esplora</string>
<string name="navigation_settings">Impostazioni</string> <string name="navigation_settings">Impostazioni</string>
<string name="post_action_edit">Modifica</string> <string name="post_action_cross_post">Cross-post…</string>
<string name="post_action_edit">Modifica…</string>
<string name="post_action_hide">Nascondi</string> <string name="post_action_hide">Nascondi</string>
<string name="post_action_report">Segnala…</string> <string name="post_action_report">Segnala…</string>
<string name="post_action_see_raw">Vedi raw…</string> <string name="post_action_see_raw">Vedi raw…</string>

View File

@ -23,8 +23,10 @@
<string name="community_info_posts">berichten</string> <string name="community_info_posts">berichten</string>
<string name="community_info_subscribers">abonnees</string> <string name="community_info_subscribers">abonnees</string>
<string name="community_info_weekly_active_users">actieve gebruikers (week)</string> <string name="community_info_weekly_active_users">actieve gebruikers (week)</string>
<string name="create_comment_body">Reactie body</string> <string name="create_comment_body">Commentaar body</string>
<string name="create_comment_title">Nieuwe opmerking</string> <string name="create_post_community">Gemeenschap</string>
<string name="create_post_cross_post_text">Crosspost van:</string>
<string name="create_comment_title">Nieuw commentaar</string>
<string name="create_post_body">Bericht body</string> <string name="create_post_body">Bericht body</string>
<string name="create_post_name">Bericht titel</string> <string name="create_post_name">Bericht titel</string>
<string name="create_post_nsfw">NSFW</string> <string name="create_post_nsfw">NSFW</string>
@ -40,6 +42,7 @@
<string name="dialog_raw_content_url">URL</string> <string name="dialog_raw_content_url">URL</string>
<string name="dialog_title_change_instance">Instantie wijzigen</string> <string name="dialog_title_change_instance">Instantie wijzigen</string>
<string name="dialog_title_raw_content">Content</string> <string name="dialog_title_raw_content">Content</string>
<string name="dialog_title_select_community">Selecteer een gemeenschap</string>
<string name="explore_result_type_all">Alle</string> <string name="explore_result_type_all">Alle</string>
<string name="explore_result_type_comments">Opmerkingen</string> <string name="explore_result_type_comments">Opmerkingen</string>
<string name="explore_result_type_communities">Samenleving</string> <string name="explore_result_type_communities">Samenleving</string>
@ -132,13 +135,14 @@
<string name="navigation_profile">Profiel</string> <string name="navigation_profile">Profiel</string>
<string name="navigation_search">Ontdekken</string> <string name="navigation_search">Ontdekken</string>
<string name="navigation_settings">Instellingen</string> <string name="navigation_settings">Instellingen</string>
<string name="post_action_edit">Bewerk</string> <string name="post_action_cross_post">Crosspost…</string>
<string name="post_action_edit">Bewerk…</string>
<string name="post_action_hide">Verbergen</string> <string name="post_action_hide">Verbergen</string>
<string name="post_action_report">Verslag</string> <string name="post_action_report">Verslag</string>
<string name="post_action_see_raw">Toon raw</string> <string name="post_action_see_raw">Toon raw</string>
<string name="post_action_share">Delen</string> <string name="post_action_share">Delen</string>
<string name="post_detail_cross_posts">ook geplaatst op:</string> <string name="post_detail_cross_posts">ook geplaatst op:</string>
<string name="post_detail_load_more_comments">Meer reacties laden</string> <string name="post_detail_load_more_comments">Meer reacties laden</string>
<string name="post_hour_short">u</string> <string name="post_hour_short">u</string>
<string name="post_minute_short">m</string> <string name="post_minute_short">m</string>
<string name="post_second_short">s</string> <string name="post_second_short">s</string>

View File

@ -26,6 +26,8 @@
<string name="create_comment_body">Texto do comentário</string> <string name="create_comment_body">Texto do comentário</string>
<string name="create_comment_title">Novo comentário</string> <string name="create_comment_title">Novo comentário</string>
<string name="create_post_body">Texto da publicação</string> <string name="create_post_body">Texto da publicação</string>
<string name="create_post_community">Comunidade</string>
<string name="create_post_cross_post_text">Publicação cruzada de:</string>
<string name="create_post_name">Título da publicação</string> <string name="create_post_name">Título da publicação</string>
<string name="create_post_nsfw">NSFW</string> <string name="create_post_nsfw">NSFW</string>
<string name="create_post_tab_editor">Editor</string> <string name="create_post_tab_editor">Editor</string>
@ -40,6 +42,7 @@
<string name="dialog_raw_content_url">URL</string> <string name="dialog_raw_content_url">URL</string>
<string name="dialog_title_change_instance">Mudar instância</string> <string name="dialog_title_change_instance">Mudar instância</string>
<string name="dialog_title_raw_content">Conteúdo bruto</string> <string name="dialog_title_raw_content">Conteúdo bruto</string>
<string name="dialog_title_select_community">Selecionar uma comunidade</string>
<string name="explore_result_type_all">Todos</string> <string name="explore_result_type_all">Todos</string>
<string name="explore_result_type_comments">Comentários</string> <string name="explore_result_type_comments">Comentários</string>
<string name="explore_result_type_communities">Comunidades</string> <string name="explore_result_type_communities">Comunidades</string>
@ -122,7 +125,8 @@
<string name="navigation_profile">Perfil</string> <string name="navigation_profile">Perfil</string>
<string name="navigation_search">Explorar</string> <string name="navigation_search">Explorar</string>
<string name="navigation_settings">Configurações</string> <string name="navigation_settings">Configurações</string>
<string name="post_action_edit">Modificar</string> <string name="post_action_cross_post">Publicação cruzada…</string>
<string name="post_action_edit">Modificar…</string>
<string name="post_action_hide">Esconder</string> <string name="post_action_hide">Esconder</string>
<string name="post_action_report">Denunciar…</string> <string name="post_action_report">Denunciar…</string>
<string name="post_action_see_raw">Ver conteúdo bruto</string> <string name="post_action_see_raw">Ver conteúdo bruto</string>

View File

@ -26,6 +26,8 @@
<string name="create_comment_body">Text comentariului</string> <string name="create_comment_body">Text comentariului</string>
<string name="create_comment_title">Nou comentariu</string> <string name="create_comment_title">Nou comentariu</string>
<string name="create_post_body">Text postării</string> <string name="create_post_body">Text postării</string>
<string name="create_post_community">Community</string>
<string name="create_post_cross_post_text">Postare încrucișată din:</string>
<string name="create_post_name">Titlu postării</string> <string name="create_post_name">Titlu postării</string>
<string name="create_post_nsfw">NSFW</string> <string name="create_post_nsfw">NSFW</string>
<string name="create_post_tab_editor">Editor</string> <string name="create_post_tab_editor">Editor</string>
@ -40,6 +42,7 @@
<string name="dialog_raw_content_url">URL</string> <string name="dialog_raw_content_url">URL</string>
<string name="dialog_title_change_instance">Schimbă instanță</string> <string name="dialog_title_change_instance">Schimbă instanță</string>
<string name="dialog_title_raw_content">Conținut brut</string> <string name="dialog_title_raw_content">Conținut brut</string>
<string name="dialog_title_select_community">Selectează comunitate</string>
<string name="explore_result_type_all">Toate</string> <string name="explore_result_type_all">Toate</string>
<string name="explore_result_type_comments">Comentarii</string> <string name="explore_result_type_comments">Comentarii</string>
<string name="explore_result_type_communities">Comunități</string> <string name="explore_result_type_communities">Comunități</string>
@ -123,10 +126,11 @@
<string name="navigation_profile">Profil</string> <string name="navigation_profile">Profil</string>
<string name="navigation_search">Exploră</string> <string name="navigation_search">Exploră</string>
<string name="navigation_settings">Setări</string> <string name="navigation_settings">Setări</string>
<string name="post_action_edit">Editează</string> <string name="post_action_cross_post">Postare încrucișată…</string>
<string name="post_action_edit">Editează…</string>
<string name="post_action_hide">Ascunde</string> <string name="post_action_hide">Ascunde</string>
<string name="post_action_report">Reportează…</string> <string name="post_action_report">Reportează…</string>
<string name="post_action_see_raw">Vizualizare bruta</string> <string name="post_action_see_raw">Vizualizare brută</string>
<string name="post_action_share">Partajează…</string> <string name="post_action_share">Partajează…</string>
<string name="post_detail_cross_posts">postat și în:</string> <string name="post_detail_cross_posts">postat și în:</string>
<string name="post_detail_load_more_comments">Încărcă mai multe comentări…</string> <string name="post_detail_load_more_comments">Încărcă mai multe comentări…</string>