15
15
*/
16
16
package io.getstream.feeds.android.sample.feed
17
17
18
- import android.net.Uri
19
18
import androidx.compose.animation.AnimatedVisibility
20
19
import androidx.compose.foundation.background
20
+ import androidx.compose.foundation.combinedClickable
21
21
import androidx.compose.foundation.layout.Arrangement
22
22
import androidx.compose.foundation.layout.Box
23
23
import androidx.compose.foundation.layout.Column
@@ -49,6 +49,8 @@ import androidx.compose.runtime.remember
49
49
import androidx.compose.runtime.setValue
50
50
import androidx.compose.ui.Alignment
51
51
import androidx.compose.ui.Modifier
52
+ import androidx.compose.ui.hapticfeedback.HapticFeedbackType
53
+ import androidx.compose.ui.platform.LocalHapticFeedback
52
54
import androidx.compose.ui.res.painterResource
53
55
import androidx.compose.ui.text.font.FontWeight
54
56
import androidx.compose.ui.unit.dp
@@ -63,7 +65,9 @@ import io.getstream.feeds.android.client.api.model.FeedId
63
65
import io.getstream.feeds.android.client.api.model.ThreadedCommentData
64
66
import io.getstream.feeds.android.sample.R
65
67
import io.getstream.feeds.android.sample.components.LoadingScreen
68
+ import io.getstream.feeds.android.sample.feed.CommentsSheetViewModel.Event
66
69
import io.getstream.feeds.android.sample.ui.util.ScrolledToBottomEffect
70
+ import io.getstream.feeds.android.sample.ui.util.conditional
67
71
import io.getstream.feeds.android.sample.ui.util.rippleClickable
68
72
import io.getstream.feeds.android.sample.util.AsyncResource
69
73
@@ -90,13 +94,13 @@ fun ColumnScope.CommentsBottomSheet(navigator: DestinationsNavigator) {
90
94
}
91
95
92
96
is AsyncResource .Content -> {
93
- val comments by state.data.comments.collectAsStateWithLifecycle()
97
+ val comments by state.data.second.comments.collectAsStateWithLifecycle()
98
+ val currentUserId = state.data.first.id
94
99
95
100
CommentsBottomSheetContent (
96
101
comments = comments,
97
- onLoadMore = viewModel::onLoadMore,
98
- onLikeClick = viewModel::onLikeClick,
99
- onPostComment = viewModel::onPostComment,
102
+ currentUserId = currentUserId,
103
+ onEvent = viewModel::onEvent,
100
104
)
101
105
}
102
106
}
@@ -105,9 +109,8 @@ fun ColumnScope.CommentsBottomSheet(navigator: DestinationsNavigator) {
105
109
@Composable
106
110
private fun ColumnScope.CommentsBottomSheetContent (
107
111
comments : List <ThreadedCommentData >,
108
- onLoadMore : () -> Unit ,
109
- onLikeClick : (ThreadedCommentData ) -> Unit ,
110
- onPostComment : (text: String , parentCommentId: String? , attachmentUris: List <Uri >) -> Unit ,
112
+ currentUserId : String ,
113
+ onEvent : (Event ) -> Unit ,
111
114
) {
112
115
var createCommentData: CreateCommentData ? by remember { mutableStateOf(null ) }
113
116
var expandedCommentId: String? by remember { mutableStateOf(null ) }
@@ -122,20 +125,21 @@ private fun ColumnScope.CommentsBottomSheetContent(
122
125
Box (Modifier .fillMaxWidth().defaultMinSize(minHeight = 300 .dp)) {
123
126
val lazyListState = rememberLazyListState()
124
127
125
- ScrolledToBottomEffect (lazyListState, action = onLoadMore )
128
+ ScrolledToBottomEffect (lazyListState, action = { onEvent( Event . OnScrollToBottom ) } )
126
129
127
130
LazyColumn (state = lazyListState) {
128
131
items(comments) { comment ->
129
132
Comment (
130
133
data = comment,
134
+ currentUserId = currentUserId,
131
135
isExpanded = comment.id == expandedCommentId,
132
136
onExpandClick = {
133
137
expandedCommentId = comment.id.takeUnless { it == expandedCommentId }
134
138
},
135
139
onReplyClick = { commentId ->
136
140
createCommentData = CreateCommentData (commentId)
137
141
},
138
- onLikeClick = onLikeClick ,
142
+ onEvent = onEvent ,
139
143
modifier = Modifier .fillMaxWidth().padding(horizontal = 16 .dp, vertical = 8 .dp),
140
144
)
141
145
}
@@ -163,7 +167,7 @@ private fun ColumnScope.CommentsBottomSheetContent(
163
167
onDismiss = { createCommentData = null },
164
168
requireText = true ,
165
169
onPost = { text, attachments ->
166
- onPostComment( text, createCommentData?.replyParentId, attachments)
170
+ onEvent( Event . OnPost ( text, createCommentData?.replyParentId, attachments) )
167
171
createCommentData = null
168
172
},
169
173
)
@@ -173,20 +177,36 @@ private fun ColumnScope.CommentsBottomSheetContent(
173
177
@Composable
174
178
private fun Comment (
175
179
data : ThreadedCommentData ,
180
+ currentUserId : String ,
176
181
isExpanded : Boolean ,
177
182
onExpandClick : () -> Unit ,
178
183
onReplyClick : (commentId: String ) -> Unit ,
179
- onLikeClick : (ThreadedCommentData ) -> Unit ,
184
+ onEvent : (Event ) -> Unit ,
180
185
modifier : Modifier = Modifier ,
181
186
) {
182
187
var expandedCommentId: String? by remember { mutableStateOf(null ) }
188
+ var showContextMenu by remember { mutableStateOf(false ) }
189
+ var showEditDialog by remember { mutableStateOf(false ) }
190
+
191
+ val hapticFeedback = LocalHapticFeedback .current
183
192
184
193
Column (modifier.fillMaxWidth()) {
185
194
Column (
186
195
Modifier .background(
187
196
MaterialTheme .colorScheme.secondaryContainer,
188
197
shape = RoundedCornerShape (16 .dp),
189
198
)
199
+ .conditional(data.user.id == currentUserId) {
200
+ combinedClickable(
201
+ indication = null ,
202
+ interactionSource = null ,
203
+ onClick = {},
204
+ onLongClick = {
205
+ hapticFeedback.performHapticFeedback(HapticFeedbackType .LongPress )
206
+ showContextMenu = true
207
+ },
208
+ )
209
+ }
190
210
.padding(16 .dp)
191
211
.fillMaxWidth(),
192
212
verticalArrangement = Arrangement .spacedBy(4 .dp),
@@ -205,7 +225,7 @@ private fun Comment(
205
225
Text (
206
226
text = if (hasOwnHeart) " Unlike" else " Like" ,
207
227
modifier =
208
- Modifier .rippleClickable { onLikeClick( data) }
228
+ Modifier .rippleClickable { onEvent( Event . OnLike ( data) ) }
209
229
.padding(horizontal = 8 .dp, vertical = 4 .dp),
210
230
)
211
231
Text (
@@ -243,17 +263,47 @@ private fun Comment(
243
263
data.replies?.forEach { reply ->
244
264
Comment (
245
265
data = reply,
266
+ currentUserId = currentUserId,
246
267
isExpanded = reply.id == expandedCommentId,
247
268
onExpandClick = {
248
269
expandedCommentId = reply.id.takeUnless { it == expandedCommentId }
249
270
},
250
271
onReplyClick = onReplyClick,
251
- onLikeClick = onLikeClick ,
272
+ onEvent = onEvent ,
252
273
modifier = Modifier .fillMaxWidth().padding(start = 16 .dp, top = 16 .dp),
253
274
)
254
275
}
255
276
}
256
277
}
278
+
279
+ // Context menu dialog for long press
280
+ if (showContextMenu) {
281
+ ContentContextMenuDialog (
282
+ title = " Comment Options" ,
283
+ showEdit = true ,
284
+ onDismiss = { showContextMenu = false },
285
+ onEdit = {
286
+ showEditDialog = true
287
+ showContextMenu = false
288
+ },
289
+ onDelete = {
290
+ onEvent(Event .OnDelete (data.id))
291
+ showContextMenu = false
292
+ },
293
+ )
294
+ }
295
+
296
+ // Edit comment dialog
297
+ if (showEditDialog) {
298
+ EditContentDialog (
299
+ data.text.orEmpty(),
300
+ onDismiss = { showEditDialog = false },
301
+ onSave = { newText ->
302
+ onEvent(Event .OnEdit (commentId = data.id, text = newText))
303
+ showEditDialog = false
304
+ },
305
+ )
306
+ }
257
307
}
258
308
}
259
309
0 commit comments