From 2191a319d7715a6b3a270fc6b1cd16292f723a54 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Tue, 9 Jan 2024 17:36:02 -0500 Subject: [PATCH 01/12] Adding ability to remove and restore comments. #1182 --- .../main/java/com/jerboa/JerboaAppState.kt | 7 ++ app/src/main/java/com/jerboa/MainActivity.kt | 11 ++- app/src/main/java/com/jerboa/Utils.kt | 50 +++++++++- .../java/com/jerboa/model/RemoveViewModel.kt | 68 +++++++++++++ .../java/com/jerboa/model/SiteViewModel.kt | 8 ++ .../ui/components/comment/CommentNode.kt | 62 ++++++++---- .../ui/components/comment/CommentNodes.kt | 29 ++++-- .../comment/CommentOptionsDropdown.kt | 34 ++++++- .../comment/mentionnode/CommentMentionNode.kt | 4 + .../CommentMentionOptionsDropdown.kt | 1 + .../com/jerboa/ui/components/common/Route.kt | 1 + .../ui/components/inbox/InboxActivity.kt | 5 + .../person/PersonProfileActivity.kt | 10 ++ .../jerboa/ui/components/post/PostActivity.kt | 8 ++ .../jerboa/ui/components/remove/RemoveItem.kt | 42 ++++++++ .../remove/comment/CommentRemoveActivity.kt | 95 +++++++++++++++++++ app/src/main/res/values/strings.xml | 7 ++ build.gradle.kts | 8 +- 18 files changed, 417 insertions(+), 33 deletions(-) create mode 100644 app/src/main/java/com/jerboa/model/RemoveViewModel.kt create mode 100644 app/src/main/java/com/jerboa/ui/components/remove/RemoveItem.kt create mode 100644 app/src/main/java/com/jerboa/ui/components/remove/comment/CommentRemoveActivity.kt diff --git a/app/src/main/java/com/jerboa/JerboaAppState.kt b/app/src/main/java/com/jerboa/JerboaAppState.kt index 21923e810..4bf92e054 100644 --- a/app/src/main/java/com/jerboa/JerboaAppState.kt +++ b/app/src/main/java/com/jerboa/JerboaAppState.kt @@ -19,6 +19,8 @@ import com.jerboa.ui.components.community.sidebar.CommunityViewSidebar import com.jerboa.ui.components.post.create.CreatePostReturn import com.jerboa.ui.components.post.edit.PostEditReturn import com.jerboa.ui.components.privatemessage.PrivateMessage +import com.jerboa.ui.components.remove.comment.CommentRemoveReturn +import it.vercruysse.lemmyapi.v0x19.datatypes.Comment import it.vercruysse.lemmyapi.v0x19.datatypes.CommentView import it.vercruysse.lemmyapi.v0x19.datatypes.Community import it.vercruysse.lemmyapi.v0x19.datatypes.CommunityView @@ -68,6 +70,11 @@ class JerboaAppState( navController.navigate(Route.PostReportArgs.makeRoute(id = "$id")) } + fun toCommentRemove(comment: Comment) { + sendReturnForwards(CommentRemoveReturn.COMMENT_SEND, comment) + navController.navigate(Route.COMMENT_REMOVE) + } + fun toSettings() = navController.navigate(Route.SETTINGS) fun toAccountSettings() = navController.navigate(Route.ACCOUNT_SETTINGS) diff --git a/app/src/main/java/com/jerboa/MainActivity.kt b/app/src/main/java/com/jerboa/MainActivity.kt index e0598fd7d..c51a49271 100644 --- a/app/src/main/java/com/jerboa/MainActivity.kt +++ b/app/src/main/java/com/jerboa/MainActivity.kt @@ -6,7 +6,6 @@ import android.os.Build import android.os.Bundle import android.util.Patterns import android.widget.TextView -import android.widget.Toast import androidx.activity.compose.setContent import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity @@ -62,6 +61,7 @@ import com.jerboa.ui.components.post.create.CreatePostActivity import com.jerboa.ui.components.post.edit.PostEditActivity import com.jerboa.ui.components.privatemessage.CreatePrivateMessageActivity import com.jerboa.ui.components.privatemessage.PrivateMessageReplyActivity +import com.jerboa.ui.components.remove.comment.CommentRemoveActivity import com.jerboa.ui.components.report.comment.CreateCommentReportActivity import com.jerboa.ui.components.report.post.CreatePostReportActivity import com.jerboa.ui.components.settings.SettingsActivity @@ -557,6 +557,15 @@ class MainActivity : AppCompatActivity() { ) } + composable( + route = Route.COMMENT_REMOVE, + ) { + CommentRemoveActivity( + appState = appState, + accountViewModel = accountViewModel, + ) + } + composable( route = Route.POST_REPORT, arguments = diff --git a/app/src/main/java/com/jerboa/Utils.kt b/app/src/main/java/com/jerboa/Utils.kt index 440b01d61..5f0047894 100644 --- a/app/src/main/java/com/jerboa/Utils.kt +++ b/app/src/main/java/com/jerboa/Utils.kt @@ -459,10 +459,15 @@ suspend fun openLink( val communityUrl = looksLikeCommunityUrl(parsedUrl) if (userUrl != null && (formatted || API.checkIfLemmyInstance(url))) { - val route = Route.ProfileFromUrlArgs.makeRoute(instance = userUrl.first, name = userUrl.second) + val route = + Route.ProfileFromUrlArgs.makeRoute(instance = userUrl.first, name = userUrl.second) navController.navigate(route) } else if (communityUrl != null && (formatted || API.checkIfLemmyInstance(url))) { - val route = Route.CommunityFromUrlArgs.makeRoute(instance = communityUrl.first, name = communityUrl.second) + val route = + Route.CommunityFromUrlArgs.makeRoute( + instance = communityUrl.first, + name = communityUrl.second, + ) navController.navigate(route) } else { openLinkRaw(url, navController, useCustomTab, usePrivateTab) @@ -1070,7 +1075,11 @@ fun convertSpToPx( sp: TextUnit, ctx: Context, ): Int { - return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp.value, ctx.resources.displayMetrics).toInt() + return TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_SP, + sp.value, + ctx.resources.displayMetrics, + ).toInt() } fun findAndUpdatePrivateMessage( @@ -1288,7 +1297,8 @@ fun copyToClipboard( ): Boolean { val activity = context.findActivity() activity?.let { - val clipboard: ClipboardManager = it.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + val clipboard: ClipboardManager = + it.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clip = ClipData.newPlainText(clipLabel, textToCopy) clipboard.setPrimaryClip(clip) return true @@ -1526,3 +1536,35 @@ fun String.padUrlWithHttps(): String { "https://$this" } } + +/** + * Determines whether someone can moderate an item. Uses a hierarchy of admins then mods. + */ +fun canMod( + creatorId: PersonId, + admins: List?, + moderators: List?, + myId: PersonId?, + onSelf: Boolean = false, +): Boolean { + return if (myId !== null) { + // You can do moderator actions only on the mods added after you. + val adminIds = admins?.map { a -> a.person.id }.orEmpty() + val modIds = moderators?.map { m -> m.moderator.id }.orEmpty() + + val adminsThenMods = adminIds.toMutableList() + adminsThenMods.addAll(modIds) + + val myIndex = adminsThenMods.indexOf(myId) + if (myIndex == -1) { + false + } else { + // onSelf +1 on mod actions not for yourself, IE ban, remove, etc + val subList = adminsThenMods.subList(0, myIndex.plus(if (onSelf) 0 else 1)) + + !subList.contains(creatorId) + } + } else { + false + } +} diff --git a/app/src/main/java/com/jerboa/model/RemoveViewModel.kt b/app/src/main/java/com/jerboa/model/RemoveViewModel.kt new file mode 100644 index 000000000..ab4794389 --- /dev/null +++ b/app/src/main/java/com/jerboa/model/RemoveViewModel.kt @@ -0,0 +1,68 @@ +package com.jerboa.model + +import android.content.Context +import android.util.Log +import android.widget.Toast +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.focus.FocusManager +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.jerboa.R +import com.jerboa.api.API +import com.jerboa.api.ApiState +import com.jerboa.api.toApiState +import com.jerboa.ui.components.common.apiErrorToast +import it.vercruysse.lemmyapi.v0x19.datatypes.CommentResponse +import it.vercruysse.lemmyapi.v0x19.datatypes.CommentView +import it.vercruysse.lemmyapi.v0x19.datatypes.RemoveComment +import kotlinx.coroutines.launch + +class RemoveViewModel : ViewModel() { + var commentRemoveRes: ApiState by mutableStateOf(ApiState.Empty) + private set + + fun removeOrRestoreComment( + commentId: Int, + removed: Boolean, + reason: String, + ctx: Context, + focusManager: FocusManager, + onSuccess: (CommentView) -> Unit, + ) { + viewModelScope.launch { + val form = + RemoveComment( + comment_id = commentId, + removed = removed, + reason = reason, + ) + + commentRemoveRes = ApiState.Loading + commentRemoveRes = API.getInstance().removeComment(form).toApiState() + + when (val res = commentRemoveRes) { + is ApiState.Failure -> { + Log.d("removeComment", "failed", res.msg) + apiErrorToast(msg = res.msg, ctx = ctx) + } + + is ApiState.Success -> { + val message = + if (removed) { + ctx.getString(R.string.remove_view_model_comment_removed) + } else { + ctx.getString(R.string.remove_view_model_comment_restored) + } + val commentView = res.data.comment_view + Toast.makeText(ctx, message, Toast.LENGTH_SHORT).show() + + focusManager.clearFocus() + onSuccess(commentView) + } + else -> {} + } + } + } +} diff --git a/app/src/main/java/com/jerboa/model/SiteViewModel.kt b/app/src/main/java/com/jerboa/model/SiteViewModel.kt index 8d1d98e01..bd7a9e968 100644 --- a/app/src/main/java/com/jerboa/model/SiteViewModel.kt +++ b/app/src/main/java/com/jerboa/model/SiteViewModel.kt @@ -22,6 +22,7 @@ import com.jerboa.jerboaApplication import it.vercruysse.lemmyapi.v0x19.datatypes.CommunityFollowerView import it.vercruysse.lemmyapi.v0x19.datatypes.GetSiteResponse import it.vercruysse.lemmyapi.v0x19.datatypes.GetUnreadCountResponse +import it.vercruysse.lemmyapi.v0x19.datatypes.PersonView import it.vercruysse.lemmyapi.v0x19.datatypes.SaveUserSettings import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -165,6 +166,13 @@ class SiteViewModel(private val accountRepository: AccountRepository) : ViewMode } } + fun admins(): ImmutableList { + return when (val res = siteRes) { + is ApiState.Success -> res.data.admins.toImmutableList() + else -> persistentListOf() + } + } + companion object { val Factory = viewModelFactory { diff --git a/app/src/main/java/com/jerboa/ui/components/comment/CommentNode.kt b/app/src/main/java/com/jerboa/ui/components/comment/CommentNode.kt index 1a7a61fb2..dd3db509a 100644 --- a/app/src/main/java/com/jerboa/ui/components/comment/CommentNode.kt +++ b/app/src/main/java/com/jerboa/ui/components/comment/CommentNode.kt @@ -51,6 +51,7 @@ import com.jerboa.border import com.jerboa.buildCommentsTree import com.jerboa.calculateCommentOffset import com.jerboa.calculateNewInstantScores +import com.jerboa.canMod import com.jerboa.datatypes.sampleCommentView import com.jerboa.datatypes.sampleCommunity import com.jerboa.datatypes.samplePost @@ -171,6 +172,8 @@ fun CommentBodyPreview() { fun LazyListScope.commentNodeItem( node: CommentNode, + admins: List, + moderators: List?, increaseLazyListIndexTracker: () -> Unit, addToParentIndexes: () -> Unit, isFlat: Boolean, @@ -191,6 +194,7 @@ fun LazyListScope.commentNodeItem( onCommunityClick: (community: Community) -> Unit, onPostClick: (postId: Int) -> Unit, onReportClick: (commentView: CommentView) -> Unit, + onRemoveClick: (commentView: CommentView) -> Unit, onCommentLinkClick: (commentView: CommentView) -> Unit, onBlockCreatorClick: (creator: Person) -> Unit, onFetchChildrenClick: (commentView: CommentView) -> Unit, @@ -321,6 +325,8 @@ fun LazyListScope.commentNodeItem( ) { CommentFooterLine( commentView = commentView, + admins = admins, + moderators = moderators, instantScores = instantScores.value, onUpvoteClick = { instantScores.value = @@ -346,6 +352,7 @@ fun LazyListScope.commentNodeItem( onReplyClick = onReplyClick, onSaveClick = onSaveClick, onReportClick = onReportClick, + onRemoveClick = onRemoveClick, onCommentLinkClick = onCommentLinkClick, onPersonClick = onPersonClick, onBlockCreatorClick = onBlockCreatorClick, @@ -385,40 +392,45 @@ fun LazyListScope.commentNodeItem( increaseLazyListIndexTracker = increaseLazyListIndexTracker, addToParentIndexes = addToParentIndexes, isFlat = isFlat, + isExpanded = isExpanded, toggleExpanded = toggleExpanded, toggleActionBar = toggleActionBar, - isExpanded = isExpanded, onUpvoteClick = onUpvoteClick, onDownvoteClick = onDownvoteClick, + onReplyClick = onReplyClick, onSaveClick = onSaveClick, onMarkAsReadClick = onMarkAsReadClick, onCommentClick = onCommentClick, onEditCommentClick = onEditCommentClick, onDeleteCommentClick = onDeleteCommentClick, + onReportClick = onReportClick, + onRemoveClick = onRemoveClick, + onCommentLinkClick = onCommentLinkClick, + onFetchChildrenClick = onFetchChildrenClick, onPersonClick = onPersonClick, onHeaderClick = onHeaderClick, onHeaderLongClick = onHeaderLongClick, onCommunityClick = onCommunityClick, - onPostClick = onPostClick, - showPostAndCommunityContext = showPostAndCommunityContext, - onReportClick = onReportClick, - onCommentLinkClick = onCommentLinkClick, - onFetchChildrenClick = onFetchChildrenClick, - onReplyClick = onReplyClick, onBlockCreatorClick = onBlockCreatorClick, + onPostClick = onPostClick, account = account, - isCollapsedByParent = isCollapsedByParent || !isExpanded(commentId), + showPostAndCommunityContext = showPostAndCommunityContext, showCollapsedCommentContent = showCollapsedCommentContent, + isCollapsedByParent = isCollapsedByParent || !isExpanded(commentId), showActionBar = showActionBar, enableDownVotes = enableDownVotes, showAvatar = showAvatar, blurNSFW = blurNSFW, showScores = showScores, + admins = admins, + moderators = moderators, ) } fun LazyListScope.missingCommentNodeItem( node: MissingCommentNode, + admins: List, + moderators: List?, increaseLazyListIndexTracker: () -> Unit, addToParentIndexes: () -> Unit, isFlat: Boolean, @@ -439,6 +451,7 @@ fun LazyListScope.missingCommentNodeItem( onCommunityClick: (community: Community) -> Unit, onPostClick: (postId: Int) -> Unit, onReportClick: (commentView: CommentView) -> Unit, + onRemoveClick: (commentView: CommentView) -> Unit, onCommentLinkClick: (commentView: CommentView) -> Unit, onBlockCreatorClick: (creator: Person) -> Unit, onFetchChildrenClick: (commentView: CommentView) -> Unit, @@ -518,33 +531,36 @@ fun LazyListScope.missingCommentNodeItem( commentNodeItems( nodes = node.children.toImmutableList(), + admins = admins, + moderators = moderators, increaseLazyListIndexTracker = increaseLazyListIndexTracker, addToParentIndexes = addToParentIndexes, isFlat = isFlat, + isExpanded = isExpanded, toggleExpanded = toggleExpanded, toggleActionBar = toggleActionBar, - isExpanded = isExpanded, onUpvoteClick = onUpvoteClick, onDownvoteClick = onDownvoteClick, + onReplyClick = onReplyClick, onSaveClick = onSaveClick, onMarkAsReadClick = onMarkAsReadClick, onCommentClick = onCommentClick, onEditCommentClick = onEditCommentClick, onDeleteCommentClick = onDeleteCommentClick, + onReportClick = onReportClick, + onRemoveClick = onRemoveClick, + onCommentLinkClick = onCommentLinkClick, + onFetchChildrenClick = onFetchChildrenClick, onPersonClick = onPersonClick, onHeaderClick = onHeaderClick, onHeaderLongClick = onHeaderLongClick, onCommunityClick = onCommunityClick, - onPostClick = onPostClick, - showPostAndCommunityContext = showPostAndCommunityContext, - onReportClick = onReportClick, - onCommentLinkClick = onCommentLinkClick, - onFetchChildrenClick = onFetchChildrenClick, - onReplyClick = onReplyClick, onBlockCreatorClick = onBlockCreatorClick, + onPostClick = onPostClick, account = account, - isCollapsedByParent = isCollapsedByParent || !isExpanded(commentId), + showPostAndCommunityContext = showPostAndCommunityContext, showCollapsedCommentContent = showCollapsedCommentContent, + isCollapsedByParent = isCollapsedByParent || !isExpanded(commentId), showActionBar = showActionBar, enableDownVotes = enableDownVotes, showAvatar = showAvatar, @@ -649,6 +665,8 @@ fun PostAndCommunityContextHeaderPreview() { @Composable fun CommentFooterLine( commentView: CommentView, + admins: List, + moderators: List?, enableDownVotes: Boolean, instantScores: InstantScores, onUpvoteClick: () -> Unit, @@ -659,6 +677,7 @@ fun CommentFooterLine( onEditCommentClick: (commentView: CommentView) -> Unit, onDeleteCommentClick: (commentView: CommentView) -> Unit, onReportClick: (commentView: CommentView) -> Unit, + onRemoveClick: (commentView: CommentView) -> Unit, onCommentLinkClick: (commentView: CommentView) -> Unit, onBlockCreatorClick: (creator: Person) -> Unit, onPersonClick: (personId: Int) -> Unit, @@ -678,10 +697,18 @@ fun CommentFooterLine( onEditCommentClick = onEditCommentClick, onDeleteCommentClick = onDeleteCommentClick, onReportClick = onReportClick, + onRemoveClick = onRemoveClick, onBlockCreatorClick = onBlockCreatorClick, onCommentLinkClick = onCommentLinkClick, onPersonClick = onPersonClick, isCreator = account.id == commentView.creator.id, + canMod = + canMod( + creatorId = commentView.comment.creator_id, + admins = admins, + moderators = moderators, + myId = account.id, + ), viewSource = viewSource, ) } @@ -772,6 +799,8 @@ fun CommentNodesPreview() { val tree = buildCommentsTree(comments, null) CommentNodes( nodes = tree, + admins = listOf(), + moderators = listOf(), increaseLazyListIndexTracker = {}, addToParentIndexes = {}, isFlat = false, @@ -788,6 +817,7 @@ fun CommentNodesPreview() { onEditCommentClick = {}, onDeleteCommentClick = {}, onReportClick = {}, + onRemoveClick = {}, onCommentLinkClick = {}, onPersonClick = {}, onHeaderClick = {}, diff --git a/app/src/main/java/com/jerboa/ui/components/comment/CommentNodes.kt b/app/src/main/java/com/jerboa/ui/components/comment/CommentNodes.kt index 0c52ceb11..3ade2c552 100644 --- a/app/src/main/java/com/jerboa/ui/components/comment/CommentNodes.kt +++ b/app/src/main/java/com/jerboa/ui/components/comment/CommentNodes.kt @@ -14,12 +14,16 @@ import com.jerboa.MissingCommentNode import com.jerboa.db.entity.Account import it.vercruysse.lemmyapi.v0x19.datatypes.CommentView import it.vercruysse.lemmyapi.v0x19.datatypes.Community +import it.vercruysse.lemmyapi.v0x19.datatypes.CommunityModeratorView import it.vercruysse.lemmyapi.v0x19.datatypes.Person +import it.vercruysse.lemmyapi.v0x19.datatypes.PersonView import kotlinx.collections.immutable.ImmutableList @Composable fun CommentNodes( nodes: ImmutableList, + admins: List, + moderators: List?, increaseLazyListIndexTracker: () -> Unit, addToParentIndexes: () -> Unit, isFlat: Boolean, @@ -36,6 +40,7 @@ fun CommentNodes( onEditCommentClick: (commentView: CommentView) -> Unit, onDeleteCommentClick: (commentView: CommentView) -> Unit, onReportClick: (commentView: CommentView) -> Unit, + onRemoveClick: (commentView: CommentView) -> Unit, onCommentLinkClick: (commentView: CommentView) -> Unit, onFetchChildrenClick: (commentView: CommentView) -> Unit, onPersonClick: (personId: Int) -> Unit, @@ -57,6 +62,8 @@ fun CommentNodes( LazyColumn(state = listState) { commentNodeItems( nodes = nodes, + admins = admins, + moderators = moderators, increaseLazyListIndexTracker = increaseLazyListIndexTracker, addToParentIndexes = addToParentIndexes, isFlat = isFlat, @@ -67,20 +74,21 @@ fun CommentNodes( onDownvoteClick = onDownvoteClick, onReplyClick = onReplyClick, onSaveClick = onSaveClick, - account = account, onMarkAsReadClick = onMarkAsReadClick, onCommentClick = onCommentClick, - onPersonClick = onPersonClick, - onHeaderClick = onHeaderClick, - onHeaderLongClick = onHeaderLongClick, - onCommunityClick = onCommunityClick, - onPostClick = onPostClick, onEditCommentClick = onEditCommentClick, onDeleteCommentClick = onDeleteCommentClick, onReportClick = onReportClick, + onRemoveClick = onRemoveClick, onCommentLinkClick = onCommentLinkClick, onFetchChildrenClick = onFetchChildrenClick, + onPersonClick = onPersonClick, + onHeaderClick = onHeaderClick, + onHeaderLongClick = onHeaderLongClick, + onCommunityClick = onCommunityClick, onBlockCreatorClick = onBlockCreatorClick, + onPostClick = onPostClick, + account = account, showPostAndCommunityContext = showPostAndCommunityContext, showCollapsedCommentContent = showCollapsedCommentContent, isCollapsedByParent = isCollapsedByParent, @@ -98,6 +106,8 @@ fun CommentNodes( fun LazyListScope.commentNodeItems( nodes: ImmutableList, + admins: List, + moderators: List?, increaseLazyListIndexTracker: () -> Unit, addToParentIndexes: () -> Unit, isFlat: Boolean, @@ -113,6 +123,7 @@ fun LazyListScope.commentNodeItems( onEditCommentClick: (commentView: CommentView) -> Unit, onDeleteCommentClick: (commentView: CommentView) -> Unit, onReportClick: (commentView: CommentView) -> Unit, + onRemoveClick: (commentView: CommentView) -> Unit, onCommentLinkClick: (commentView: CommentView) -> Unit, onFetchChildrenClick: (commentView: CommentView) -> Unit, onPersonClick: (personId: Int) -> Unit, @@ -136,6 +147,8 @@ fun LazyListScope.commentNodeItems( is CommentNode -> commentNodeItem( node = node, + admins = admins, + moderators = moderators, increaseLazyListIndexTracker = increaseLazyListIndexTracker, addToParentIndexes = addToParentIndexes, isFlat = isFlat, @@ -157,6 +170,7 @@ fun LazyListScope.commentNodeItems( onEditCommentClick = onEditCommentClick, onDeleteCommentClick = onDeleteCommentClick, onReportClick = onReportClick, + onRemoveClick = onRemoveClick, onCommentLinkClick = onCommentLinkClick, onFetchChildrenClick = onFetchChildrenClick, onBlockCreatorClick = onBlockCreatorClick, @@ -173,6 +187,8 @@ fun LazyListScope.commentNodeItems( is MissingCommentNode -> missingCommentNodeItem( node = node, + admins = admins, + moderators = moderators, increaseLazyListIndexTracker = increaseLazyListIndexTracker, addToParentIndexes = addToParentIndexes, isFlat = isFlat, @@ -194,6 +210,7 @@ fun LazyListScope.commentNodeItems( onEditCommentClick = onEditCommentClick, onDeleteCommentClick = onDeleteCommentClick, onReportClick = onReportClick, + onRemoveClick = onRemoveClick, onCommentLinkClick = onCommentLinkClick, onFetchChildrenClick = onFetchChildrenClick, onBlockCreatorClick = onBlockCreatorClick, diff --git a/app/src/main/java/com/jerboa/ui/components/comment/CommentOptionsDropdown.kt b/app/src/main/java/com/jerboa/ui/components/comment/CommentOptionsDropdown.kt index 0b6b62b53..a0eee5ff0 100644 --- a/app/src/main/java/com/jerboa/ui/components/comment/CommentOptionsDropdown.kt +++ b/app/src/main/java/com/jerboa/ui/components/comment/CommentOptionsDropdown.kt @@ -3,6 +3,7 @@ package com.jerboa.ui.components.comment import android.widget.Toast import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Block +import androidx.compose.material.icons.outlined.Close import androidx.compose.material.icons.outlined.Comment import androidx.compose.material.icons.outlined.ContentCopy import androidx.compose.material.icons.outlined.CopyAll @@ -38,7 +39,9 @@ fun CommentOptionsDropdown( onDeleteCommentClick: (CommentView) -> Unit, onBlockCreatorClick: (Person) -> Unit, onReportClick: (CommentView) -> Unit, + onRemoveClick: (CommentView) -> Unit, isCreator: Boolean, + canMod: Boolean, viewSource: Boolean, ) { val localClipboardManager = LocalClipboardManager.current @@ -90,9 +93,17 @@ fun CommentOptionsDropdown( onClick = { onDismissRequest() if (copyToClipboard(ctx, commentView.comment.content, "comment")) { - Toast.makeText(ctx, ctx.getString(R.string.comment_node_comment_copied), Toast.LENGTH_SHORT).show() + Toast.makeText( + ctx, + ctx.getString(R.string.comment_node_comment_copied), + Toast.LENGTH_SHORT, + ).show() } else { - Toast.makeText(ctx, ctx.getString(R.string.generic_error), Toast.LENGTH_SHORT).show() + Toast.makeText( + ctx, + ctx.getString(R.string.generic_error), + Toast.LENGTH_SHORT, + ).show() } }, ) @@ -160,6 +171,25 @@ fun CommentOptionsDropdown( onReportClick(commentView) }, ) + + if (canMod) { + Divider() + val (removeText, removeIcon) = + if (commentView.comment.removed) { + Pair(stringResource(R.string.restore_comment), Icons.Outlined.Restore) + } else { + Pair(stringResource(R.string.remove_comment), Icons.Outlined.Close) + } + + PopupMenuItem( + text = removeText, + icon = removeIcon, + onClick = { + onDismissRequest() + onRemoveClick(commentView) + }, + ) + } } } } diff --git a/app/src/main/java/com/jerboa/ui/components/comment/mentionnode/CommentMentionNode.kt b/app/src/main/java/com/jerboa/ui/components/comment/mentionnode/CommentMentionNode.kt index d7a17eb8d..c707a4a2b 100644 --- a/app/src/main/java/com/jerboa/ui/components/comment/mentionnode/CommentMentionNode.kt +++ b/app/src/main/java/com/jerboa/ui/components/comment/mentionnode/CommentMentionNode.kt @@ -99,6 +99,7 @@ fun CommentMentionNodeFooterLine( onPersonClick: (personId: Int) -> Unit, onViewSourceClick: () -> Unit, onReportClick: (personMentionView: PersonMentionView) -> Unit, + onRemoveClick: (personMentionView: PersonMentionView) -> Unit, onLinkClick: (personMentionView: PersonMentionView) -> Unit, onBlockCreatorClick: (creator: Person) -> Unit, myVote: Int?, @@ -118,6 +119,7 @@ fun CommentMentionNodeFooterLine( onPersonClick = onPersonClick, onViewSourceClick = onViewSourceClick, onReportClick = onReportClick, + onRemoveClick = onRemoveClick, onBlockCreatorClick = onBlockCreatorClick, isCreator = account.id == personMentionView.creator.id, onCommentLinkClick = onLinkClick, @@ -235,6 +237,7 @@ fun CommentMentionNode( onCommunityClick: (community: Community) -> Unit, onPostClick: (postId: Int) -> Unit, onReportClick: (personMentionView: PersonMentionView) -> Unit, + onRemoveClick: (personMentionView: PersonMentionView) -> Unit, onLinkClick: (personMentionView: PersonMentionView) -> Unit, onBlockCreatorClick: (creator: Person) -> Unit, account: Account, @@ -314,6 +317,7 @@ fun CommentMentionNode( onSaveClick = onSaveClick, onMarkAsReadClick = onMarkAsReadClick, onReportClick = onReportClick, + onRemoveClick = onRemoveClick, onLinkClick = onLinkClick, onBlockCreatorClick = onBlockCreatorClick, myVote = myVote, diff --git a/app/src/main/java/com/jerboa/ui/components/comment/mentionnode/CommentMentionOptionsDropdown.kt b/app/src/main/java/com/jerboa/ui/components/comment/mentionnode/CommentMentionOptionsDropdown.kt index 4239e1b79..78df6a155 100644 --- a/app/src/main/java/com/jerboa/ui/components/comment/mentionnode/CommentMentionOptionsDropdown.kt +++ b/app/src/main/java/com/jerboa/ui/components/comment/mentionnode/CommentMentionOptionsDropdown.kt @@ -33,6 +33,7 @@ fun CommentMentionsOptionsDropdown( onViewSourceClick: () -> Unit, onBlockCreatorClick: (Person) -> Unit, onReportClick: (PersonMentionView) -> Unit, + onRemoveClick: (PersonMentionView) -> Unit, isCreator: Boolean, viewSource: Boolean, ) { diff --git a/app/src/main/java/com/jerboa/ui/components/common/Route.kt b/app/src/main/java/com/jerboa/ui/components/common/Route.kt index 6916fd174..514b39c21 100644 --- a/app/src/main/java/com/jerboa/ui/components/common/Route.kt +++ b/app/src/main/java/com/jerboa/ui/components/common/Route.kt @@ -32,6 +32,7 @@ object Route { const val COMMENT_EDIT = "commentEdit" const val POST_EDIT = "postEdit" const val PRIVATE_MESSAGE_REPLY = "privateMessageReply" + const val COMMENT_REMOVE = "commentRemove" val CREATE_PRIVATE_MESSAGE = CreatePrivateMessageArgs.route val COMMENT_REPORT = CommentReportArgs.route diff --git a/app/src/main/java/com/jerboa/ui/components/inbox/InboxActivity.kt b/app/src/main/java/com/jerboa/ui/components/inbox/InboxActivity.kt index 52826fc9d..4de961b41 100644 --- a/app/src/main/java/com/jerboa/ui/components/inbox/InboxActivity.kt +++ b/app/src/main/java/com/jerboa/ui/components/inbox/InboxActivity.kt @@ -610,6 +610,11 @@ fun InboxTabs( onReportClick = { pm -> appState.toCommentReport(id = pm.comment.id) }, + onRemoveClick = { pm -> + appState.toCommentRemove( + comment = pm.comment, + ) + }, onLinkClick = { pm -> // Go to the parent comment or post instead for context val parent = getCommentParentId(pm.comment) diff --git a/app/src/main/java/com/jerboa/ui/components/person/PersonProfileActivity.kt b/app/src/main/java/com/jerboa/ui/components/person/PersonProfileActivity.kt index 8b1208f92..2f3bc033f 100644 --- a/app/src/main/java/com/jerboa/ui/components/person/PersonProfileActivity.kt +++ b/app/src/main/java/com/jerboa/ui/components/person/PersonProfileActivity.kt @@ -80,6 +80,7 @@ import com.jerboa.ui.components.community.CommunityLink import com.jerboa.ui.components.post.PostListings import com.jerboa.ui.components.post.PostViewReturn import com.jerboa.ui.components.post.edit.PostEditReturn +import com.jerboa.ui.components.remove.comment.CommentRemoveReturn import com.jerboa.ui.theme.MEDIUM_PADDING import it.vercruysse.lemmyapi.v0x19.datatypes.BlockPerson import it.vercruysse.lemmyapi.v0x19.datatypes.CommentView @@ -130,6 +131,7 @@ fun PersonProfileActivity( appState.ConsumeReturn(PostEditReturn.POST_VIEW, personProfileViewModel::updatePost) appState.ConsumeReturn(CommentEditReturn.COMMENT_VIEW, personProfileViewModel::updateComment) + appState.ConsumeReturn(CommentRemoveReturn.COMMENT_VIEW, personProfileViewModel::updateComment) appState.ConsumeReturn(CommentReplyReturn.COMMENT_VIEW) { cv -> when (val res = personProfileViewModel.personDetailsRes) { @@ -244,6 +246,7 @@ fun PersonProfileActivity( padding = it, appState = appState, personProfileViewModel = personProfileViewModel, + siteViewModel = siteViewModel, ctx = ctx, account = account, scope = scope, @@ -277,6 +280,7 @@ fun UserTabs( appState: JerboaAppState, savedMode: Boolean, personProfileViewModel: PersonProfileViewModel, + siteViewModel: SiteViewModel, ctx: Context, account: Account, scope: CoroutineScope, @@ -644,6 +648,9 @@ fun UserTabs( } CommentNodes( nodes = nodes, + admins = siteViewModel.admins(), +// No community moderators available here + moderators = null, increaseLazyListIndexTracker = {}, addToParentIndexes = {}, isFlat = true, @@ -741,6 +748,9 @@ fun UserTabs( onReportClick = { cv -> appState.toCommentReport(id = cv.comment.id) }, + onRemoveClick = { cv -> + appState.toCommentRemove(comment = cv.comment) + }, onCommentLinkClick = { cv -> appState.toComment(id = cv.comment.id) }, diff --git a/app/src/main/java/com/jerboa/ui/components/post/PostActivity.kt b/app/src/main/java/com/jerboa/ui/components/post/PostActivity.kt index ed29e3c9f..04785506e 100644 --- a/app/src/main/java/com/jerboa/ui/components/post/PostActivity.kt +++ b/app/src/main/java/com/jerboa/ui/components/post/PostActivity.kt @@ -85,6 +85,7 @@ import com.jerboa.ui.components.common.isLoading import com.jerboa.ui.components.common.isRefreshing import com.jerboa.ui.components.common.simpleVerticalScrollbar import com.jerboa.ui.components.post.edit.PostEditReturn +import com.jerboa.ui.components.remove.comment.CommentRemoveReturn import it.vercruysse.lemmyapi.dto.CommentSortType import it.vercruysse.lemmyapi.v0x19.datatypes.* @@ -140,6 +141,7 @@ fun PostActivity( appState.ConsumeReturn(PostEditReturn.POST_VIEW, postViewModel::updatePost) appState.ConsumeReturn(CommentReplyReturn.COMMENT_VIEW, postViewModel::appendComment) appState.ConsumeReturn(CommentEditReturn.COMMENT_VIEW, postViewModel::updateComment) + appState.ConsumeReturn(CommentRemoveReturn.COMMENT_VIEW, postViewModel::updateComment) val onClickSortType = { commentSortType: CommentSortType -> postViewModel.updateSortType(commentSortType) @@ -278,6 +280,7 @@ fun PostActivity( is ApiState.Failure -> ApiErrorText(postRes.msg, padding) is ApiState.Success -> { val postView = postRes.data.post_view + val moderators = postRes.data.moderators if (!account.isAnon()) appState.addReturn(PostViewReturn.POST_VIEW, postView.copy(read = true)) LazyColumn( @@ -466,6 +469,8 @@ fun PostActivity( commentNodeItems( nodes = commentTree, + admins = siteViewModel.admins(), + moderators = moderators, increaseLazyListIndexTracker = { lazyListIndexTracker++ }, @@ -574,6 +579,9 @@ fun PostActivity( onReportClick = { cv -> appState.toCommentReport(id = cv.comment.id) }, + onRemoveClick = { cv -> + appState.toCommentRemove(comment = cv.comment) + }, onCommentLinkClick = { cv -> appState.toComment(id = cv.comment.id) }, diff --git a/app/src/main/java/com/jerboa/ui/components/remove/RemoveItem.kt b/app/src/main/java/com/jerboa/ui/components/remove/RemoveItem.kt new file mode 100644 index 000000000..2071484a5 --- /dev/null +++ b/app/src/main/java/com/jerboa/ui/components/remove/RemoveItem.kt @@ -0,0 +1,42 @@ +package com.jerboa.ui.components.remove + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.TextFieldValue +import com.jerboa.R +import com.jerboa.db.entity.Account +import com.jerboa.ui.components.common.MarkdownTextField + +@Composable +fun RemoveItemBody( + reason: TextFieldValue, + onReasonChange: (TextFieldValue) -> Unit, + account: Account, + padding: PaddingValues, +) { + val scrollState = rememberScrollState() + + Column( + modifier = + Modifier + .verticalScroll(scrollState) + .padding(padding) + .imePadding(), + ) { + MarkdownTextField( + text = reason, + onTextChange = onReasonChange, + account = account, + modifier = Modifier.fillMaxWidth(), + placeholder = stringResource(R.string.type_your_reason), + ) + } +} diff --git a/app/src/main/java/com/jerboa/ui/components/remove/comment/CommentRemoveActivity.kt b/app/src/main/java/com/jerboa/ui/components/remove/comment/CommentRemoveActivity.kt new file mode 100644 index 000000000..3d4d53a3d --- /dev/null +++ b/app/src/main/java/com/jerboa/ui/components/remove/comment/CommentRemoveActivity.kt @@ -0,0 +1,95 @@ +package com.jerboa.ui.components.remove.comment + +import android.util.Log +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Send +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.TextFieldValue +import androidx.lifecycle.viewmodel.compose.viewModel +import com.jerboa.JerboaAppState +import com.jerboa.R +import com.jerboa.api.ApiState +import com.jerboa.db.entity.isAnon +import com.jerboa.model.AccountViewModel +import com.jerboa.model.RemoveViewModel +import com.jerboa.ui.components.common.ActionTopBar +import com.jerboa.ui.components.common.getCurrentAccount +import com.jerboa.ui.components.remove.RemoveItemBody +import it.vercruysse.lemmyapi.v0x19.datatypes.Comment + +object CommentRemoveReturn { + const val COMMENT_VIEW = "comment-remove::return(comment-view)" + const val COMMENT_SEND = "comment-remove::send(comment-view)" +} + +@Composable +fun CommentRemoveActivity( + appState: JerboaAppState, + accountViewModel: AccountViewModel, +) { + Log.d("jerboa", "got to create comment remove activity") + + val ctx = LocalContext.current + val account = getCurrentAccount(accountViewModel = accountViewModel) + + val removeViewModel: RemoveViewModel = viewModel() + val comment = appState.getPrevReturn(key = CommentRemoveReturn.COMMENT_SEND) + + var reason by rememberSaveable(stateSaver = TextFieldValue.Saver) { + mutableStateOf( + TextFieldValue(""), + ) + } + val loading = + when (removeViewModel.commentRemoveRes) { + ApiState.Loading -> true + else -> false + } + + val focusManager = LocalFocusManager.current + val title = stringResource(if (comment.removed) R.string.restore_comment else R.string.remove_comment) + + Scaffold( + topBar = { + ActionTopBar( + title = title, + loading = loading, + onActionClick = { + if (!account.isAnon()) { + removeViewModel.removeOrRestoreComment( + commentId = comment.id, + reason = reason.text, + removed = !comment.removed, + ctx = ctx, + focusManager = focusManager, + ) { commentView -> + appState.apply { + addReturn(CommentRemoveReturn.COMMENT_VIEW, commentView) + navigateUp() + } + } + } + }, + actionText = R.string.form_submit, + actionIcon = Icons.Outlined.Send, + onBackClick = appState::popBackStack, + ) + }, + content = { padding -> + RemoveItemBody( + reason = reason, + onReasonChange = { reason = it }, + account = account, + padding = padding, + ) + }, + ) +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 338f563e4..46e9f8457 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -403,4 +403,11 @@ Failed to parse datetime There is no record of this comment The version (%s) is not supported + Comment removed + Comment restored + Post removed + Post restored + Remove Comment + Restore Comment + Type your reason diff --git a/build.gradle.kts b/build.gradle.kts index 7b93a4817..b548952bc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,14 +1,14 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - id("com.android.application") version "8.2.0" apply false - id("com.android.library") version "8.2.0" apply false + id("com.android.application") version "8.2.1" apply false + id("com.android.library") version "8.2.1" apply false id("org.jetbrains.kotlin.android") version "1.9.21" apply false id("com.github.ben-manes.versions") version "0.42.0" id("org.jmailen.kotlinter") version "4.1.0" apply false id("com.google.devtools.ksp") version "1.9.21-1.0.15" apply false - id("com.android.test") version "8.2.0" apply false - id("androidx.baselineprofile") version "1.2.0-alpha13" apply false + id("com.android.test") version "8.2.1" apply false + id("androidx.baselineprofile") version "1.2.2" apply false } subprojects { From d75f59c3edb2303108884e999d788e9c0261a570 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Tue, 9 Jan 2024 17:40:09 -0500 Subject: [PATCH 02/12] Fix weird formatting miss. --- .../com/jerboa/ui/components/person/PersonProfileActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/jerboa/ui/components/person/PersonProfileActivity.kt b/app/src/main/java/com/jerboa/ui/components/person/PersonProfileActivity.kt index 2f3bc033f..c7cda55b5 100644 --- a/app/src/main/java/com/jerboa/ui/components/person/PersonProfileActivity.kt +++ b/app/src/main/java/com/jerboa/ui/components/person/PersonProfileActivity.kt @@ -649,7 +649,7 @@ fun UserTabs( CommentNodes( nodes = nodes, admins = siteViewModel.admins(), -// No community moderators available here + // No community moderators available here moderators = null, increaseLazyListIndexTracker = {}, addToParentIndexes = {}, From f5b85162fb9846371e923a62bd291b89f814b619 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 11 Jan 2024 10:32:05 -0500 Subject: [PATCH 03/12] Use ImmutableList instead of List. --- app/src/main/java/com/jerboa/Utils.kt | 4 ++-- .../ui/components/comment/CommentNode.kt | 18 ++++++++++-------- .../ui/components/comment/CommentNodes.kt | 8 ++++---- .../jerboa/ui/components/post/PostActivity.kt | 3 ++- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/jerboa/Utils.kt b/app/src/main/java/com/jerboa/Utils.kt index 5f0047894..4478d4339 100644 --- a/app/src/main/java/com/jerboa/Utils.kt +++ b/app/src/main/java/com/jerboa/Utils.kt @@ -1542,8 +1542,8 @@ fun String.padUrlWithHttps(): String { */ fun canMod( creatorId: PersonId, - admins: List?, - moderators: List?, + admins: ImmutableList?, + moderators: ImmutableList?, myId: PersonId?, onSelf: Boolean = false, ): Boolean { diff --git a/app/src/main/java/com/jerboa/ui/components/comment/CommentNode.kt b/app/src/main/java/com/jerboa/ui/components/comment/CommentNode.kt index dd3db509a..5a1e1093d 100644 --- a/app/src/main/java/com/jerboa/ui/components/comment/CommentNode.kt +++ b/app/src/main/java/com/jerboa/ui/components/comment/CommentNode.kt @@ -73,6 +73,8 @@ import com.jerboa.ui.theme.XXL_PADDING import com.jerboa.ui.theme.colorList import com.jerboa.ui.theme.muted import it.vercruysse.lemmyapi.v0x19.datatypes.* +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList @Composable @@ -172,8 +174,8 @@ fun CommentBodyPreview() { fun LazyListScope.commentNodeItem( node: CommentNode, - admins: List, - moderators: List?, + admins: ImmutableList, + moderators: ImmutableList?, increaseLazyListIndexTracker: () -> Unit, addToParentIndexes: () -> Unit, isFlat: Boolean, @@ -429,8 +431,8 @@ fun LazyListScope.commentNodeItem( fun LazyListScope.missingCommentNodeItem( node: MissingCommentNode, - admins: List, - moderators: List?, + admins: ImmutableList, + moderators: ImmutableList?, increaseLazyListIndexTracker: () -> Unit, addToParentIndexes: () -> Unit, isFlat: Boolean, @@ -665,8 +667,8 @@ fun PostAndCommunityContextHeaderPreview() { @Composable fun CommentFooterLine( commentView: CommentView, - admins: List, - moderators: List?, + admins: ImmutableList, + moderators: ImmutableList?, enableDownVotes: Boolean, instantScores: InstantScores, onUpvoteClick: () -> Unit, @@ -799,8 +801,8 @@ fun CommentNodesPreview() { val tree = buildCommentsTree(comments, null) CommentNodes( nodes = tree, - admins = listOf(), - moderators = listOf(), + admins = persistentListOf(), + moderators = persistentListOf(), increaseLazyListIndexTracker = {}, addToParentIndexes = {}, isFlat = false, diff --git a/app/src/main/java/com/jerboa/ui/components/comment/CommentNodes.kt b/app/src/main/java/com/jerboa/ui/components/comment/CommentNodes.kt index 3ade2c552..e6fe337ba 100644 --- a/app/src/main/java/com/jerboa/ui/components/comment/CommentNodes.kt +++ b/app/src/main/java/com/jerboa/ui/components/comment/CommentNodes.kt @@ -22,8 +22,8 @@ import kotlinx.collections.immutable.ImmutableList @Composable fun CommentNodes( nodes: ImmutableList, - admins: List, - moderators: List?, + admins: ImmutableList, + moderators: ImmutableList?, increaseLazyListIndexTracker: () -> Unit, addToParentIndexes: () -> Unit, isFlat: Boolean, @@ -106,8 +106,8 @@ fun CommentNodes( fun LazyListScope.commentNodeItems( nodes: ImmutableList, - admins: List, - moderators: List?, + admins: ImmutableList, + moderators: ImmutableList?, increaseLazyListIndexTracker: () -> Unit, addToParentIndexes: () -> Unit, isFlat: Boolean, diff --git a/app/src/main/java/com/jerboa/ui/components/post/PostActivity.kt b/app/src/main/java/com/jerboa/ui/components/post/PostActivity.kt index 04785506e..fa1c745a5 100644 --- a/app/src/main/java/com/jerboa/ui/components/post/PostActivity.kt +++ b/app/src/main/java/com/jerboa/ui/components/post/PostActivity.kt @@ -88,6 +88,7 @@ import com.jerboa.ui.components.post.edit.PostEditReturn import com.jerboa.ui.components.remove.comment.CommentRemoveReturn import it.vercruysse.lemmyapi.dto.CommentSortType import it.vercruysse.lemmyapi.v0x19.datatypes.* +import kotlinx.collections.immutable.toImmutableList object PostViewReturn { const val POST_VIEW = "post-view::return(post-view)" @@ -280,7 +281,7 @@ fun PostActivity( is ApiState.Failure -> ApiErrorText(postRes.msg, padding) is ApiState.Success -> { val postView = postRes.data.post_view - val moderators = postRes.data.moderators + val moderators = postRes.data.moderators.toImmutableList() if (!account.isAnon()) appState.addReturn(PostViewReturn.POST_VIEW, postView.copy(read = true)) LazyColumn( From dd0390523d1b9e3a7c3ac58523d8272d9f9c8845 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 11 Jan 2024 10:34:18 -0500 Subject: [PATCH 04/12] Surrounding canMod with remember. --- .../jerboa/ui/components/comment/CommentNode.kt | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/jerboa/ui/components/comment/CommentNode.kt b/app/src/main/java/com/jerboa/ui/components/comment/CommentNode.kt index 5a1e1093d..5242438d1 100644 --- a/app/src/main/java/com/jerboa/ui/components/comment/CommentNode.kt +++ b/app/src/main/java/com/jerboa/ui/components/comment/CommentNode.kt @@ -691,6 +691,15 @@ fun CommentFooterLine( ) { var showMoreOptions by remember { mutableStateOf(false) } + val canMod = remember { + canMod( + creatorId = commentView.comment.creator_id, + admins = admins, + moderators = moderators, + myId = account.id, + ) + } + if (showMoreOptions) { CommentOptionsDropdown( commentView = commentView, @@ -704,13 +713,7 @@ fun CommentFooterLine( onCommentLinkClick = onCommentLinkClick, onPersonClick = onPersonClick, isCreator = account.id == commentView.creator.id, - canMod = - canMod( - creatorId = commentView.comment.creator_id, - admins = admins, - moderators = moderators, - myId = account.id, - ), + canMod = canMod, viewSource = viewSource, ) } From 5af719ad0866f90cc854ec3e3ad5afe94e154e99 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 11 Jan 2024 11:44:52 -0500 Subject: [PATCH 05/12] Adding ability to remove and restore posts. #1182 --- .../main/java/com/jerboa/JerboaAppState.kt | 7 ++ app/src/main/java/com/jerboa/MainActivity.kt | 10 ++ ...ViewModel.kt => CommentRemoveViewModel.kt} | 5 +- .../com/jerboa/model/PostRemoveViewModel.kt | 69 ++++++++++++++ .../ui/components/comment/CommentNode.kt | 17 ++-- .../comment/CommentOptionsDropdown.kt | 4 +- .../com/jerboa/ui/components/common/Route.kt | 1 + .../components/community/CommunityActivity.kt | 15 +++ .../jerboa/ui/components/home/HomeActivity.kt | 8 ++ .../person/PersonProfileActivity.kt | 8 ++ .../jerboa/ui/components/post/PostActivity.kt | 7 ++ .../jerboa/ui/components/post/PostListing.kt | 59 ++++++++++++ .../jerboa/ui/components/post/PostListings.kt | 11 +++ .../post/composables/PostOptionsDropdown.kt | 22 +++++ .../remove/comment/CommentRemoveActivity.kt | 8 +- .../remove/post/PostRemoveActivity.kt | 95 +++++++++++++++++++ app/src/main/res/values/strings.xml | 3 + 17 files changed, 333 insertions(+), 16 deletions(-) rename app/src/main/java/com/jerboa/model/{RemoveViewModel.kt => CommentRemoveViewModel.kt} (94%) create mode 100644 app/src/main/java/com/jerboa/model/PostRemoveViewModel.kt create mode 100644 app/src/main/java/com/jerboa/ui/components/remove/post/PostRemoveActivity.kt diff --git a/app/src/main/java/com/jerboa/JerboaAppState.kt b/app/src/main/java/com/jerboa/JerboaAppState.kt index 4bf92e054..5aea1aabf 100644 --- a/app/src/main/java/com/jerboa/JerboaAppState.kt +++ b/app/src/main/java/com/jerboa/JerboaAppState.kt @@ -20,10 +20,12 @@ import com.jerboa.ui.components.post.create.CreatePostReturn import com.jerboa.ui.components.post.edit.PostEditReturn import com.jerboa.ui.components.privatemessage.PrivateMessage import com.jerboa.ui.components.remove.comment.CommentRemoveReturn +import com.jerboa.ui.components.remove.post.PostRemoveReturn import it.vercruysse.lemmyapi.v0x19.datatypes.Comment import it.vercruysse.lemmyapi.v0x19.datatypes.CommentView import it.vercruysse.lemmyapi.v0x19.datatypes.Community import it.vercruysse.lemmyapi.v0x19.datatypes.CommunityView +import it.vercruysse.lemmyapi.v0x19.datatypes.Post import it.vercruysse.lemmyapi.v0x19.datatypes.PostView import it.vercruysse.lemmyapi.v0x19.datatypes.PrivateMessageView import kotlinx.coroutines.CoroutineScope @@ -70,6 +72,11 @@ class JerboaAppState( navController.navigate(Route.PostReportArgs.makeRoute(id = "$id")) } + fun toPostRemove(post: Post) { + sendReturnForwards(PostRemoveReturn.POST_SEND, post) + navController.navigate(Route.POST_REMOVE) + } + fun toCommentRemove(comment: Comment) { sendReturnForwards(CommentRemoveReturn.COMMENT_SEND, comment) navController.navigate(Route.COMMENT_REMOVE) diff --git a/app/src/main/java/com/jerboa/MainActivity.kt b/app/src/main/java/com/jerboa/MainActivity.kt index c51a49271..4ae6122b8 100644 --- a/app/src/main/java/com/jerboa/MainActivity.kt +++ b/app/src/main/java/com/jerboa/MainActivity.kt @@ -62,6 +62,7 @@ import com.jerboa.ui.components.post.edit.PostEditActivity import com.jerboa.ui.components.privatemessage.CreatePrivateMessageActivity import com.jerboa.ui.components.privatemessage.PrivateMessageReplyActivity import com.jerboa.ui.components.remove.comment.CommentRemoveActivity +import com.jerboa.ui.components.remove.post.PostRemoveActivity import com.jerboa.ui.components.report.comment.CreateCommentReportActivity import com.jerboa.ui.components.report.post.CreatePostReportActivity import com.jerboa.ui.components.settings.SettingsActivity @@ -566,6 +567,15 @@ class MainActivity : AppCompatActivity() { ) } + composable( + route = Route.POST_REMOVE, + ) { + PostRemoveActivity( + appState = appState, + accountViewModel = accountViewModel, + ) + } + composable( route = Route.POST_REPORT, arguments = diff --git a/app/src/main/java/com/jerboa/model/RemoveViewModel.kt b/app/src/main/java/com/jerboa/model/CommentRemoveViewModel.kt similarity index 94% rename from app/src/main/java/com/jerboa/model/RemoveViewModel.kt rename to app/src/main/java/com/jerboa/model/CommentRemoveViewModel.kt index ab4794389..d9fd69cae 100644 --- a/app/src/main/java/com/jerboa/model/RemoveViewModel.kt +++ b/app/src/main/java/com/jerboa/model/CommentRemoveViewModel.kt @@ -14,17 +14,18 @@ import com.jerboa.api.API import com.jerboa.api.ApiState import com.jerboa.api.toApiState import com.jerboa.ui.components.common.apiErrorToast +import it.vercruysse.lemmyapi.v0x19.datatypes.CommentId import it.vercruysse.lemmyapi.v0x19.datatypes.CommentResponse import it.vercruysse.lemmyapi.v0x19.datatypes.CommentView import it.vercruysse.lemmyapi.v0x19.datatypes.RemoveComment import kotlinx.coroutines.launch -class RemoveViewModel : ViewModel() { +class CommentRemoveViewModel : ViewModel() { var commentRemoveRes: ApiState by mutableStateOf(ApiState.Empty) private set fun removeOrRestoreComment( - commentId: Int, + commentId: CommentId, removed: Boolean, reason: String, ctx: Context, diff --git a/app/src/main/java/com/jerboa/model/PostRemoveViewModel.kt b/app/src/main/java/com/jerboa/model/PostRemoveViewModel.kt new file mode 100644 index 000000000..57767752b --- /dev/null +++ b/app/src/main/java/com/jerboa/model/PostRemoveViewModel.kt @@ -0,0 +1,69 @@ +package com.jerboa.model + +import android.content.Context +import android.util.Log +import android.widget.Toast +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.focus.FocusManager +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.jerboa.R +import com.jerboa.api.API +import com.jerboa.api.ApiState +import com.jerboa.api.toApiState +import com.jerboa.ui.components.common.apiErrorToast +import it.vercruysse.lemmyapi.v0x19.datatypes.PostId +import it.vercruysse.lemmyapi.v0x19.datatypes.PostResponse +import it.vercruysse.lemmyapi.v0x19.datatypes.PostView +import it.vercruysse.lemmyapi.v0x19.datatypes.RemovePost +import kotlinx.coroutines.launch + +class PostRemoveViewModel : ViewModel() { + var postRemoveRes: ApiState by mutableStateOf(ApiState.Empty) + private set + + fun removeOrRestorePost( + postId: PostId, + removed: Boolean, + reason: String, + ctx: Context, + focusManager: FocusManager, + onSuccess: (PostView) -> Unit, + ) { + viewModelScope.launch { + val form = + RemovePost( + post_id = postId, + removed = removed, + reason = reason, + ) + + postRemoveRes = ApiState.Loading + postRemoveRes = API.getInstance().removePost(form).toApiState() + + when (val res = postRemoveRes) { + is ApiState.Failure -> { + Log.d("removePost", "failed", res.msg) + apiErrorToast(msg = res.msg, ctx = ctx) + } + + is ApiState.Success -> { + val message = + if (removed) { + ctx.getString(R.string.remove_view_model_post_removed) + } else { + ctx.getString(R.string.remove_view_model_post_restored) + } + val postView = res.data.post_view + Toast.makeText(ctx, message, Toast.LENGTH_SHORT).show() + + focusManager.clearFocus() + onSuccess(postView) + } + else -> {} + } + } + } +} diff --git a/app/src/main/java/com/jerboa/ui/components/comment/CommentNode.kt b/app/src/main/java/com/jerboa/ui/components/comment/CommentNode.kt index 5242438d1..5c0aede12 100644 --- a/app/src/main/java/com/jerboa/ui/components/comment/CommentNode.kt +++ b/app/src/main/java/com/jerboa/ui/components/comment/CommentNode.kt @@ -691,14 +691,15 @@ fun CommentFooterLine( ) { var showMoreOptions by remember { mutableStateOf(false) } - val canMod = remember { - canMod( - creatorId = commentView.comment.creator_id, - admins = admins, - moderators = moderators, - myId = account.id, - ) - } + val canMod = + remember { + canMod( + creatorId = commentView.comment.creator_id, + admins = admins, + moderators = moderators, + myId = account.id, + ) + } if (showMoreOptions) { CommentOptionsDropdown( diff --git a/app/src/main/java/com/jerboa/ui/components/comment/CommentOptionsDropdown.kt b/app/src/main/java/com/jerboa/ui/components/comment/CommentOptionsDropdown.kt index a0eee5ff0..510113a6e 100644 --- a/app/src/main/java/com/jerboa/ui/components/comment/CommentOptionsDropdown.kt +++ b/app/src/main/java/com/jerboa/ui/components/comment/CommentOptionsDropdown.kt @@ -3,7 +3,6 @@ package com.jerboa.ui.components.comment import android.widget.Toast import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Block -import androidx.compose.material.icons.outlined.Close import androidx.compose.material.icons.outlined.Comment import androidx.compose.material.icons.outlined.ContentCopy import androidx.compose.material.icons.outlined.CopyAll @@ -11,6 +10,7 @@ import androidx.compose.material.icons.outlined.Delete import androidx.compose.material.icons.outlined.Description import androidx.compose.material.icons.outlined.Edit import androidx.compose.material.icons.outlined.Flag +import androidx.compose.material.icons.outlined.Gavel import androidx.compose.material.icons.outlined.Link import androidx.compose.material.icons.outlined.Person import androidx.compose.material.icons.outlined.Restore @@ -178,7 +178,7 @@ fun CommentOptionsDropdown( if (commentView.comment.removed) { Pair(stringResource(R.string.restore_comment), Icons.Outlined.Restore) } else { - Pair(stringResource(R.string.remove_comment), Icons.Outlined.Close) + Pair(stringResource(R.string.remove_comment), Icons.Outlined.Gavel) } PopupMenuItem( diff --git a/app/src/main/java/com/jerboa/ui/components/common/Route.kt b/app/src/main/java/com/jerboa/ui/components/common/Route.kt index 514b39c21..959e8c76d 100644 --- a/app/src/main/java/com/jerboa/ui/components/common/Route.kt +++ b/app/src/main/java/com/jerboa/ui/components/common/Route.kt @@ -31,6 +31,7 @@ object Route { const val SITE_SIDEBAR = "siteSidebar" const val COMMENT_EDIT = "commentEdit" const val POST_EDIT = "postEdit" + const val POST_REMOVE = "postRemove" const val PRIVATE_MESSAGE_REPLY = "privateMessageReply" const val COMMENT_REMOVE = "commentRemove" val CREATE_PRIVATE_MESSAGE = CreatePrivateMessageArgs.route diff --git a/app/src/main/java/com/jerboa/ui/components/community/CommunityActivity.kt b/app/src/main/java/com/jerboa/ui/components/community/CommunityActivity.kt index c603608b7..6b5ae49b0 100644 --- a/app/src/main/java/com/jerboa/ui/components/community/CommunityActivity.kt +++ b/app/src/main/java/com/jerboa/ui/components/community/CommunityActivity.kt @@ -56,6 +56,7 @@ import com.jerboa.ui.components.common.isRefreshing import com.jerboa.ui.components.post.PostListings import com.jerboa.ui.components.post.PostViewReturn import com.jerboa.ui.components.post.edit.PostEditReturn +import com.jerboa.ui.components.remove.post.PostRemoveReturn import it.vercruysse.lemmyapi.dto.SubscribedType import it.vercruysse.lemmyapi.v0x19.datatypes.BlockCommunity import it.vercruysse.lemmyapi.v0x19.datatypes.CommunityId @@ -96,6 +97,7 @@ fun CommunityActivity( viewModel(factory = CommunityViewModel.Companion.Factory(communityArg)) appState.ConsumeReturn(PostEditReturn.POST_VIEW, communityViewModel::updatePost) + appState.ConsumeReturn(PostRemoveReturn.POST_VIEW, communityViewModel::updatePost) appState.ConsumeReturn(PostViewReturn.POST_VIEW, communityViewModel::updatePost) val pullRefreshState = @@ -106,6 +108,14 @@ fun CommunityActivity( }, ) + val moderators = + when (val communityRes = communityViewModel.communityRes) { + is ApiState.Success -> communityRes.data.moderators.toImmutableList() + else -> { + null + } + } + Scaffold( modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), snackbarHost = { JerboaSnackbarHost(snackbarHostState) }, @@ -192,6 +202,8 @@ fun CommunityActivity( is ApiState.Holder -> { PostListings( posts = postsRes.data.posts.toImmutableList(), + admins = siteViewModel.admins(), + moderators = moderators, contentAboveListings = { when (val communityRes = communityViewModel.communityRes) { is ApiState.Success -> { @@ -315,6 +327,9 @@ fun CommunityActivity( onReportClick = { postView -> appState.toPostReport(id = postView.post.id) }, + onRemoveClick = { pv -> + appState.toPostRemove(post = pv.post) + }, onCommunityClick = { community -> appState.toCommunity(id = community.id) }, diff --git a/app/src/main/java/com/jerboa/ui/components/home/HomeActivity.kt b/app/src/main/java/com/jerboa/ui/components/home/HomeActivity.kt index c5210d21c..e2308be62 100644 --- a/app/src/main/java/com/jerboa/ui/components/home/HomeActivity.kt +++ b/app/src/main/java/com/jerboa/ui/components/home/HomeActivity.kt @@ -62,6 +62,7 @@ import com.jerboa.ui.components.common.isRefreshing import com.jerboa.ui.components.post.PostListings import com.jerboa.ui.components.post.PostViewReturn import com.jerboa.ui.components.post.edit.PostEditReturn +import com.jerboa.ui.components.remove.post.PostRemoveReturn import it.vercruysse.lemmyapi.v0x19.datatypes.CreatePostLike import it.vercruysse.lemmyapi.v0x19.datatypes.DeletePost import it.vercruysse.lemmyapi.v0x19.datatypes.MarkPostAsRead @@ -104,6 +105,7 @@ fun HomeActivity( val snackbarHostState = remember(account) { SnackbarHostState() } appState.ConsumeReturn(PostEditReturn.POST_VIEW, homeViewModel::updatePost) + appState.ConsumeReturn(PostRemoveReturn.POST_VIEW, homeViewModel::updatePost) appState.ConsumeReturn(PostViewReturn.POST_VIEW, homeViewModel::updatePost) LaunchedEffect(account) { @@ -251,6 +253,9 @@ fun MainPostListingsContent( PostListings( posts = posts, + admins = siteViewModel.admins(), + // No community moderators available here + moderators = null, contentAboveListings = { if (taglines !== null) Taglines(taglines = taglines.toImmutableList()) }, onUpvoteClick = { postView -> account.doIfReadyElseDisplayInfo( @@ -335,6 +340,9 @@ fun MainPostListingsContent( onReportClick = { postView -> appState.toPostReport(id = postView.post.id) }, + onRemoveClick = { pv -> + appState.toPostRemove(post = pv.post) + }, onCommunityClick = { community -> appState.toCommunity(id = community.id) }, diff --git a/app/src/main/java/com/jerboa/ui/components/person/PersonProfileActivity.kt b/app/src/main/java/com/jerboa/ui/components/person/PersonProfileActivity.kt index c7cda55b5..c8391941e 100644 --- a/app/src/main/java/com/jerboa/ui/components/person/PersonProfileActivity.kt +++ b/app/src/main/java/com/jerboa/ui/components/person/PersonProfileActivity.kt @@ -81,6 +81,7 @@ import com.jerboa.ui.components.post.PostListings import com.jerboa.ui.components.post.PostViewReturn import com.jerboa.ui.components.post.edit.PostEditReturn import com.jerboa.ui.components.remove.comment.CommentRemoveReturn +import com.jerboa.ui.components.remove.post.PostRemoveReturn import com.jerboa.ui.theme.MEDIUM_PADDING import it.vercruysse.lemmyapi.v0x19.datatypes.BlockPerson import it.vercruysse.lemmyapi.v0x19.datatypes.CommentView @@ -130,6 +131,7 @@ fun PersonProfileActivity( viewModel(factory = PersonProfileViewModel.Companion.Factory(personArg, savedMode)) appState.ConsumeReturn(PostEditReturn.POST_VIEW, personProfileViewModel::updatePost) + appState.ConsumeReturn(PostRemoveReturn.POST_VIEW, personProfileViewModel::updatePost) appState.ConsumeReturn(CommentEditReturn.COMMENT_VIEW, personProfileViewModel::updateComment) appState.ConsumeReturn(CommentRemoveReturn.COMMENT_VIEW, personProfileViewModel::updateComment) @@ -453,6 +455,9 @@ fun UserTabs( is ApiState.Holder -> { PostListings( posts = profileRes.data.posts.toImmutableList(), + admins = siteViewModel.admins(), + // No community moderators available here + moderators = null, onUpvoteClick = { pv -> account.doIfReadyElseDisplayInfo( appState, @@ -536,6 +541,9 @@ fun UserTabs( onReportClick = { pv -> appState.toPostReport(id = pv.post.id) }, + onRemoveClick = { pv -> + appState.toPostRemove(post = pv.post) + }, onCommunityClick = { community -> appState.toCommunity(id = community.id) }, diff --git a/app/src/main/java/com/jerboa/ui/components/post/PostActivity.kt b/app/src/main/java/com/jerboa/ui/components/post/PostActivity.kt index fa1c745a5..5b941cd83 100644 --- a/app/src/main/java/com/jerboa/ui/components/post/PostActivity.kt +++ b/app/src/main/java/com/jerboa/ui/components/post/PostActivity.kt @@ -86,6 +86,7 @@ import com.jerboa.ui.components.common.isRefreshing import com.jerboa.ui.components.common.simpleVerticalScrollbar import com.jerboa.ui.components.post.edit.PostEditReturn import com.jerboa.ui.components.remove.comment.CommentRemoveReturn +import com.jerboa.ui.components.remove.post.PostRemoveReturn import it.vercruysse.lemmyapi.dto.CommentSortType import it.vercruysse.lemmyapi.v0x19.datatypes.* import kotlinx.collections.immutable.toImmutableList @@ -140,6 +141,7 @@ fun PostActivity( val postViewModel: PostViewModel = viewModel(factory = PostViewModel.Companion.Factory(id)) appState.ConsumeReturn(PostEditReturn.POST_VIEW, postViewModel::updatePost) + appState.ConsumeReturn(PostRemoveReturn.POST_VIEW, postViewModel::updatePost) appState.ConsumeReturn(CommentReplyReturn.COMMENT_VIEW, postViewModel::appendComment) appState.ConsumeReturn(CommentEditReturn.COMMENT_VIEW, postViewModel::updateComment) appState.ConsumeReturn(CommentRemoveReturn.COMMENT_VIEW, postViewModel::updateComment) @@ -295,6 +297,8 @@ fun PostActivity( item(key = "${postView.post.id}_listing", "post_listing") { PostListing( postView = postView, + admins = siteViewModel.admins(), + moderators = moderators, onUpvoteClick = { pv -> account.doIfReadyElseDisplayInfo( appState, @@ -388,6 +392,9 @@ fun PostActivity( onReportClick = { pv -> appState.toPostReport(id = pv.post.id) }, + onRemoveClick = { pv -> + appState.toPostRemove(post = pv.post) + }, onPersonClick = appState::toProfile, showReply = true, // Do nothing fullBody = true, diff --git a/app/src/main/java/com/jerboa/ui/components/post/PostListing.kt b/app/src/main/java/com/jerboa/ui/components/post/PostListing.kt index 4e01aa821..5d71c6ca9 100644 --- a/app/src/main/java/com/jerboa/ui/components/post/PostListing.kt +++ b/app/src/main/java/com/jerboa/ui/components/post/PostListing.kt @@ -26,6 +26,7 @@ import androidx.compose.material.icons.outlined.Comment import androidx.compose.material.icons.outlined.CommentsDisabled import androidx.compose.material.icons.outlined.Delete import androidx.compose.material.icons.outlined.Forum +import androidx.compose.material.icons.outlined.Gavel import androidx.compose.material.icons.outlined.Link import androidx.compose.material.icons.outlined.MoreVert import androidx.compose.material.icons.outlined.PushPin @@ -62,6 +63,7 @@ import com.jerboa.PostViewMode import com.jerboa.R import com.jerboa.VoteType import com.jerboa.calculateNewInstantScores +import com.jerboa.canMod import com.jerboa.datatypes.sampleImagePostView import com.jerboa.datatypes.sampleLinkNoThumbnailPostView import com.jerboa.datatypes.sampleLinkPostView @@ -113,6 +115,8 @@ import com.jerboa.ui.theme.XXL_PADDING import com.jerboa.ui.theme.jerboaColorScheme import com.jerboa.ui.theme.muted import it.vercruysse.lemmyapi.v0x19.datatypes.* +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.CoroutineScope @Composable @@ -208,6 +212,13 @@ fun PostHeaderLine( tint = MaterialTheme.colorScheme.error, ) } + if (postView.post.removed) { + Icon( + imageVector = Icons.Outlined.Gavel, + contentDescription = stringResource(R.string.postListing_removed), + tint = MaterialTheme.colorScheme.error, + ) + } } ScoreAndTime( score = score, @@ -532,6 +543,8 @@ fun PreviewSourcePost() { @Composable fun PostFooterLine( postView: PostView, + admins: ImmutableList, + moderators: ImmutableList?, instantScores: InstantScores, onUpvoteClick: () -> Unit, onDownvoteClick: () -> Unit, @@ -540,6 +553,7 @@ fun PostFooterLine( onEditPostClick: (postView: PostView) -> Unit, onDeletePostClick: (postView: PostView) -> Unit, onReportClick: (postView: PostView) -> Unit, + onRemoveClick: (postView: PostView) -> Unit, onCommunityClick: (community: Community) -> Unit, onPersonClick: (personId: Int) -> Unit, onViewSourceClick: () -> Unit, @@ -555,6 +569,16 @@ fun PostFooterLine( ) { var showMoreOptions by remember { mutableStateOf(false) } + val canMod = + remember { + canMod( + creatorId = postView.creator.id, + admins = admins, + moderators = moderators, + myId = account.id, + ) + } + if (showMoreOptions) { PostOptionsDropdown( postView = postView, @@ -564,8 +588,10 @@ fun PostFooterLine( onEditPostClick = onEditPostClick, onDeletePostClick = onDeletePostClick, onReportClick = onReportClick, + onRemoveClick = onRemoveClick, onViewSourceClick = onViewSourceClick, isCreator = account.id == postView.creator.id, + canMod = canMod, viewSource = viewSource, showViewSource = fromPostActivity, scope = scope, @@ -745,6 +771,8 @@ fun PostFooterLinePreview() { ) PostFooterLine( postView = postView, + admins = persistentListOf(), + moderators = persistentListOf(), instantScores = instantScores, onUpvoteClick = {}, onDownvoteClick = {}, @@ -753,6 +781,7 @@ fun PostFooterLinePreview() { onEditPostClick = {}, onDeletePostClick = {}, onReportClick = {}, + onRemoveClick = {}, onCommunityClick = {}, onPersonClick = {}, onViewSourceClick = {}, @@ -771,6 +800,8 @@ fun PostFooterLinePreview() { fun PreviewPostListingCard() { PostListing( postView = samplePostView, + admins = persistentListOf(), + moderators = persistentListOf(), useCustomTabs = false, usePrivateTabs = false, onUpvoteClick = {}, @@ -782,6 +813,7 @@ fun PreviewPostListingCard() { onEditPostClick = {}, onDeletePostClick = {}, onReportClick = {}, + onRemoveClick = {}, onPersonClick = {}, fullBody = false, account = AnonAccount, @@ -803,6 +835,8 @@ fun PreviewPostListingCard() { fun PreviewLinkPostListing() { PostListing( postView = sampleLinkPostView, + admins = persistentListOf(), + moderators = persistentListOf(), useCustomTabs = false, usePrivateTabs = false, onUpvoteClick = {}, @@ -814,6 +848,7 @@ fun PreviewLinkPostListing() { onEditPostClick = {}, onDeletePostClick = {}, onReportClick = {}, + onRemoveClick = {}, onPersonClick = {}, fullBody = false, account = AnonAccount, @@ -835,6 +870,8 @@ fun PreviewLinkPostListing() { fun PreviewImagePostListingCard() { PostListing( postView = sampleImagePostView, + admins = persistentListOf(), + moderators = persistentListOf(), useCustomTabs = false, usePrivateTabs = false, onUpvoteClick = {}, @@ -846,6 +883,7 @@ fun PreviewImagePostListingCard() { onEditPostClick = {}, onDeletePostClick = {}, onReportClick = {}, + onRemoveClick = {}, onPersonClick = {}, fullBody = false, account = AnonAccount, @@ -867,6 +905,8 @@ fun PreviewImagePostListingCard() { fun PreviewImagePostListingSmallCard() { PostListing( postView = sampleImagePostView, + admins = persistentListOf(), + moderators = persistentListOf(), useCustomTabs = false, usePrivateTabs = false, onUpvoteClick = {}, @@ -878,6 +918,7 @@ fun PreviewImagePostListingSmallCard() { onEditPostClick = {}, onDeletePostClick = {}, onReportClick = {}, + onRemoveClick = {}, onPersonClick = {}, fullBody = false, account = AnonAccount, @@ -899,6 +940,8 @@ fun PreviewImagePostListingSmallCard() { fun PreviewLinkNoThumbnailPostListing() { PostListing( postView = sampleLinkNoThumbnailPostView, + admins = persistentListOf(), + moderators = persistentListOf(), useCustomTabs = false, usePrivateTabs = false, onUpvoteClick = {}, @@ -910,6 +953,7 @@ fun PreviewLinkNoThumbnailPostListing() { onEditPostClick = {}, onDeletePostClick = {}, onReportClick = {}, + onRemoveClick = {}, onPersonClick = {}, fullBody = false, account = AnonAccount, @@ -929,6 +973,8 @@ fun PreviewLinkNoThumbnailPostListing() { @Composable fun PostListing( postView: PostView, + admins: ImmutableList, + moderators: ImmutableList?, useCustomTabs: Boolean, usePrivateTabs: Boolean, onUpvoteClick: (postView: PostView) -> Unit, @@ -940,6 +986,7 @@ fun PostListing( onEditPostClick: (postView: PostView) -> Unit, onDeletePostClick: (postView: PostView) -> Unit, onReportClick: (postView: PostView) -> Unit, + onRemoveClick: (postView: PostView) -> Unit, onPersonClick: (personId: Int) -> Unit, showReply: Boolean = false, showCommunityName: Boolean = true, @@ -975,6 +1022,8 @@ fun PostListing( PostViewMode.Card -> PostListingCard( postView = postView, + admins = admins, + moderators = moderators, instantScores = instantScores.value, onUpvoteClick = { instantScores.value = @@ -999,6 +1048,7 @@ fun PostListing( onEditPostClick = onEditPostClick, onDeletePostClick = onDeletePostClick, onReportClick = onReportClick, + onRemoveClick = onRemoveClick, onPersonClick = onPersonClick, onViewSourceClick = { viewSource = !viewSource @@ -1024,6 +1074,8 @@ fun PostListing( PostViewMode.SmallCard -> PostListingCard( postView = postView, + admins = admins, + moderators = moderators, instantScores = instantScores.value, onUpvoteClick = { instantScores.value = @@ -1048,6 +1100,7 @@ fun PostListing( onEditPostClick = onEditPostClick, onDeletePostClick = onDeletePostClick, onReportClick = onReportClick, + onRemoveClick = onRemoveClick, onPersonClick = onPersonClick, onViewSourceClick = { viewSource = !viewSource @@ -1430,6 +1483,8 @@ fun PostListingListWithThumbPreview() { @Composable fun PostListingCard( postView: PostView, + admins: ImmutableList, + moderators: ImmutableList?, instantScores: InstantScores, onUpvoteClick: () -> Unit, onDownvoteClick: () -> Unit, @@ -1440,6 +1495,7 @@ fun PostListingCard( onEditPostClick: (postView: PostView) -> Unit, onDeletePostClick: (postView: PostView) -> Unit, onReportClick: (postView: PostView) -> Unit, + onRemoveClick: (postView: PostView) -> Unit, onPersonClick: (personId: Int) -> Unit, onViewSourceClick: () -> Unit, viewSource: Boolean, @@ -1505,6 +1561,8 @@ fun PostListingCard( // Footer bar PostFooterLine( postView = postView, + admins = admins, + moderators = moderators, instantScores = instantScores, onUpvoteClick = onUpvoteClick, onDownvoteClick = onDownvoteClick, @@ -1513,6 +1571,7 @@ fun PostListingCard( onEditPostClick = onEditPostClick, onDeletePostClick = onDeletePostClick, onReportClick = onReportClick, + onRemoveClick = onRemoveClick, onCommunityClick = onCommunityClick, onPersonClick = onPersonClick, onViewSourceClick = onViewSourceClick, diff --git a/app/src/main/java/com/jerboa/ui/components/post/PostListings.kt b/app/src/main/java/com/jerboa/ui/components/post/PostListings.kt index 01c9a133f..6d259d9ac 100644 --- a/app/src/main/java/com/jerboa/ui/components/post/PostListings.kt +++ b/app/src/main/java/com/jerboa/ui/components/post/PostListings.kt @@ -30,6 +30,8 @@ import com.jerboa.ui.components.common.RetryLoadingPosts import com.jerboa.ui.components.common.simpleVerticalScrollbar import com.jerboa.ui.theme.SMALL_PADDING import it.vercruysse.lemmyapi.v0x19.datatypes.Community +import it.vercruysse.lemmyapi.v0x19.datatypes.CommunityModeratorView +import it.vercruysse.lemmyapi.v0x19.datatypes.PersonView import it.vercruysse.lemmyapi.v0x19.datatypes.PostView import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -37,6 +39,8 @@ import kotlinx.collections.immutable.persistentListOf @Composable fun PostListings( posts: ImmutableList, + admins: ImmutableList, + moderators: ImmutableList?, contentAboveListings: @Composable () -> Unit = {}, onUpvoteClick: (postView: PostView) -> Unit, onDownvoteClick: (postView: PostView) -> Unit, @@ -45,6 +49,7 @@ fun PostListings( onEditPostClick: (postView: PostView) -> Unit, onDeletePostClick: (postView: PostView) -> Unit, onReportClick: (postView: PostView) -> Unit, + onRemoveClick: (postView: PostView) -> Unit, onCommunityClick: (community: Community) -> Unit, onPersonClick: (personId: Int) -> Unit, loadMorePosts: () -> Unit, @@ -87,6 +92,8 @@ fun PostListings( ) { index, postView -> PostListing( postView = postView, + admins = admins, + moderators = moderators, useCustomTabs = useCustomTabs, usePrivateTabs = usePrivateTabs, onUpvoteClick = onUpvoteClick, @@ -97,6 +104,7 @@ fun PostListings( onEditPostClick = onEditPostClick, onDeletePostClick = onDeletePostClick, onReportClick = onReportClick, + onRemoveClick = onRemoveClick, onPersonClick = onPersonClick, showCommunityName = showCommunityName, fullBody = false, @@ -152,6 +160,8 @@ fun PostListings( fun PreviewPostListings() { PostListings( posts = persistentListOf(samplePostView, sampleLinkPostView), + admins = persistentListOf(), + moderators = persistentListOf(), onUpvoteClick = {}, onDownvoteClick = {}, onPostClick = {}, @@ -159,6 +169,7 @@ fun PreviewPostListings() { onEditPostClick = {}, onDeletePostClick = {}, onReportClick = {}, + onRemoveClick = {}, onCommunityClick = {}, onPersonClick = {}, loadMorePosts = {}, diff --git a/app/src/main/java/com/jerboa/ui/components/post/composables/PostOptionsDropdown.kt b/app/src/main/java/com/jerboa/ui/components/post/composables/PostOptionsDropdown.kt index 4c4335a7f..8e07c81da 100644 --- a/app/src/main/java/com/jerboa/ui/components/post/composables/PostOptionsDropdown.kt +++ b/app/src/main/java/com/jerboa/ui/components/post/composables/PostOptionsDropdown.kt @@ -10,6 +10,7 @@ import androidx.compose.material.icons.outlined.Description import androidx.compose.material.icons.outlined.Edit import androidx.compose.material.icons.outlined.Flag import androidx.compose.material.icons.outlined.Forum +import androidx.compose.material.icons.outlined.Gavel import androidx.compose.material.icons.outlined.Link import androidx.compose.material.icons.outlined.Person import androidx.compose.material.icons.outlined.Restore @@ -54,8 +55,10 @@ fun PostOptionsDropdown( onEditPostClick: (PostView) -> Unit, onDeletePostClick: (PostView) -> Unit, onReportClick: (PostView) -> Unit, + onRemoveClick: (PostView) -> Unit, onViewSourceClick: () -> Unit, isCreator: Boolean, + canMod: Boolean, viewSource: Boolean, showViewSource: Boolean, scope: CoroutineScope, @@ -398,6 +401,25 @@ fun PostOptionsDropdown( onReportClick(postView) }, ) + + if (canMod) { + Divider() + val (removeText, removeIcon) = + if (postView.post.removed) { + Pair(stringResource(R.string.restore_post), Icons.Outlined.Restore) + } else { + Pair(stringResource(R.string.remove_post), Icons.Outlined.Gavel) + } + + PopupMenuItem( + text = removeText, + icon = removeIcon, + onClick = { + onDismissRequest() + onRemoveClick(postView) + }, + ) + } } } } diff --git a/app/src/main/java/com/jerboa/ui/components/remove/comment/CommentRemoveActivity.kt b/app/src/main/java/com/jerboa/ui/components/remove/comment/CommentRemoveActivity.kt index 3d4d53a3d..92c94161d 100644 --- a/app/src/main/java/com/jerboa/ui/components/remove/comment/CommentRemoveActivity.kt +++ b/app/src/main/java/com/jerboa/ui/components/remove/comment/CommentRemoveActivity.kt @@ -19,7 +19,7 @@ import com.jerboa.R import com.jerboa.api.ApiState import com.jerboa.db.entity.isAnon import com.jerboa.model.AccountViewModel -import com.jerboa.model.RemoveViewModel +import com.jerboa.model.CommentRemoveViewModel import com.jerboa.ui.components.common.ActionTopBar import com.jerboa.ui.components.common.getCurrentAccount import com.jerboa.ui.components.remove.RemoveItemBody @@ -40,7 +40,7 @@ fun CommentRemoveActivity( val ctx = LocalContext.current val account = getCurrentAccount(accountViewModel = accountViewModel) - val removeViewModel: RemoveViewModel = viewModel() + val commentRemoveViewModel: CommentRemoveViewModel = viewModel() val comment = appState.getPrevReturn(key = CommentRemoveReturn.COMMENT_SEND) var reason by rememberSaveable(stateSaver = TextFieldValue.Saver) { @@ -49,7 +49,7 @@ fun CommentRemoveActivity( ) } val loading = - when (removeViewModel.commentRemoveRes) { + when (commentRemoveViewModel.commentRemoveRes) { ApiState.Loading -> true else -> false } @@ -64,7 +64,7 @@ fun CommentRemoveActivity( loading = loading, onActionClick = { if (!account.isAnon()) { - removeViewModel.removeOrRestoreComment( + commentRemoveViewModel.removeOrRestoreComment( commentId = comment.id, reason = reason.text, removed = !comment.removed, diff --git a/app/src/main/java/com/jerboa/ui/components/remove/post/PostRemoveActivity.kt b/app/src/main/java/com/jerboa/ui/components/remove/post/PostRemoveActivity.kt new file mode 100644 index 000000000..36defc08a --- /dev/null +++ b/app/src/main/java/com/jerboa/ui/components/remove/post/PostRemoveActivity.kt @@ -0,0 +1,95 @@ +package com.jerboa.ui.components.remove.post + +import android.util.Log +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Send +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.TextFieldValue +import androidx.lifecycle.viewmodel.compose.viewModel +import com.jerboa.JerboaAppState +import com.jerboa.R +import com.jerboa.api.ApiState +import com.jerboa.db.entity.isAnon +import com.jerboa.model.AccountViewModel +import com.jerboa.model.PostRemoveViewModel +import com.jerboa.ui.components.common.ActionTopBar +import com.jerboa.ui.components.common.getCurrentAccount +import com.jerboa.ui.components.remove.RemoveItemBody +import it.vercruysse.lemmyapi.v0x19.datatypes.Post + +object PostRemoveReturn { + const val POST_VIEW = "post-edit::return(post-view)" + const val POST_SEND = "post-edit::send(post-view)" +} + +@Composable +fun PostRemoveActivity( + appState: JerboaAppState, + accountViewModel: AccountViewModel, +) { + Log.d("jerboa", "got to create post remove activity") + + val ctx = LocalContext.current + val account = getCurrentAccount(accountViewModel = accountViewModel) + + val postRemoveViewModel: PostRemoveViewModel = viewModel() + val post = appState.getPrevReturn(key = PostRemoveReturn.POST_SEND) + + var reason by rememberSaveable(stateSaver = TextFieldValue.Saver) { + mutableStateOf( + TextFieldValue(""), + ) + } + val loading = + when (postRemoveViewModel.postRemoveRes) { + ApiState.Loading -> true + else -> false + } + + val focusManager = LocalFocusManager.current + val title = stringResource(if (post.removed) R.string.restore_post else R.string.remove_post) + + Scaffold( + topBar = { + ActionTopBar( + title = title, + loading = loading, + onActionClick = { + if (!account.isAnon()) { + postRemoveViewModel.removeOrRestorePost( + postId = post.id, + reason = reason.text, + removed = !post.removed, + ctx = ctx, + focusManager = focusManager, + ) { postView -> + appState.apply { + addReturn(PostRemoveReturn.POST_VIEW, postView) + navigateUp() + } + } + } + }, + actionText = R.string.form_submit, + actionIcon = Icons.Outlined.Send, + onBackClick = appState::popBackStack, + ) + }, + content = { padding -> + RemoveItemBody( + reason = reason, + onReasonChange = { reason = it }, + account = account, + padding = padding, + ) + }, + ) +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 46e9f8457..8c02687fc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -218,6 +218,7 @@ Report Person Upload Image Deleted + Removed Featured in community Featured locally Go to community @@ -409,5 +410,7 @@ Post restored Remove Comment Restore Comment + Remove Post + Restore Post Type your reason From 8d6568270ec2461a8af5363d4cc5ba8aff8cdf50 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 18 Jan 2024 15:50:18 -0500 Subject: [PATCH 06/12] Fixing jerboaappstate. --- app/src/main/java/com/jerboa/JerboaAppState.kt | 6 ------ app/src/main/java/com/jerboa/MainActivity.kt | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/app/src/main/java/com/jerboa/JerboaAppState.kt b/app/src/main/java/com/jerboa/JerboaAppState.kt index 1d6a04d9f..5aea1aabf 100644 --- a/app/src/main/java/com/jerboa/JerboaAppState.kt +++ b/app/src/main/java/com/jerboa/JerboaAppState.kt @@ -19,15 +19,9 @@ import com.jerboa.ui.components.community.sidebar.CommunityViewSidebar import com.jerboa.ui.components.post.create.CreatePostReturn import com.jerboa.ui.components.post.edit.PostEditReturn import com.jerboa.ui.components.privatemessage.PrivateMessage -<<<<<<< HEAD import com.jerboa.ui.components.remove.comment.CommentRemoveReturn import com.jerboa.ui.components.remove.post.PostRemoveReturn import it.vercruysse.lemmyapi.v0x19.datatypes.Comment -||||||| 21e2222a -======= -import com.jerboa.ui.components.remove.comment.CommentRemoveReturn -import it.vercruysse.lemmyapi.v0x19.datatypes.Comment ->>>>>>> main import it.vercruysse.lemmyapi.v0x19.datatypes.CommentView import it.vercruysse.lemmyapi.v0x19.datatypes.Community import it.vercruysse.lemmyapi.v0x19.datatypes.CommunityView diff --git a/app/src/main/java/com/jerboa/MainActivity.kt b/app/src/main/java/com/jerboa/MainActivity.kt index 57416d757..b8acf24af 100644 --- a/app/src/main/java/com/jerboa/MainActivity.kt +++ b/app/src/main/java/com/jerboa/MainActivity.kt @@ -61,8 +61,8 @@ import com.jerboa.ui.components.post.create.CreatePostActivity import com.jerboa.ui.components.post.edit.PostEditActivity import com.jerboa.ui.components.privatemessage.CreatePrivateMessageActivity import com.jerboa.ui.components.privatemessage.PrivateMessageReplyActivity -import com.jerboa.ui.components.remove.post.PostRemoveActivity import com.jerboa.ui.components.remove.comment.CommentRemoveActivity +import com.jerboa.ui.components.remove.post.PostRemoveActivity import com.jerboa.ui.components.report.comment.CreateCommentReportActivity import com.jerboa.ui.components.report.post.CreatePostReportActivity import com.jerboa.ui.components.settings.SettingsActivity From 2832a7279f0f22a3edf5633a2324ae3d18d107be Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 18 Jan 2024 15:54:21 -0500 Subject: [PATCH 07/12] Removing extra RemoveViewModel. --- .../java/com/jerboa/model/RemoveViewModel.kt | 68 ------------------- .../remove/comment/CommentRemoveActivity.kt | 8 +-- 2 files changed, 4 insertions(+), 72 deletions(-) delete mode 100644 app/src/main/java/com/jerboa/model/RemoveViewModel.kt diff --git a/app/src/main/java/com/jerboa/model/RemoveViewModel.kt b/app/src/main/java/com/jerboa/model/RemoveViewModel.kt deleted file mode 100644 index ab4794389..000000000 --- a/app/src/main/java/com/jerboa/model/RemoveViewModel.kt +++ /dev/null @@ -1,68 +0,0 @@ -package com.jerboa.model - -import android.content.Context -import android.util.Log -import android.widget.Toast -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.compose.ui.focus.FocusManager -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.jerboa.R -import com.jerboa.api.API -import com.jerboa.api.ApiState -import com.jerboa.api.toApiState -import com.jerboa.ui.components.common.apiErrorToast -import it.vercruysse.lemmyapi.v0x19.datatypes.CommentResponse -import it.vercruysse.lemmyapi.v0x19.datatypes.CommentView -import it.vercruysse.lemmyapi.v0x19.datatypes.RemoveComment -import kotlinx.coroutines.launch - -class RemoveViewModel : ViewModel() { - var commentRemoveRes: ApiState by mutableStateOf(ApiState.Empty) - private set - - fun removeOrRestoreComment( - commentId: Int, - removed: Boolean, - reason: String, - ctx: Context, - focusManager: FocusManager, - onSuccess: (CommentView) -> Unit, - ) { - viewModelScope.launch { - val form = - RemoveComment( - comment_id = commentId, - removed = removed, - reason = reason, - ) - - commentRemoveRes = ApiState.Loading - commentRemoveRes = API.getInstance().removeComment(form).toApiState() - - when (val res = commentRemoveRes) { - is ApiState.Failure -> { - Log.d("removeComment", "failed", res.msg) - apiErrorToast(msg = res.msg, ctx = ctx) - } - - is ApiState.Success -> { - val message = - if (removed) { - ctx.getString(R.string.remove_view_model_comment_removed) - } else { - ctx.getString(R.string.remove_view_model_comment_restored) - } - val commentView = res.data.comment_view - Toast.makeText(ctx, message, Toast.LENGTH_SHORT).show() - - focusManager.clearFocus() - onSuccess(commentView) - } - else -> {} - } - } - } -} diff --git a/app/src/main/java/com/jerboa/ui/components/remove/comment/CommentRemoveActivity.kt b/app/src/main/java/com/jerboa/ui/components/remove/comment/CommentRemoveActivity.kt index 3d4d53a3d..92c94161d 100644 --- a/app/src/main/java/com/jerboa/ui/components/remove/comment/CommentRemoveActivity.kt +++ b/app/src/main/java/com/jerboa/ui/components/remove/comment/CommentRemoveActivity.kt @@ -19,7 +19,7 @@ import com.jerboa.R import com.jerboa.api.ApiState import com.jerboa.db.entity.isAnon import com.jerboa.model.AccountViewModel -import com.jerboa.model.RemoveViewModel +import com.jerboa.model.CommentRemoveViewModel import com.jerboa.ui.components.common.ActionTopBar import com.jerboa.ui.components.common.getCurrentAccount import com.jerboa.ui.components.remove.RemoveItemBody @@ -40,7 +40,7 @@ fun CommentRemoveActivity( val ctx = LocalContext.current val account = getCurrentAccount(accountViewModel = accountViewModel) - val removeViewModel: RemoveViewModel = viewModel() + val commentRemoveViewModel: CommentRemoveViewModel = viewModel() val comment = appState.getPrevReturn(key = CommentRemoveReturn.COMMENT_SEND) var reason by rememberSaveable(stateSaver = TextFieldValue.Saver) { @@ -49,7 +49,7 @@ fun CommentRemoveActivity( ) } val loading = - when (removeViewModel.commentRemoveRes) { + when (commentRemoveViewModel.commentRemoveRes) { ApiState.Loading -> true else -> false } @@ -64,7 +64,7 @@ fun CommentRemoveActivity( loading = loading, onActionClick = { if (!account.isAnon()) { - removeViewModel.removeOrRestoreComment( + commentRemoveViewModel.removeOrRestoreComment( commentId = comment.id, reason = reason.text, removed = !comment.removed, From 155168597b80dfcc0dae9a2fff184e98b2e254ae Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 18 Jan 2024 16:00:33 -0500 Subject: [PATCH 08/12] Changing remove icon to gavel. --- .../jerboa/ui/components/comment/CommentOptionsDropdown.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/jerboa/ui/components/comment/CommentOptionsDropdown.kt b/app/src/main/java/com/jerboa/ui/components/comment/CommentOptionsDropdown.kt index a0eee5ff0..510113a6e 100644 --- a/app/src/main/java/com/jerboa/ui/components/comment/CommentOptionsDropdown.kt +++ b/app/src/main/java/com/jerboa/ui/components/comment/CommentOptionsDropdown.kt @@ -3,7 +3,6 @@ package com.jerboa.ui.components.comment import android.widget.Toast import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Block -import androidx.compose.material.icons.outlined.Close import androidx.compose.material.icons.outlined.Comment import androidx.compose.material.icons.outlined.ContentCopy import androidx.compose.material.icons.outlined.CopyAll @@ -11,6 +10,7 @@ import androidx.compose.material.icons.outlined.Delete import androidx.compose.material.icons.outlined.Description import androidx.compose.material.icons.outlined.Edit import androidx.compose.material.icons.outlined.Flag +import androidx.compose.material.icons.outlined.Gavel import androidx.compose.material.icons.outlined.Link import androidx.compose.material.icons.outlined.Person import androidx.compose.material.icons.outlined.Restore @@ -178,7 +178,7 @@ fun CommentOptionsDropdown( if (commentView.comment.removed) { Pair(stringResource(R.string.restore_comment), Icons.Outlined.Restore) } else { - Pair(stringResource(R.string.remove_comment), Icons.Outlined.Close) + Pair(stringResource(R.string.remove_comment), Icons.Outlined.Gavel) } PopupMenuItem( From 436a240cca0a3ddbf8409434d82a12fc13fa8dae Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 18 Jan 2024 17:08:46 -0500 Subject: [PATCH 09/12] Change a few strings to non-contextual. --- .../java/com/jerboa/model/CommentRemoveViewModel.kt | 4 ++-- .../main/java/com/jerboa/model/PostRemoveViewModel.kt | 4 ++-- .../java/com/jerboa/ui/components/post/PostListing.kt | 2 +- app/src/main/res/values/strings.xml | 10 +++++----- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/jerboa/model/CommentRemoveViewModel.kt b/app/src/main/java/com/jerboa/model/CommentRemoveViewModel.kt index d9fd69cae..cb3a4525a 100644 --- a/app/src/main/java/com/jerboa/model/CommentRemoveViewModel.kt +++ b/app/src/main/java/com/jerboa/model/CommentRemoveViewModel.kt @@ -52,9 +52,9 @@ class CommentRemoveViewModel : ViewModel() { is ApiState.Success -> { val message = if (removed) { - ctx.getString(R.string.remove_view_model_comment_removed) + ctx.getString(R.string.comment_removed) } else { - ctx.getString(R.string.remove_view_model_comment_restored) + ctx.getString(R.string.comment_restored) } val commentView = res.data.comment_view Toast.makeText(ctx, message, Toast.LENGTH_SHORT).show() diff --git a/app/src/main/java/com/jerboa/model/PostRemoveViewModel.kt b/app/src/main/java/com/jerboa/model/PostRemoveViewModel.kt index 57767752b..d14dc3113 100644 --- a/app/src/main/java/com/jerboa/model/PostRemoveViewModel.kt +++ b/app/src/main/java/com/jerboa/model/PostRemoveViewModel.kt @@ -52,9 +52,9 @@ class PostRemoveViewModel : ViewModel() { is ApiState.Success -> { val message = if (removed) { - ctx.getString(R.string.remove_view_model_post_removed) + ctx.getString(R.string.post_removed) } else { - ctx.getString(R.string.remove_view_model_post_restored) + ctx.getString(R.string.post_restored) } val postView = res.data.post_view Toast.makeText(ctx, message, Toast.LENGTH_SHORT).show() diff --git a/app/src/main/java/com/jerboa/ui/components/post/PostListing.kt b/app/src/main/java/com/jerboa/ui/components/post/PostListing.kt index 5d71c6ca9..1abb5aa18 100644 --- a/app/src/main/java/com/jerboa/ui/components/post/PostListing.kt +++ b/app/src/main/java/com/jerboa/ui/components/post/PostListing.kt @@ -215,7 +215,7 @@ fun PostHeaderLine( if (postView.post.removed) { Icon( imageVector = Icons.Outlined.Gavel, - contentDescription = stringResource(R.string.postListing_removed), + contentDescription = stringResource(R.string.removed), tint = MaterialTheme.colorScheme.error, ) } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8c02687fc..72b27637f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -218,7 +218,7 @@ Report Person Upload Image Deleted - Removed + Removed Featured in community Featured locally Go to community @@ -404,10 +404,10 @@ Failed to parse datetime There is no record of this comment The version (%s) is not supported - Comment removed - Comment restored - Post removed - Post restored + Comment removed + Comment restored + Post removed + Post restored Remove Comment Restore Comment Remove Post From 53cdaba52b6a525ff527a29a7afe73f470dd8d30 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 18 Jan 2024 17:09:32 -0500 Subject: [PATCH 10/12] Add remove comment to commentmentionnode. --- .../comment/mentionnode/CommentMentionNode.kt | 21 ++++++++++++++++++ .../CommentMentionOptionsDropdown.kt | 22 +++++++++++++++++++ .../ui/components/inbox/InboxActivity.kt | 3 +++ 3 files changed, 46 insertions(+) diff --git a/app/src/main/java/com/jerboa/ui/components/comment/mentionnode/CommentMentionNode.kt b/app/src/main/java/com/jerboa/ui/components/comment/mentionnode/CommentMentionNode.kt index c707a4a2b..4885b9362 100644 --- a/app/src/main/java/com/jerboa/ui/components/comment/mentionnode/CommentMentionNode.kt +++ b/app/src/main/java/com/jerboa/ui/components/comment/mentionnode/CommentMentionNode.kt @@ -28,6 +28,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import com.jerboa.R import com.jerboa.VoteType +import com.jerboa.canMod import com.jerboa.datatypes.samplePersonMentionView import com.jerboa.db.entity.Account import com.jerboa.ui.components.comment.CommentBody @@ -40,8 +41,11 @@ import com.jerboa.ui.theme.SMALL_PADDING import com.jerboa.ui.theme.XXL_PADDING import com.jerboa.ui.theme.muted import it.vercruysse.lemmyapi.v0x19.datatypes.Community +import it.vercruysse.lemmyapi.v0x19.datatypes.CommunityModeratorView import it.vercruysse.lemmyapi.v0x19.datatypes.Person import it.vercruysse.lemmyapi.v0x19.datatypes.PersonMentionView +import it.vercruysse.lemmyapi.v0x19.datatypes.PersonView +import kotlinx.collections.immutable.ImmutableList @Composable fun CommentMentionNodeHeader( @@ -91,6 +95,8 @@ fun CommentMentionNodeHeaderPreview() { @Composable fun CommentMentionNodeFooterLine( personMentionView: PersonMentionView, + admins: ImmutableList, + moderators: ImmutableList?, onUpvoteClick: () -> Unit, onDownvoteClick: () -> Unit, onReplyClick: (personMentionView: PersonMentionView) -> Unit, @@ -112,6 +118,16 @@ fun CommentMentionNodeFooterLine( ) { var showMoreOptions by remember { mutableStateOf(false) } + val canMod = + remember { + canMod( + creatorId = personMentionView.comment.creator_id, + admins = admins, + moderators = moderators, + myId = account.id, + ) + } + if (showMoreOptions) { CommentMentionsOptionsDropdown( personMentionView = personMentionView, @@ -123,6 +139,7 @@ fun CommentMentionNodeFooterLine( onBlockCreatorClick = onBlockCreatorClick, isCreator = account.id == personMentionView.creator.id, onCommentLinkClick = onLinkClick, + canMod = canMod, viewSource = viewSource, ) } @@ -228,6 +245,8 @@ fun CommentMentionNodeFooterLine( @Composable fun CommentMentionNode( personMentionView: PersonMentionView, + admins: ImmutableList, + moderators: ImmutableList?, onUpvoteClick: (personMentionView: PersonMentionView) -> Unit, onDownvoteClick: (personMentionView: PersonMentionView) -> Unit, onReplyClick: (personMentionView: PersonMentionView) -> Unit, @@ -303,6 +322,8 @@ fun CommentMentionNode( ) { CommentMentionNodeFooterLine( personMentionView = personMentionView, + admins = admins, + moderators = moderators, onUpvoteClick = { onUpvoteClick(personMentionView) }, diff --git a/app/src/main/java/com/jerboa/ui/components/comment/mentionnode/CommentMentionOptionsDropdown.kt b/app/src/main/java/com/jerboa/ui/components/comment/mentionnode/CommentMentionOptionsDropdown.kt index 78df6a155..cc712b92b 100644 --- a/app/src/main/java/com/jerboa/ui/components/comment/mentionnode/CommentMentionOptionsDropdown.kt +++ b/app/src/main/java/com/jerboa/ui/components/comment/mentionnode/CommentMentionOptionsDropdown.kt @@ -8,8 +8,10 @@ import androidx.compose.material.icons.outlined.ContentCopy import androidx.compose.material.icons.outlined.CopyAll import androidx.compose.material.icons.outlined.Description import androidx.compose.material.icons.outlined.Flag +import androidx.compose.material.icons.outlined.Gavel import androidx.compose.material.icons.outlined.Link import androidx.compose.material.icons.outlined.Person +import androidx.compose.material.icons.outlined.Restore import androidx.compose.material3.Divider import androidx.compose.runtime.Composable import androidx.compose.ui.platform.LocalClipboardManager @@ -35,6 +37,7 @@ fun CommentMentionsOptionsDropdown( onReportClick: (PersonMentionView) -> Unit, onRemoveClick: (PersonMentionView) -> Unit, isCreator: Boolean, + canMod: Boolean, viewSource: Boolean, ) { val localClipboardManager = LocalClipboardManager.current @@ -128,5 +131,24 @@ fun CommentMentionsOptionsDropdown( }, ) } + + if (canMod) { + Divider() + val (removeText, removeIcon) = + if (personMentionView.comment.removed) { + Pair(stringResource(R.string.restore_comment), Icons.Outlined.Restore) + } else { + Pair(stringResource(R.string.remove_comment), Icons.Outlined.Gavel) + } + + PopupMenuItem( + text = removeText, + icon = removeIcon, + onClick = { + onDismissRequest() + onRemoveClick(personMentionView) + }, + ) + } } } diff --git a/app/src/main/java/com/jerboa/ui/components/inbox/InboxActivity.kt b/app/src/main/java/com/jerboa/ui/components/inbox/InboxActivity.kt index 4de961b41..0c523e108 100644 --- a/app/src/main/java/com/jerboa/ui/components/inbox/InboxActivity.kt +++ b/app/src/main/java/com/jerboa/ui/components/inbox/InboxActivity.kt @@ -533,6 +533,9 @@ fun InboxTabs( ) { pmv -> CommentMentionNode( personMentionView = pmv, + admins = siteViewModel.admins(), + // No community moderators available here + moderators = null, onUpvoteClick = { pm -> account.doIfReadyElseDisplayInfo( appState, From 151868d16baf7d9910a46ea92d36d8fdfaf56b65 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 18 Jan 2024 17:10:37 -0500 Subject: [PATCH 11/12] Remove non-optional body from compiler warning. --- app/src/main/java/com/jerboa/Utils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/jerboa/Utils.kt b/app/src/main/java/com/jerboa/Utils.kt index 4478d4339..6eda4f16a 100644 --- a/app/src/main/java/com/jerboa/Utils.kt +++ b/app/src/main/java/com/jerboa/Utils.kt @@ -1455,7 +1455,7 @@ fun Context.getInputStream(url: String): InputStream { Request.Builder() .url(url) .build(), - ).execute().body?.byteStream() ?: throw IOException("Failed to get input stream") + ).execute().body.byteStream() } } From a8da6424bf22029e258d659a779d4ef890647062 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Sat, 20 Jan 2024 23:26:25 -0500 Subject: [PATCH 12/12] Wrapping remember around moderators. --- .../components/community/CommunityActivity.kt | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/jerboa/ui/components/community/CommunityActivity.kt b/app/src/main/java/com/jerboa/ui/components/community/CommunityActivity.kt index 6b5ae49b0..32b0423b7 100644 --- a/app/src/main/java/com/jerboa/ui/components/community/CommunityActivity.kt +++ b/app/src/main/java/com/jerboa/ui/components/community/CommunityActivity.kt @@ -108,14 +108,6 @@ fun CommunityActivity( }, ) - val moderators = - when (val communityRes = communityViewModel.communityRes) { - is ApiState.Success -> communityRes.data.moderators.toImmutableList() - else -> { - null - } - } - Scaffold( modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), snackbarHost = { JerboaSnackbarHost(snackbarHostState) }, @@ -200,12 +192,23 @@ fun CommunityActivity( ApiState.Empty -> ApiEmptyText() is ApiState.Failure -> ApiErrorText(postsRes.msg) is ApiState.Holder -> { + val communityRes = communityViewModel.communityRes + val moderators = + remember(communityRes) { + when (communityRes) { + is ApiState.Success -> communityRes.data.moderators.toImmutableList() + else -> { + null + } + } + } + PostListings( posts = postsRes.data.posts.toImmutableList(), admins = siteViewModel.admins(), moderators = moderators, contentAboveListings = { - when (val communityRes = communityViewModel.communityRes) { + when (communityRes) { is ApiState.Success -> { CommunityTopSection( communityView = communityRes.data.community_view,