feat: report post and comments
This commit is contained in:
parent
42b1ef5a9a
commit
745755ff88
@ -0,0 +1,17 @@
|
|||||||
|
package com.github.diegoberaldin.raccoonforlemmy.core.api.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class CommentReport(
|
||||||
|
@SerialName("id") val id: CommentReportId,
|
||||||
|
@SerialName("creator_id") val creatorId: PersonId,
|
||||||
|
@SerialName("comment_id") val commentId: CommentId,
|
||||||
|
@SerialName("original_comment_text") val originalCommentText: String,
|
||||||
|
@SerialName("reason") val reason: String,
|
||||||
|
@SerialName("resolved") val resolved: Boolean,
|
||||||
|
@SerialName("resolver_id") val resolverId: PersonId? = null,
|
||||||
|
@SerialName("published") val published: String,
|
||||||
|
@SerialName("updated") val updated: String? = null,
|
||||||
|
)
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.github.diegoberaldin.raccoonforlemmy.core.api.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class CommentReportResponse(
|
||||||
|
@SerialName("comment_report_view") val commentReportView: CommentReportView,
|
||||||
|
)
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.github.diegoberaldin.raccoonforlemmy.core.api.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class CommentReportView(
|
||||||
|
@SerialName("comment_report") val commentReport: CommentReport,
|
||||||
|
@SerialName("comment") val comment: Comment,
|
||||||
|
@SerialName("post") val post: Post,
|
||||||
|
@SerialName("community") val community: Community,
|
||||||
|
@SerialName("creator") val creator: Person,
|
||||||
|
@SerialName("comment_creator") val commentCreator: Person,
|
||||||
|
@SerialName("counts") val counts: CommentAggregates,
|
||||||
|
@SerialName("creator_banned_from_community") val creatorBannedFromCommunity: Boolean,
|
||||||
|
@SerialName("my_vote") val myVote: Int? = null,
|
||||||
|
@SerialName("resolver") val resolver: Person? = null,
|
||||||
|
)
|
@ -12,4 +12,6 @@ typealias LocalUserId = Int
|
|||||||
typealias CustomEmojiId = Int
|
typealias CustomEmojiId = Int
|
||||||
typealias PersonMentionId = Int
|
typealias PersonMentionId = Int
|
||||||
typealias CommentReplyId = Int
|
typealias CommentReplyId = Int
|
||||||
|
typealias CommentReportId = Int
|
||||||
|
typealias PostReportId = Int
|
||||||
typealias PrivateMessageId = Int
|
typealias PrivateMessageId = Int
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.github.diegoberaldin.raccoonforlemmy.core.api.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class CreateCommentReportForm(
|
||||||
|
@SerialName("comment_id") val commentId: CommentId,
|
||||||
|
@SerialName("reason") val reason: String,
|
||||||
|
@SerialName("auto") val auth: String,
|
||||||
|
)
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.github.diegoberaldin.raccoonforlemmy.core.api.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class CreatePostReportForm(
|
||||||
|
@SerialName("post_id") val postId: PostId,
|
||||||
|
@SerialName("reason") val reason: String,
|
||||||
|
@SerialName("auto") val auth: String,
|
||||||
|
)
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.github.diegoberaldin.raccoonforlemmy.core.api.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class PostReport(
|
||||||
|
@SerialName("id") val id: PostReportId,
|
||||||
|
@SerialName("creator_id") val creatorId: PersonId,
|
||||||
|
@SerialName("post_id") val postId: PostId,
|
||||||
|
@SerialName("original_post_name") val originalPostName: String,
|
||||||
|
@SerialName("original_post_url") val originalPostUrl: String? = null,
|
||||||
|
@SerialName("original_post_body") val originalPostBody: String? = null,
|
||||||
|
@SerialName("reason") val reason: String,
|
||||||
|
@SerialName("resolved") val resolved: Boolean,
|
||||||
|
@SerialName("resolver_id") val resolverId: PersonId? = null,
|
||||||
|
@SerialName("published") val published: String,
|
||||||
|
@SerialName("updated") val updated: String? = null,
|
||||||
|
)
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.github.diegoberaldin.raccoonforlemmy.core.api.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class PostReportResponse(
|
||||||
|
@SerialName("post_report_view") val postReportView: PostReportView,
|
||||||
|
)
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.github.diegoberaldin.raccoonforlemmy.core.api.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class PostReportView(
|
||||||
|
@SerialName("post_report") val postReport: PostReport,
|
||||||
|
@SerialName("post") val post: Post,
|
||||||
|
@SerialName("community") val community: Community,
|
||||||
|
@SerialName("creator") val creator: Person,
|
||||||
|
@SerialName("post_creator") val postCreator: Person,
|
||||||
|
@SerialName("creator_banned_from_community") val creatorBannedFromCommunity: Boolean,
|
||||||
|
@SerialName("my_vote") val myVote: Int? = null,
|
||||||
|
@SerialName("counts") val counts: PostAggregates,
|
||||||
|
@SerialName("resolver") val resolver: Person? = null,
|
||||||
|
)
|
@ -1,10 +1,12 @@
|
|||||||
package com.github.diegoberaldin.raccoonforlemmy.core.api.service
|
package com.github.diegoberaldin.raccoonforlemmy.core.api.service
|
||||||
|
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CommentReplyResponse
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CommentReplyResponse
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CommentReportResponse
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CommentResponse
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CommentResponse
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CommentSortType
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CommentSortType
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreateCommentForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreateCommentForm
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreateCommentLikeForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreateCommentLikeForm
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreateCommentReportForm
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.DeleteCommentForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.DeleteCommentForm
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.EditCommentForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.EditCommentForm
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.GetCommentResponse
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.GetCommentResponse
|
||||||
@ -86,4 +88,11 @@ interface CommentService {
|
|||||||
@Header("Authorization") authHeader: String? = null,
|
@Header("Authorization") authHeader: String? = null,
|
||||||
@Body form: DeleteCommentForm,
|
@Body form: DeleteCommentForm,
|
||||||
): Response<CommentResponse>
|
): Response<CommentResponse>
|
||||||
|
|
||||||
|
@POST("comment/report")
|
||||||
|
@Headers("Content-Type: application/json")
|
||||||
|
suspend fun createReport(
|
||||||
|
@Body form: CreateCommentReportForm,
|
||||||
|
@Header("Authorization") authHeader: String? = null,
|
||||||
|
): Response<CommentReportResponse>
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package com.github.diegoberaldin.raccoonforlemmy.core.api.service
|
|||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CommentReplyResponse
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CommentReplyResponse
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreatePostForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreatePostForm
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreatePostLikeForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreatePostLikeForm
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreatePostReportForm
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.DeletePostForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.DeletePostForm
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.EditPostForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.EditPostForm
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.GetPostResponse
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.GetPostResponse
|
||||||
@ -10,6 +11,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.GetPostsResponse
|
|||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.ListingType
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.ListingType
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.MarkPostAsReadForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.MarkPostAsReadForm
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.PictrsImages
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.PictrsImages
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.PostReportResponse
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.PostResponse
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.PostResponse
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.SavePostForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.SavePostForm
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.SortType
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.SortType
|
||||||
@ -97,4 +99,11 @@ interface PostService {
|
|||||||
@Header("Authorization") authHeader: String? = null,
|
@Header("Authorization") authHeader: String? = null,
|
||||||
@Body content: MultiPartFormDataContent,
|
@Body content: MultiPartFormDataContent,
|
||||||
): Response<PictrsImages>
|
): Response<PictrsImages>
|
||||||
|
|
||||||
|
@POST("post/report")
|
||||||
|
@Headers("Content-Type: application/json")
|
||||||
|
suspend fun createReport(
|
||||||
|
@Header("Authorization") authHeader: String? = null,
|
||||||
|
@Body form: CreatePostReportForm,
|
||||||
|
): Response<PostReportResponse>
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.image.ZoomableImag
|
|||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoMviModel
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoMviModel
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.NavigationCoordinator
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.NavigationCoordinator
|
||||||
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.saveditems.SavedItemsMviModel
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.saveditems.SavedItemsMviModel
|
||||||
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
|
||||||
@ -122,3 +123,13 @@ actual fun getModalDrawerViewModel(): ModalDrawerMviModel {
|
|||||||
val res: ModalDrawerMviModel by inject(ModalDrawerMviModel::class.java)
|
val res: ModalDrawerMviModel by inject(ModalDrawerMviModel::class.java)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actual fun getCreateReportViewModel(
|
||||||
|
postId: Int?,
|
||||||
|
commentId: Int?,
|
||||||
|
): CreateReportMviModel {
|
||||||
|
val res: CreateReportMviModel by inject(CreateReportMviModel::class.java, parameters = {
|
||||||
|
parametersOf(postId, commentId)
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
@ -84,6 +84,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.image.ZoomableImag
|
|||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoScreen
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoScreen
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomSheet
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomSheet
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailScreen
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailScreen
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateReportScreen
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen
|
||||||
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
|
||||||
@ -427,6 +428,7 @@ class CommunityDetailScreen(
|
|||||||
options = buildList {
|
options = buildList {
|
||||||
add(stringResource(MR.strings.post_action_share))
|
add(stringResource(MR.strings.post_action_share))
|
||||||
add(stringResource(MR.strings.post_action_hide))
|
add(stringResource(MR.strings.post_action_hide))
|
||||||
|
add(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(stringResource(MR.strings.post_action_edit))
|
||||||
add(stringResource(MR.strings.comment_action_delete))
|
add(stringResource(MR.strings.comment_action_delete))
|
||||||
@ -493,13 +495,13 @@ class CommunityDetailScreen(
|
|||||||
},
|
},
|
||||||
onOptionSelected = { optionIdx ->
|
onOptionSelected = { optionIdx ->
|
||||||
when (optionIdx) {
|
when (optionIdx) {
|
||||||
3 -> model.reduce(
|
4 -> model.reduce(
|
||||||
CommunityDetailMviModel.Intent.DeletePost(
|
CommunityDetailMviModel.Intent.DeletePost(
|
||||||
post.id
|
post.id
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
2 -> {
|
3 -> {
|
||||||
notificationCenter.addObserver(
|
notificationCenter.addObserver(
|
||||||
{
|
{
|
||||||
model.reduce(CommunityDetailMviModel.Intent.Refresh)
|
model.reduce(CommunityDetailMviModel.Intent.Refresh)
|
||||||
@ -514,6 +516,14 @@ class CommunityDetailScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2 -> {
|
||||||
|
bottomSheetNavigator.show(
|
||||||
|
CreateReportScreen(
|
||||||
|
postId = post.id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
1 -> model.reduce(
|
1 -> model.reduce(
|
||||||
CommunityDetailMviModel.Intent.Hide(
|
CommunityDetailMviModel.Intent.Hide(
|
||||||
idx
|
idx
|
||||||
|
@ -23,6 +23,8 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.Default
|
|||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.NavigationCoordinator
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.NavigationCoordinator
|
||||||
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.postdetail.PostDetailViewModel
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailViewModel
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateReportMviModel
|
||||||
|
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.userdetail.UserDetailMviModel
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailMviModel
|
||||||
@ -172,4 +174,14 @@ val commonUiModule = module {
|
|||||||
settingsRepository = get(),
|
settingsRepository = get(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
factory<CreateReportMviModel> {
|
||||||
|
CreateReportViewModel(
|
||||||
|
postId = it[0],
|
||||||
|
commentId = it[1],
|
||||||
|
mvi = DefaultMviModel(CreateReportMviModel.UiState()),
|
||||||
|
identityRepository = get(),
|
||||||
|
postRepository = get(),
|
||||||
|
commentRepository = get(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.image.ZoomableImag
|
|||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoMviModel
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoMviModel
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.NavigationCoordinator
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.NavigationCoordinator
|
||||||
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.saveditems.SavedItemsMviModel
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.saveditems.SavedItemsMviModel
|
||||||
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
|
||||||
@ -62,4 +63,9 @@ expect fun getInboxChatViewModel(otherUserId: Int): InboxChatMviModel
|
|||||||
|
|
||||||
expect fun getSavedItemsViewModel(): SavedItemsMviModel
|
expect fun getSavedItemsViewModel(): SavedItemsMviModel
|
||||||
|
|
||||||
expect fun getModalDrawerViewModel(): ModalDrawerMviModel
|
expect fun getModalDrawerViewModel(): ModalDrawerMviModel
|
||||||
|
|
||||||
|
expect fun getCreateReportViewModel(
|
||||||
|
postId: Int? = null,
|
||||||
|
commentId: Int? = null,
|
||||||
|
): CreateReportMviModel
|
@ -87,6 +87,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCo
|
|||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getPostDetailViewModel
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getPostDetailViewModel
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.image.ZoomableImageScreen
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.image.ZoomableImageScreen
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomSheet
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomSheet
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateReportScreen
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen
|
||||||
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
|
||||||
@ -302,6 +303,7 @@ class PostDetailScreen(
|
|||||||
},
|
},
|
||||||
options = buildList {
|
options = buildList {
|
||||||
add(stringResource(MR.strings.post_action_share))
|
add(stringResource(MR.strings.post_action_share))
|
||||||
|
add(stringResource(MR.strings.post_action_report))
|
||||||
if (statePost.creator?.id == uiState.currentUserId && !isOnOtherInstance) {
|
if (statePost.creator?.id == uiState.currentUserId && !isOnOtherInstance) {
|
||||||
add(stringResource(MR.strings.post_action_edit))
|
add(stringResource(MR.strings.post_action_edit))
|
||||||
add(stringResource(MR.strings.comment_action_delete))
|
add(stringResource(MR.strings.comment_action_delete))
|
||||||
@ -347,7 +349,9 @@ class PostDetailScreen(
|
|||||||
},
|
},
|
||||||
onOptionSelected = { idx ->
|
onOptionSelected = { idx ->
|
||||||
when (idx) {
|
when (idx) {
|
||||||
1 -> {
|
3 -> model.reduce(PostDetailMviModel.Intent.DeletePost)
|
||||||
|
|
||||||
|
2 -> {
|
||||||
notificationCenter.addObserver(
|
notificationCenter.addObserver(
|
||||||
{
|
{
|
||||||
model.reduce(PostDetailMviModel.Intent.RefreshPost)
|
model.reduce(PostDetailMviModel.Intent.RefreshPost)
|
||||||
@ -360,7 +364,9 @@ class PostDetailScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
2 -> model.reduce(PostDetailMviModel.Intent.DeletePost)
|
1 -> {
|
||||||
|
bottomSheetNavigator.show(CreateReportScreen(postId = statePost.id))
|
||||||
|
}
|
||||||
|
|
||||||
else -> model.reduce(PostDetailMviModel.Intent.SharePost)
|
else -> model.reduce(PostDetailMviModel.Intent.SharePost)
|
||||||
}
|
}
|
||||||
@ -501,6 +507,7 @@ class PostDetailScreen(
|
|||||||
separateUpAndDownVotes = uiState.separateUpAndDownVotes,
|
separateUpAndDownVotes = uiState.separateUpAndDownVotes,
|
||||||
autoLoadImages = uiState.autoLoadImages,
|
autoLoadImages = uiState.autoLoadImages,
|
||||||
options = buildList {
|
options = buildList {
|
||||||
|
add(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(stringResource(MR.strings.post_action_edit))
|
||||||
add(stringResource(MR.strings.comment_action_delete))
|
add(stringResource(MR.strings.comment_action_delete))
|
||||||
@ -575,15 +582,15 @@ class PostDetailScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onOptionSelected = { idx ->
|
onOptionSelected = { optionId ->
|
||||||
when (idx) {
|
when (optionId) {
|
||||||
1 -> model.reduce(
|
2 -> model.reduce(
|
||||||
PostDetailMviModel.Intent.DeleteComment(
|
PostDetailMviModel.Intent.DeleteComment(
|
||||||
comment.id
|
comment.id
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> {
|
1 -> {
|
||||||
notificationCenter.addObserver(
|
notificationCenter.addObserver(
|
||||||
{
|
{
|
||||||
model.reduce(PostDetailMviModel.Intent.Refresh)
|
model.reduce(PostDetailMviModel.Intent.Refresh)
|
||||||
@ -598,6 +605,14 @@ class PostDetailScreen(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
bottomSheetNavigator.show(
|
||||||
|
CreateReportScreen(
|
||||||
|
commentId = comment.id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.report
|
||||||
|
|
||||||
|
import cafe.adriel.voyager.core.model.ScreenModel
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||||
|
import dev.icerock.moko.resources.desc.StringDesc
|
||||||
|
|
||||||
|
interface CreateReportMviModel :
|
||||||
|
MviModel<CreateReportMviModel.Intent, CreateReportMviModel.UiState, CreateReportMviModel.Effect>,
|
||||||
|
ScreenModel {
|
||||||
|
|
||||||
|
sealed interface Intent {
|
||||||
|
data class SetText(val value: String) : Intent
|
||||||
|
data object Send : Intent
|
||||||
|
}
|
||||||
|
|
||||||
|
data class UiState(
|
||||||
|
val text: String = "",
|
||||||
|
val textError: StringDesc? = null,
|
||||||
|
val loading: Boolean = false,
|
||||||
|
)
|
||||||
|
|
||||||
|
sealed interface Effect {
|
||||||
|
data object Success : Effect
|
||||||
|
|
||||||
|
data class Failure(val message: String?) : Effect
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,166 @@
|
|||||||
|
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.report
|
||||||
|
|
||||||
|
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.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.heightIn
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Send
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.SnackbarHost
|
||||||
|
import androidx.compose.material3.SnackbarHostState
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextField
|
||||||
|
import androidx.compose.material3.TextFieldDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
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.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.focus.focusRequester
|
||||||
|
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 cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
|
||||||
|
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.BottomSheetHandle
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.ProgressHud
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getCreateReportViewModel
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||||
|
import dev.icerock.moko.resources.compose.localized
|
||||||
|
import dev.icerock.moko.resources.compose.stringResource
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
|
||||||
|
class CreateReportScreen(
|
||||||
|
private val postId: Int? = null,
|
||||||
|
private val commentId: Int? = null,
|
||||||
|
) : Screen {
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
override fun Content() {
|
||||||
|
val model = rememberScreenModel {
|
||||||
|
getCreateReportViewModel(
|
||||||
|
postId = postId,
|
||||||
|
commentId = commentId,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
model.bindToLifecycle(key)
|
||||||
|
val uiState by model.uiState.collectAsState()
|
||||||
|
val snackbarHostState = remember { SnackbarHostState() }
|
||||||
|
val genericError = stringResource(MR.strings.message_generic_error)
|
||||||
|
val bottomSheetNavigator = LocalBottomSheetNavigator.current
|
||||||
|
val notificationCenter = remember { getNotificationCenter() }
|
||||||
|
|
||||||
|
LaunchedEffect(model) {
|
||||||
|
model.effects.onEach {
|
||||||
|
when (it) {
|
||||||
|
is CreateReportMviModel.Effect.Failure -> {
|
||||||
|
snackbarHostState.showSnackbar(it.message ?: genericError)
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateReportMviModel.Effect.Success -> {
|
||||||
|
bottomSheetNavigator.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.launchIn(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(
|
||||||
|
contentAlignment = Alignment.BottomCenter,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.spacedBy(Spacing.s),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(top = Spacing.s),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(Spacing.s),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
BottomSheetHandle()
|
||||||
|
val title = when {
|
||||||
|
commentId != null -> stringResource(MR.strings.create_report_title_comment)
|
||||||
|
else -> stringResource(MR.strings.create_report_title_post)
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val commentFocusRequester = remember { FocusRequester() }
|
||||||
|
TextField(
|
||||||
|
modifier = Modifier
|
||||||
|
.focusRequester(commentFocusRequester)
|
||||||
|
.heightIn(min = 300.dp, max = 500.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
colors = TextFieldDefaults.colors(
|
||||||
|
focusedContainerColor = Color.Transparent,
|
||||||
|
unfocusedContainerColor = Color.Transparent,
|
||||||
|
disabledContainerColor = Color.Transparent,
|
||||||
|
),
|
||||||
|
label = {
|
||||||
|
Text(text = stringResource(MR.strings.create_report_placeholder))
|
||||||
|
},
|
||||||
|
textStyle = MaterialTheme.typography.bodyMedium,
|
||||||
|
value = uiState.text,
|
||||||
|
keyboardOptions = KeyboardOptions(
|
||||||
|
keyboardType = KeyboardType.Text,
|
||||||
|
autoCorrect = true,
|
||||||
|
),
|
||||||
|
onValueChange = { value ->
|
||||||
|
model.reduce(CreateReportMviModel.Intent.SetText(value))
|
||||||
|
},
|
||||||
|
isError = uiState.textError != null,
|
||||||
|
supportingText = {
|
||||||
|
if (uiState.textError != null) {
|
||||||
|
Text(
|
||||||
|
text = uiState.textError?.localized().orEmpty(),
|
||||||
|
color = MaterialTheme.colorScheme.error,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trailingIcon = {
|
||||||
|
IconButton(
|
||||||
|
content = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Send,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onClick = {
|
||||||
|
model.reduce(CreateReportMviModel.Intent.Send)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
Spacer(Modifier.height(Spacing.xxl))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uiState.loading) {
|
||||||
|
ProgressHud()
|
||||||
|
}
|
||||||
|
|
||||||
|
SnackbarHost(
|
||||||
|
modifier = Modifier.padding(bottom = Spacing.xxxl),
|
||||||
|
hostState = snackbarHostState
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.report
|
||||||
|
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommentRepository
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostRepository
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.IO
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class CreateReportViewModel(
|
||||||
|
private val postId: Int?,
|
||||||
|
private val commentId: Int?,
|
||||||
|
private val mvi: DefaultMviModel<CreateReportMviModel.Intent, CreateReportMviModel.UiState, CreateReportMviModel.Effect>,
|
||||||
|
private val identityRepository: IdentityRepository,
|
||||||
|
private val postRepository: PostRepository,
|
||||||
|
private val commentRepository: CommentRepository,
|
||||||
|
) : CreateReportMviModel,
|
||||||
|
MviModel<CreateReportMviModel.Intent, CreateReportMviModel.UiState, CreateReportMviModel.Effect> by mvi {
|
||||||
|
|
||||||
|
override fun reduce(intent: CreateReportMviModel.Intent) {
|
||||||
|
when (intent) {
|
||||||
|
is CreateReportMviModel.Intent.SetText -> {
|
||||||
|
mvi.updateState {
|
||||||
|
it.copy(text = intent.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateReportMviModel.Intent.Send -> submit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun submit() {
|
||||||
|
if (mvi.uiState.value.loading) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val text = uiState.value.text
|
||||||
|
|
||||||
|
mvi.updateState { it.copy(loading = true) }
|
||||||
|
mvi.scope?.launch(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
val auth = identityRepository.authToken.value.orEmpty()
|
||||||
|
if (postId != null) {
|
||||||
|
postRepository.report(
|
||||||
|
postId = postId,
|
||||||
|
reason = text,
|
||||||
|
auth = auth,
|
||||||
|
)
|
||||||
|
} else if (commentId != null) {
|
||||||
|
commentRepository.report(
|
||||||
|
commentId = commentId,
|
||||||
|
reason = text,
|
||||||
|
auth = auth,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
mvi.emitEffect(CreateReportMviModel.Effect.Success)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
val message = e.message
|
||||||
|
mvi.emitEffect(CreateReportMviModel.Effect.Failure(message))
|
||||||
|
} finally {
|
||||||
|
mvi.updateState { it.copy(loading = false) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -84,6 +84,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getUserDetailVi
|
|||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.image.ZoomableImageScreen
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.image.ZoomableImageScreen
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomSheet
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomSheet
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailScreen
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailScreen
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateReportScreen
|
||||||
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.onClick
|
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
|
||||||
@ -390,6 +391,7 @@ class UserDetailScreen(
|
|||||||
autoLoadImages = uiState.autoLoadImages,
|
autoLoadImages = uiState.autoLoadImages,
|
||||||
options = buildList {
|
options = buildList {
|
||||||
add(stringResource(MR.strings.post_action_share))
|
add(stringResource(MR.strings.post_action_share))
|
||||||
|
add(stringResource(MR.strings.post_action_report))
|
||||||
},
|
},
|
||||||
onUpVote = if (isOnOtherInstance) {
|
onUpVote = if (isOnOtherInstance) {
|
||||||
null
|
null
|
||||||
@ -454,6 +456,14 @@ class UserDetailScreen(
|
|||||||
},
|
},
|
||||||
onOptionSelected = { optionIdx ->
|
onOptionSelected = { optionIdx ->
|
||||||
when (optionIdx) {
|
when (optionIdx) {
|
||||||
|
1 -> {
|
||||||
|
bottomSheetNavigator.show(
|
||||||
|
CreateReportScreen(
|
||||||
|
postId = post.id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
else -> model.reduce(
|
else -> model.reduce(
|
||||||
UserDetailMviModel.Intent.SharePost(idx)
|
UserDetailMviModel.Intent.SharePost(idx)
|
||||||
)
|
)
|
||||||
@ -599,6 +609,20 @@ class UserDetailScreen(
|
|||||||
onOpenCommunity = { community ->
|
onOpenCommunity = { community ->
|
||||||
navigator?.push(CommunityDetailScreen(community))
|
navigator?.push(CommunityDetailScreen(community))
|
||||||
},
|
},
|
||||||
|
options = buildList {
|
||||||
|
add(stringResource(MR.strings.post_action_report))
|
||||||
|
},
|
||||||
|
onOptionSelected = { optionId ->
|
||||||
|
when (optionId) {
|
||||||
|
else -> {
|
||||||
|
bottomSheetNavigator.show(
|
||||||
|
CreateReportScreen(
|
||||||
|
commentId = comment.id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
)
|
)
|
||||||
Divider(
|
Divider(
|
||||||
modifier = Modifier.padding(vertical = Spacing.xxxs),
|
modifier = Modifier.padding(vertical = Spacing.xxxs),
|
||||||
|
@ -11,6 +11,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.image.ZoomableImag
|
|||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoMviModel
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoMviModel
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.NavigationCoordinator
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.NavigationCoordinator
|
||||||
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.saveditems.SavedItemsMviModel
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.saveditems.SavedItemsMviModel
|
||||||
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
|
||||||
@ -71,6 +72,11 @@ actual fun getSavedItemsViewModel(): SavedItemsMviModel =
|
|||||||
actual fun getModalDrawerViewModel(): ModalDrawerMviModel =
|
actual fun getModalDrawerViewModel(): ModalDrawerMviModel =
|
||||||
CommonUiViewModelHelper.modalDrawerViewModel
|
CommonUiViewModelHelper.modalDrawerViewModel
|
||||||
|
|
||||||
|
actual fun getCreateReportViewModel(
|
||||||
|
postId: Int?,
|
||||||
|
commentId: Int?,
|
||||||
|
): CreateReportMviModel = CommonUiViewModelHelper.getCreateReportModel(postId, commentId)
|
||||||
|
|
||||||
object CommonUiViewModelHelper : KoinComponent {
|
object CommonUiViewModelHelper : KoinComponent {
|
||||||
|
|
||||||
val navigationCoordinator: NavigationCoordinator by inject()
|
val navigationCoordinator: NavigationCoordinator by inject()
|
||||||
@ -145,4 +151,14 @@ object CommonUiViewModelHelper : KoinComponent {
|
|||||||
)
|
)
|
||||||
return model
|
return model
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getCreateReportModel(
|
||||||
|
postId: Int?,
|
||||||
|
commentId: Int?,
|
||||||
|
): CreateReportMviModel {
|
||||||
|
val model: CreateReportMviModel by inject(
|
||||||
|
parameters = { parametersOf(postId, commentId) }
|
||||||
|
)
|
||||||
|
return model
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository
|
|||||||
|
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreateCommentForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreateCommentForm
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreateCommentLikeForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreateCommentLikeForm
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreateCommentReportForm
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.DeleteCommentForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.DeleteCommentForm
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.EditCommentForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.EditCommentForm
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.SaveCommentForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.SaveCommentForm
|
||||||
@ -247,4 +248,16 @@ class CommentRepository(
|
|||||||
)
|
)
|
||||||
services.comment.delete(authHeader = auth.toAuthHeader(), form = data)
|
services.comment.delete(authHeader = auth.toAuthHeader(), form = data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun report(commentId: Int, reason: String, auth: String) {
|
||||||
|
val data = CreateCommentReportForm(
|
||||||
|
commentId = commentId,
|
||||||
|
reason = reason,
|
||||||
|
auth = auth,
|
||||||
|
)
|
||||||
|
services.comment.createReport(
|
||||||
|
form = data,
|
||||||
|
authHeader = auth.toAuthHeader(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository
|
|||||||
|
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreatePostForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreatePostForm
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreatePostLikeForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreatePostLikeForm
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreatePostReportForm
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.DeletePostForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.DeletePostForm
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.EditPostForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.EditPostForm
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.MarkPostAsReadForm
|
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.MarkPostAsReadForm
|
||||||
@ -246,4 +247,16 @@ class PostRepository(
|
|||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun report(postId: Int, reason: String, auth: String) {
|
||||||
|
val data = CreatePostReportForm(
|
||||||
|
postId = postId,
|
||||||
|
reason = reason,
|
||||||
|
auth = auth,
|
||||||
|
)
|
||||||
|
services.post.createReport(
|
||||||
|
form = data,
|
||||||
|
authHeader = auth.toAuthHeader(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,6 +71,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.image.ZoomableImag
|
|||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.ListingTypeBottomSheet
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.ListingTypeBottomSheet
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomSheet
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomSheet
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailScreen
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailScreen
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateReportScreen
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen
|
||||||
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
|
||||||
@ -306,6 +307,7 @@ class PostListScreen : Screen {
|
|||||||
options = buildList {
|
options = buildList {
|
||||||
add(stringResource(MR.strings.post_action_share))
|
add(stringResource(MR.strings.post_action_share))
|
||||||
add(stringResource(MR.strings.post_action_hide))
|
add(stringResource(MR.strings.post_action_hide))
|
||||||
|
add(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(stringResource(MR.strings.post_action_edit))
|
||||||
add(stringResource(MR.strings.comment_action_delete))
|
add(stringResource(MR.strings.comment_action_delete))
|
||||||
@ -367,13 +369,13 @@ class PostListScreen : Screen {
|
|||||||
},
|
},
|
||||||
onOptionSelected = { optionIdx ->
|
onOptionSelected = { optionIdx ->
|
||||||
when (optionIdx) {
|
when (optionIdx) {
|
||||||
3 -> model.reduce(
|
4 -> model.reduce(
|
||||||
PostListMviModel.Intent.DeletePost(
|
PostListMviModel.Intent.DeletePost(
|
||||||
post.id
|
post.id
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
2 -> {
|
3 -> {
|
||||||
notificationCenter.addObserver(
|
notificationCenter.addObserver(
|
||||||
{
|
{
|
||||||
model.reduce(PostListMviModel.Intent.Refresh)
|
model.reduce(PostListMviModel.Intent.Refresh)
|
||||||
@ -388,6 +390,14 @@ class PostListScreen : Screen {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2 -> {
|
||||||
|
bottomSheetNavigator.show(
|
||||||
|
CreateReportScreen(
|
||||||
|
postId = post.id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
1 -> model.reduce(
|
1 -> model.reduce(
|
||||||
PostListMviModel.Intent.Hide(idx)
|
PostListMviModel.Intent.Hide(idx)
|
||||||
)
|
)
|
||||||
|
@ -18,10 +18,10 @@ import androidx.compose.material.icons.filled.Visibility
|
|||||||
import androidx.compose.material.icons.filled.VisibilityOff
|
import androidx.compose.material.icons.filled.VisibilityOff
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.SnackbarHost
|
||||||
import androidx.compose.material3.SnackbarHostState
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextField
|
import androidx.compose.material3.TextField
|
||||||
@ -65,7 +65,6 @@ class LoginBottomSheet : Screen {
|
|||||||
private const val HELP_URL = "https://join-lemmy.org/docs/users/01-getting-started.html"
|
private const val HELP_URL = "https://join-lemmy.org/docs/users/01-getting-started.html"
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content() {
|
override fun Content() {
|
||||||
val model = rememberScreenModel { getLoginBottomSheetViewModel() }
|
val model = rememberScreenModel { getLoginBottomSheetViewModel() }
|
||||||
@ -75,7 +74,6 @@ class LoginBottomSheet : Screen {
|
|||||||
val snackbarHostState = remember { SnackbarHostState() }
|
val snackbarHostState = remember { SnackbarHostState() }
|
||||||
val genericError = stringResource(MR.strings.message_generic_error)
|
val genericError = stringResource(MR.strings.message_generic_error)
|
||||||
val bottomSheetNavigator = LocalBottomSheetNavigator.current
|
val bottomSheetNavigator = LocalBottomSheetNavigator.current
|
||||||
val successfulLoginMessage = stringResource(MR.strings.message_login_successful)
|
|
||||||
|
|
||||||
LaunchedEffect(model) {
|
LaunchedEffect(model) {
|
||||||
model.effects.onEach {
|
model.effects.onEach {
|
||||||
@ -87,7 +85,6 @@ class LoginBottomSheet : Screen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LoginBottomSheetMviModel.Effect.LoginSuccess -> {
|
LoginBottomSheetMviModel.Effect.LoginSuccess -> {
|
||||||
snackbarHostState.showSnackbar(message = successfulLoginMessage)
|
|
||||||
bottomSheetNavigator.hide()
|
bottomSheetNavigator.hide()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,214 +95,223 @@ class LoginBottomSheet : Screen {
|
|||||||
val navigator = remember { getNavigationCoordinator().getRootNavigator() }
|
val navigator = remember { getNavigationCoordinator().getRootNavigator() }
|
||||||
val settingsRepository = remember { getSettingsRepository() }
|
val settingsRepository = remember { getSettingsRepository() }
|
||||||
|
|
||||||
Column(
|
Box(
|
||||||
modifier = Modifier.padding(
|
contentAlignment = Alignment.BottomCenter,
|
||||||
top = Spacing.s,
|
|
||||||
start = Spacing.s,
|
|
||||||
end = Spacing.s,
|
|
||||||
bottom = Spacing.m,
|
|
||||||
),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(Spacing.s),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
) {
|
) {
|
||||||
Box {
|
Column(
|
||||||
Column(
|
modifier = Modifier.padding(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
top = Spacing.s,
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
start = Spacing.s,
|
||||||
) {
|
end = Spacing.s,
|
||||||
BottomSheetHandle()
|
bottom = Spacing.m,
|
||||||
Text(
|
|
||||||
modifier = Modifier.padding(start = Spacing.s, top = Spacing.s),
|
|
||||||
text = stringResource(MR.strings.profile_button_login),
|
|
||||||
style = MaterialTheme.typography.titleLarge,
|
|
||||||
color = MaterialTheme.colorScheme.onBackground,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
IconButton(
|
|
||||||
modifier = Modifier.align(Alignment.TopEnd),
|
|
||||||
onClick = {
|
|
||||||
bottomSheetNavigator.hide()
|
|
||||||
handleUrl(
|
|
||||||
url = HELP_URL,
|
|
||||||
openExternal = settingsRepository.currentSettings.value.openUrlsInExternalBrowser,
|
|
||||||
uriHandler = uriHandler,
|
|
||||||
navigator = navigator
|
|
||||||
)
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.HelpOutline,
|
|
||||||
contentDescription = null,
|
|
||||||
tint = MaterialTheme.colorScheme.onBackground,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val instanceFocusRequester = remember { FocusRequester() }
|
|
||||||
val usernameFocusRequester = remember { FocusRequester() }
|
|
||||||
val passwordFocusRequester = remember { FocusRequester() }
|
|
||||||
val tokenFocusRequester = remember { FocusRequester() }
|
|
||||||
|
|
||||||
TextField(
|
|
||||||
modifier = Modifier.focusRequester(instanceFocusRequester),
|
|
||||||
label = {
|
|
||||||
Text(text = stringResource(MR.strings.login_field_instance_name))
|
|
||||||
},
|
|
||||||
singleLine = true,
|
|
||||||
value = uiState.instanceName,
|
|
||||||
isError = uiState.instanceNameError != null,
|
|
||||||
keyboardActions = KeyboardActions(
|
|
||||||
onNext = {
|
|
||||||
usernameFocusRequester.requestFocus()
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
keyboardOptions = KeyboardOptions(
|
verticalArrangement = Arrangement.spacedBy(Spacing.s),
|
||||||
keyboardType = KeyboardType.Email,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
autoCorrect = false,
|
) {
|
||||||
imeAction = ImeAction.Next,
|
Box {
|
||||||
),
|
Column(
|
||||||
onValueChange = { value ->
|
modifier = Modifier.fillMaxWidth(),
|
||||||
model.reduce(LoginBottomSheetMviModel.Intent.SetInstanceName(value))
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
},
|
) {
|
||||||
supportingText = {
|
BottomSheetHandle()
|
||||||
if (uiState.instanceNameError != null) {
|
|
||||||
Text(
|
Text(
|
||||||
text = uiState.instanceNameError?.localized().orEmpty(),
|
modifier = Modifier.padding(start = Spacing.s, top = Spacing.s),
|
||||||
color = MaterialTheme.colorScheme.error,
|
text = stringResource(MR.strings.profile_button_login),
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
IconButton(
|
||||||
)
|
modifier = Modifier.align(Alignment.TopEnd),
|
||||||
|
onClick = {
|
||||||
TextField(
|
bottomSheetNavigator.hide()
|
||||||
modifier = Modifier.focusRequester(usernameFocusRequester),
|
handleUrl(
|
||||||
label = {
|
url = HELP_URL,
|
||||||
Text(text = stringResource(MR.strings.login_field_user_name))
|
openExternal = settingsRepository.currentSettings.value.openUrlsInExternalBrowser,
|
||||||
},
|
uriHandler = uriHandler,
|
||||||
singleLine = true,
|
navigator = navigator
|
||||||
value = uiState.username,
|
)
|
||||||
isError = uiState.usernameError != null,
|
},
|
||||||
keyboardActions = KeyboardActions(
|
) {
|
||||||
onNext = {
|
Icon(
|
||||||
passwordFocusRequester.requestFocus()
|
imageVector = Icons.Default.HelpOutline,
|
||||||
},
|
contentDescription = null,
|
||||||
),
|
tint = MaterialTheme.colorScheme.onBackground,
|
||||||
keyboardOptions = KeyboardOptions(
|
|
||||||
keyboardType = KeyboardType.Email,
|
|
||||||
autoCorrect = false,
|
|
||||||
imeAction = ImeAction.Next,
|
|
||||||
),
|
|
||||||
onValueChange = { value ->
|
|
||||||
model.reduce(LoginBottomSheetMviModel.Intent.SetUsername(value))
|
|
||||||
},
|
|
||||||
supportingText = {
|
|
||||||
if (uiState.usernameError != null) {
|
|
||||||
Text(
|
|
||||||
text = uiState.usernameError?.localized().orEmpty(),
|
|
||||||
color = MaterialTheme.colorScheme.error,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
)
|
|
||||||
|
|
||||||
var transformation: VisualTransformation by remember {
|
val instanceFocusRequester = remember { FocusRequester() }
|
||||||
mutableStateOf(PasswordVisualTransformation())
|
val usernameFocusRequester = remember { FocusRequester() }
|
||||||
}
|
val passwordFocusRequester = remember { FocusRequester() }
|
||||||
TextField(
|
val tokenFocusRequester = remember { FocusRequester() }
|
||||||
modifier = Modifier.focusRequester(passwordFocusRequester),
|
|
||||||
label = {
|
TextField(
|
||||||
Text(text = stringResource(MR.strings.login_field_password))
|
modifier = Modifier.focusRequester(instanceFocusRequester),
|
||||||
},
|
label = {
|
||||||
singleLine = true,
|
Text(text = stringResource(MR.strings.login_field_instance_name))
|
||||||
value = uiState.password,
|
|
||||||
isError = uiState.passwordError != null,
|
|
||||||
keyboardActions = KeyboardActions(
|
|
||||||
onNext = {
|
|
||||||
tokenFocusRequester.requestFocus()
|
|
||||||
},
|
},
|
||||||
),
|
singleLine = true,
|
||||||
keyboardOptions = KeyboardOptions(
|
value = uiState.instanceName,
|
||||||
keyboardType = KeyboardType.Password,
|
isError = uiState.instanceNameError != null,
|
||||||
imeAction = ImeAction.Next,
|
keyboardActions = KeyboardActions(
|
||||||
),
|
onNext = {
|
||||||
onValueChange = { value ->
|
usernameFocusRequester.requestFocus()
|
||||||
model.reduce(LoginBottomSheetMviModel.Intent.SetPassword(value))
|
},
|
||||||
},
|
),
|
||||||
visualTransformation = transformation,
|
keyboardOptions = KeyboardOptions(
|
||||||
trailingIcon = {
|
keyboardType = KeyboardType.Email,
|
||||||
Image(
|
autoCorrect = false,
|
||||||
modifier = Modifier.onClick {
|
imeAction = ImeAction.Next,
|
||||||
transformation = if (transformation == VisualTransformation.None) {
|
),
|
||||||
PasswordVisualTransformation()
|
onValueChange = { value ->
|
||||||
|
model.reduce(LoginBottomSheetMviModel.Intent.SetInstanceName(value))
|
||||||
|
},
|
||||||
|
supportingText = {
|
||||||
|
if (uiState.instanceNameError != null) {
|
||||||
|
Text(
|
||||||
|
text = uiState.instanceNameError?.localized().orEmpty(),
|
||||||
|
color = MaterialTheme.colorScheme.error,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
TextField(
|
||||||
|
modifier = Modifier.focusRequester(usernameFocusRequester),
|
||||||
|
label = {
|
||||||
|
Text(text = stringResource(MR.strings.login_field_user_name))
|
||||||
|
},
|
||||||
|
singleLine = true,
|
||||||
|
value = uiState.username,
|
||||||
|
isError = uiState.usernameError != null,
|
||||||
|
keyboardActions = KeyboardActions(
|
||||||
|
onNext = {
|
||||||
|
passwordFocusRequester.requestFocus()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
keyboardOptions = KeyboardOptions(
|
||||||
|
keyboardType = KeyboardType.Email,
|
||||||
|
autoCorrect = false,
|
||||||
|
imeAction = ImeAction.Next,
|
||||||
|
),
|
||||||
|
onValueChange = { value ->
|
||||||
|
model.reduce(LoginBottomSheetMviModel.Intent.SetUsername(value))
|
||||||
|
},
|
||||||
|
supportingText = {
|
||||||
|
if (uiState.usernameError != null) {
|
||||||
|
Text(
|
||||||
|
text = uiState.usernameError?.localized().orEmpty(),
|
||||||
|
color = MaterialTheme.colorScheme.error,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
var transformation: VisualTransformation by remember {
|
||||||
|
mutableStateOf(PasswordVisualTransformation())
|
||||||
|
}
|
||||||
|
TextField(
|
||||||
|
modifier = Modifier.focusRequester(passwordFocusRequester),
|
||||||
|
label = {
|
||||||
|
Text(text = stringResource(MR.strings.login_field_password))
|
||||||
|
},
|
||||||
|
singleLine = true,
|
||||||
|
value = uiState.password,
|
||||||
|
isError = uiState.passwordError != null,
|
||||||
|
keyboardActions = KeyboardActions(
|
||||||
|
onNext = {
|
||||||
|
tokenFocusRequester.requestFocus()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
keyboardOptions = KeyboardOptions(
|
||||||
|
keyboardType = KeyboardType.Password,
|
||||||
|
imeAction = ImeAction.Next,
|
||||||
|
),
|
||||||
|
onValueChange = { value ->
|
||||||
|
model.reduce(LoginBottomSheetMviModel.Intent.SetPassword(value))
|
||||||
|
},
|
||||||
|
visualTransformation = transformation,
|
||||||
|
trailingIcon = {
|
||||||
|
Image(
|
||||||
|
modifier = Modifier.onClick {
|
||||||
|
transformation = if (transformation == VisualTransformation.None) {
|
||||||
|
PasswordVisualTransformation()
|
||||||
|
} else {
|
||||||
|
VisualTransformation.None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
imageVector = if (transformation == VisualTransformation.None) {
|
||||||
|
Icons.Default.VisibilityOff
|
||||||
} else {
|
} else {
|
||||||
VisualTransformation.None
|
Icons.Default.Visibility
|
||||||
}
|
},
|
||||||
},
|
contentDescription = null,
|
||||||
imageVector = if (transformation == VisualTransformation.None) {
|
colorFilter = ColorFilter.tint(color = MaterialTheme.colorScheme.onBackground),
|
||||||
Icons.Default.VisibilityOff
|
|
||||||
} else {
|
|
||||||
Icons.Default.Visibility
|
|
||||||
},
|
|
||||||
contentDescription = null,
|
|
||||||
colorFilter = ColorFilter.tint(color = MaterialTheme.colorScheme.onBackground),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
supportingText = {
|
|
||||||
if (uiState.passwordError != null) {
|
|
||||||
Text(
|
|
||||||
text = uiState.passwordError?.localized().orEmpty(),
|
|
||||||
color = MaterialTheme.colorScheme.error,
|
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
},
|
supportingText = {
|
||||||
)
|
if (uiState.passwordError != null) {
|
||||||
|
Text(
|
||||||
|
text = uiState.passwordError?.localized().orEmpty(),
|
||||||
|
color = MaterialTheme.colorScheme.error,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
TextField(
|
TextField(
|
||||||
modifier = Modifier.focusRequester(tokenFocusRequester),
|
modifier = Modifier.focusRequester(tokenFocusRequester),
|
||||||
label = {
|
label = {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(Spacing.s),
|
||||||
|
verticalAlignment = Alignment.Bottom,
|
||||||
|
) {
|
||||||
|
Text(text = stringResource(MR.strings.login_field_token))
|
||||||
|
Text(
|
||||||
|
text = stringResource(MR.strings.login_field_label_optional),
|
||||||
|
style = MaterialTheme.typography.labelSmall,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
singleLine = true,
|
||||||
|
value = uiState.totp2faToken,
|
||||||
|
keyboardOptions = KeyboardOptions(
|
||||||
|
keyboardType = KeyboardType.Password,
|
||||||
|
imeAction = ImeAction.Done,
|
||||||
|
),
|
||||||
|
onValueChange = { value ->
|
||||||
|
model.reduce(LoginBottomSheetMviModel.Intent.SetTotp2faToken(value))
|
||||||
|
},
|
||||||
|
visualTransformation = PasswordVisualTransformation(),
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(Spacing.m))
|
||||||
|
Button(
|
||||||
|
modifier = Modifier.align(Alignment.CenterHorizontally),
|
||||||
|
onClick = {
|
||||||
|
model.reduce(LoginBottomSheetMviModel.Intent.Confirm)
|
||||||
|
},
|
||||||
|
) {
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.spacedBy(Spacing.s),
|
horizontalArrangement = Arrangement.spacedBy(Spacing.s),
|
||||||
verticalAlignment = Alignment.Bottom,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Text(text = stringResource(MR.strings.login_field_token))
|
if (uiState.loading) {
|
||||||
Text(
|
CircularProgressIndicator(
|
||||||
text = stringResource(MR.strings.login_field_label_optional),
|
modifier = Modifier.size(20.dp),
|
||||||
style = MaterialTheme.typography.labelSmall,
|
color = MaterialTheme.colorScheme.onPrimary,
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
Text(stringResource(MR.strings.button_confirm))
|
||||||
}
|
}
|
||||||
},
|
|
||||||
singleLine = true,
|
|
||||||
value = uiState.totp2faToken,
|
|
||||||
keyboardOptions = KeyboardOptions(
|
|
||||||
keyboardType = KeyboardType.Password,
|
|
||||||
imeAction = ImeAction.Done,
|
|
||||||
),
|
|
||||||
onValueChange = { value ->
|
|
||||||
model.reduce(LoginBottomSheetMviModel.Intent.SetTotp2faToken(value))
|
|
||||||
},
|
|
||||||
visualTransformation = PasswordVisualTransformation(),
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(Spacing.m))
|
|
||||||
Button(
|
|
||||||
modifier = Modifier.align(Alignment.CenterHorizontally),
|
|
||||||
onClick = {
|
|
||||||
model.reduce(LoginBottomSheetMviModel.Intent.Confirm)
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(Spacing.s),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
) {
|
|
||||||
if (uiState.loading) {
|
|
||||||
CircularProgressIndicator(
|
|
||||||
modifier = Modifier.size(20.dp),
|
|
||||||
color = MaterialTheme.colorScheme.onPrimary,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Text(stringResource(MR.strings.button_confirm))
|
|
||||||
}
|
}
|
||||||
|
Spacer(modifier = Modifier.height(Spacing.m))
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.height(Spacing.m))
|
|
||||||
|
SnackbarHost(
|
||||||
|
modifier = Modifier.padding(bottom = Spacing.xxxl),
|
||||||
|
hostState = snackbarHostState
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCo
|
|||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.image.ZoomableImageScreen
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.image.ZoomableImageScreen
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomSheet
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomSheet
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailScreen
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailScreen
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateReportScreen
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen
|
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen
|
||||||
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
|
||||||
@ -317,6 +318,7 @@ class MultiCommunityScreen(
|
|||||||
options = buildList {
|
options = buildList {
|
||||||
add(stringResource(MR.strings.post_action_share))
|
add(stringResource(MR.strings.post_action_share))
|
||||||
add(stringResource(MR.strings.post_action_hide))
|
add(stringResource(MR.strings.post_action_hide))
|
||||||
|
add(stringResource(MR.strings.post_action_report))
|
||||||
},
|
},
|
||||||
blurNsfw = uiState.blurNsfw,
|
blurNsfw = uiState.blurNsfw,
|
||||||
onOpenCommunity = { community ->
|
onOpenCommunity = { community ->
|
||||||
@ -374,6 +376,14 @@ class MultiCommunityScreen(
|
|||||||
},
|
},
|
||||||
onOptionSelected = { optionIdx ->
|
onOptionSelected = { optionIdx ->
|
||||||
when (optionIdx) {
|
when (optionIdx) {
|
||||||
|
2 -> {
|
||||||
|
bottomSheetNavigator.show(
|
||||||
|
CreateReportScreen(
|
||||||
|
postId = post.id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
1 -> model.reduce(MultiCommunityMviModel.Intent.Hide(idx))
|
1 -> model.reduce(MultiCommunityMviModel.Intent.Hide(idx))
|
||||||
else -> model.reduce(
|
else -> model.reduce(
|
||||||
MultiCommunityMviModel.Intent.SharePost(idx)
|
MultiCommunityMviModel.Intent.SharePost(idx)
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
<string name="message_missing_field">Missing field</string>
|
<string name="message_missing_field">Missing field</string>
|
||||||
<string name="message_invalid_field">Invalid field</string>
|
<string name="message_invalid_field">Invalid field</string>
|
||||||
<string name="message_image_loading_error">Image loading error</string>
|
<string name="message_image_loading_error">Image loading error</string>
|
||||||
<string name="message_login_successful">🎉 Login successful! 🎉</string>
|
|
||||||
<string name="message_empty_list">No items to display</string>
|
<string name="message_empty_list">No items to display</string>
|
||||||
<string name="message_operation_successful">Operation completed succcessfully</string>
|
<string name="message_operation_successful">Operation completed succcessfully</string>
|
||||||
|
|
||||||
@ -63,11 +62,16 @@
|
|||||||
|
|
||||||
<string name="post_detail_load_more_comments">Load more comments…</string>
|
<string name="post_detail_load_more_comments">Load more comments…</string>
|
||||||
<string name="comment_action_delete">Delete</string>
|
<string name="comment_action_delete">Delete</string>
|
||||||
<string name="post_action_share">Share</string>
|
<string name="post_action_share">Share…</string>
|
||||||
<string name="post_action_edit">Edit</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_detail_cross_posts">also posted to:</string>
|
<string name="post_detail_cross_posts">also posted to:</string>
|
||||||
|
|
||||||
|
<string name="create_report_title_post">Report post</string>
|
||||||
|
<string name="create_report_title_comment">Report comment</string>
|
||||||
|
<string name="create_report_placeholder">Report text (optional)</string>
|
||||||
|
|
||||||
<string name="explore_result_type_all">All</string>
|
<string name="explore_result_type_all">All</string>
|
||||||
<string name="explore_result_type_posts">Posts</string>
|
<string name="explore_result_type_posts">Posts</string>
|
||||||
<string name="explore_result_type_comments">Comments</string>
|
<string name="explore_result_type_comments">Comments</string>
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
<string name="message_missing_field">Campo obligatorio</string>
|
<string name="message_missing_field">Campo obligatorio</string>
|
||||||
<string name="message_invalid_field">Campo no válido</string>
|
<string name="message_invalid_field">Campo no válido</string>
|
||||||
<string name="message_image_loading_error">No ha sido posible descargar la imagen</string>
|
<string name="message_image_loading_error">No ha sido posible descargar la imagen</string>
|
||||||
<string name="message_login_successful">🎉 ¡Acceso completado con éxito! 🎉</string>
|
|
||||||
<string name="message_empty_list">Ningún elemento para mostrar</string>
|
<string name="message_empty_list">Ningún elemento para mostrar</string>
|
||||||
<string name="message_operation_successful">Operación completada con éxito</string>
|
<string name="message_operation_successful">Operación completada con éxito</string>
|
||||||
|
|
||||||
@ -59,11 +58,16 @@
|
|||||||
|
|
||||||
<string name="post_detail_load_more_comments">Descarga más comentarios…</string>
|
<string name="post_detail_load_more_comments">Descarga más comentarios…</string>
|
||||||
<string name="comment_action_delete">Eliminar</string>
|
<string name="comment_action_delete">Eliminar</string>
|
||||||
<string name="post_action_share">Compartir</string>
|
<string name="post_action_share">Compartir…</string>
|
||||||
<string name="post_action_edit">Modificar</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_detail_cross_posts">también publicado en:</string>
|
<string name="post_detail_cross_posts">también publicado en:</string>
|
||||||
|
|
||||||
|
<string name="create_report_title_post">Crear informe sobre publicación</string>
|
||||||
|
<string name="create_report_title_comment">Crear informe sobre comentario</string>
|
||||||
|
<string name="create_report_placeholder">Texto del informe (opcional)</string>
|
||||||
|
|
||||||
<string name="explore_result_type_all">Todos</string>
|
<string name="explore_result_type_all">Todos</string>
|
||||||
<string name="explore_result_type_posts">Publicaciones</string>
|
<string name="explore_result_type_posts">Publicaciones</string>
|
||||||
<string name="explore_result_type_comments">Comentarios</string>
|
<string name="explore_result_type_comments">Comentarios</string>
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
<string name="message_missing_field">Campo obbligatorio</string>
|
<string name="message_missing_field">Campo obbligatorio</string>
|
||||||
<string name="message_invalid_field">Campo non valido</string>
|
<string name="message_invalid_field">Campo non valido</string>
|
||||||
<string name="message_image_loading_error">Errore caricamento immagine</string>
|
<string name="message_image_loading_error">Errore caricamento immagine</string>
|
||||||
<string name="message_login_successful">🎉 Login effettuato con successo! 🎉</string>
|
|
||||||
<string name="message_empty_list">Nessun elemento da visualizzare</string>
|
<string name="message_empty_list">Nessun elemento da visualizzare</string>
|
||||||
<string name="message_operation_successful">Operazione completata con successo</string>
|
<string name="message_operation_successful">Operazione completata con successo</string>
|
||||||
|
|
||||||
@ -59,11 +58,16 @@
|
|||||||
|
|
||||||
<string name="post_detail_load_more_comments">Carica altri commenti…</string>
|
<string name="post_detail_load_more_comments">Carica altri commenti…</string>
|
||||||
<string name="comment_action_delete">Elimina</string>
|
<string name="comment_action_delete">Elimina</string>
|
||||||
<string name="post_action_share">Condividi</string>
|
<string name="post_action_share">Condividi…</string>
|
||||||
<string name="post_action_edit">Modifica</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_detail_cross_posts">postato anche in:</string>
|
<string name="post_detail_cross_posts">postato anche in:</string>
|
||||||
|
|
||||||
|
<string name="create_report_title_post">Segnala post</string>
|
||||||
|
<string name="create_report_title_comment">Segnala commento</string>
|
||||||
|
<string name="create_report_placeholder">Testo segnalazione (opzionale)</string>
|
||||||
|
|
||||||
<string name="explore_result_type_all">Tutti</string>
|
<string name="explore_result_type_all">Tutti</string>
|
||||||
<string name="explore_result_type_posts">Post</string>
|
<string name="explore_result_type_posts">Post</string>
|
||||||
<string name="explore_result_type_comments">Commenti</string>
|
<string name="explore_result_type_comments">Commenti</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user