Skip to content

Commit

Permalink
[CHA-848] feat: edit and delete example
Browse files Browse the repository at this point in the history
  • Loading branch information
ttypic committed Feb 26, 2025
1 parent bdf4f7c commit e502e33
Showing 1 changed file with 137 additions and 18 deletions.
155 changes: 137 additions & 18 deletions example/src/main/java/com/ably/chat/example/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.Person
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
Expand All @@ -43,6 +47,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.ably.chat.ChatClient
import com.ably.chat.Message
import com.ably.chat.MessageEventType
import com.ably.chat.MessageMetadata
import com.ably.chat.Room
import com.ably.chat.RoomOptions
Expand Down Expand Up @@ -155,13 +160,54 @@ fun Chat(room: Room, modifier: Modifier = Modifier) {
val listState = rememberLazyListState()
val coroutineScope = rememberCoroutineScope()
var receivedReactions by remember { mutableStateOf<List<String>>(listOf()) }
var edited: Message? by remember { mutableStateOf(null) }
val updating = edited != null

val handleSend = {
coroutineScope.launch {
room.messages.send(
text = messageText.text,
)
messageText = TextFieldValue("")
sending = false
}
}

val handleEdit = handleEdit@{
val editedMessage = edited ?: return@handleEdit
coroutineScope.launch {
room.messages.update(
editedMessage.copy(text = messageText.text),
)
messageText = TextFieldValue("")
edited = null
sending = false
}
}

DisposableEffect(Unit) {
val subscription = room.messages.subscribe {
messages += it.message
coroutineScope.launch {
listState.animateScrollToItem(messages.size - 1)
val subscription = room.messages.subscribe { event ->
when (event.type) {
MessageEventType.Created -> {
messages += event.message
coroutineScope.launch {
listState.animateScrollToItem(messages.size - 1)
}
}

MessageEventType.Updated -> {
messages = messages.map {
if (it.serial != event.message.serial) it else event.message
}
}

MessageEventType.Deleted -> {
messages = messages.filter {
it.serial != event.message.serial
}
}
}

}

coroutineScope.launch {
Expand Down Expand Up @@ -196,11 +242,23 @@ fun Chat(room: Room, modifier: Modifier = Modifier) {
state = listState,
) {
items(messages.size) { index ->
MessageBubble(messages[index])
MessageBubble(
message = messages[index],
onEdit = {
edited = messages[index]
messageText = TextFieldValue(messages[index].text)
},
onDelete = {
coroutineScope.launch {
room.messages.delete(messages[index])
}
},
)
}
}

ChatInputField(
updating = updating,
sending = sending,
messageInput = messageText,
onMessageChange = {
Expand All @@ -211,12 +269,9 @@ fun Chat(room: Room, modifier: Modifier = Modifier) {
},
onSendClick = {
sending = true
coroutineScope.launch {
room.messages.send(
text = messageText.text,
)
messageText = TextFieldValue("")
sending = false
when {
updating -> handleEdit()
else -> handleSend()
}
},
onReactionClick = {
Expand All @@ -232,7 +287,10 @@ fun Chat(room: Room, modifier: Modifier = Modifier) {
}

@Composable
fun MessageBubble(message: Message) {
fun MessageBubble(message: Message, onEdit: () -> Unit = {}, onDelete: () -> Unit = {}) {
var expanded by remember { mutableStateOf(false) }
var confirmationDialogShown by remember { mutableStateOf(false) }

Row(
modifier = Modifier
.fillMaxWidth()
Expand All @@ -252,12 +310,63 @@ fun MessageBubble(message: Message) {
color = Color.White,
)
}
if (message.clientId == randomClientId) {
Box {
IconButton(onClick = { expanded = true }) {
Icon(Icons.Default.MoreVert, contentDescription = "More Options")
}

DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
) {
DropdownMenuItem(
text = { Text("Edit") },
onClick = {
expanded = false
onEdit()
},
)
DropdownMenuItem(
text = { Text("Delete") },
onClick = {
expanded = false
confirmationDialogShown = true
},
)
}
}
}
// Delete Confirmation Dialog
if (confirmationDialogShown) {
AlertDialog(
onDismissRequest = { confirmationDialogShown = false },
title = { Text("Delete Message") },
text = { Text("Are you sure you want to delete this message?") },
confirmButton = {
Button(
onClick = {
onDelete()
confirmationDialogShown = false
}
) {
Text("Delete")
}
},
dismissButton = {
Button(onClick = { confirmationDialogShown = false }) {
Text("Cancel")
}
}
)
}
}
}

@Composable
fun ChatInputField(
sending: Boolean = false,
updating: Boolean = false,
messageInput: TextFieldValue,
onMessageChange: (TextFieldValue) -> Unit,
onSendClick: () -> Unit,
Expand All @@ -279,13 +388,23 @@ fun ChatInputField(
.background(Color.White),
placeholder = { Text("Type a message...") },
)
if (messageInput.text.isNotEmpty()) {
Button(enabled = !sending, onClick = onSendClick) {
Text("Send")
when {
updating -> {
Button(enabled = !sending, onClick = onSendClick) {
Text("Update")
}
}
} else {
Button(onClick = onReactionClick) {
Text("\uD83D\uDC4D")

messageInput.text.isEmpty() -> {
Button(onClick = onReactionClick) {
Text("\uD83D\uDC4D")
}
}

else -> {
Button(enabled = !sending, onClick = onSendClick) {
Text("Send")
}
}
}
}
Expand Down

0 comments on commit e502e33

Please sign in to comment.