Skip to content

Migrate Jetchat to new TextField #1543

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Jetchat/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ dependencies {
implementation(libs.androidx.compose.ui.viewbinding)
implementation(libs.androidx.compose.ui.googlefonts)

implementation(libs.coil.kt.compose)
implementation(libs.coil.kt.gif)

debugImplementation(libs.androidx.compose.ui.test.manifest)

androidTestImplementation(libs.junit)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@

package com.example.compose.jetchat.conversation

import android.content.ClipDescription
import android.net.Uri
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.draganddrop.dragAndDropTarget
import androidx.compose.foundation.content.ReceiveContentListener
import androidx.compose.foundation.content.TransferableContent
import androidx.compose.foundation.content.consume
import androidx.compose.foundation.content.contentReceiver
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
Expand All @@ -48,6 +51,7 @@ import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.outlined.Search
Expand All @@ -72,15 +76,12 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draganddrop.DragAndDropEvent
import androidx.compose.ui.draganddrop.DragAndDropTarget
import androidx.compose.ui.draganddrop.mimeTypes
import androidx.compose.ui.draganddrop.toAndroidDragEvent
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.LastBaseline
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.platform.testTag
Expand All @@ -89,6 +90,9 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import com.example.compose.jetchat.FunctionalityNotAvailablePopup
import com.example.compose.jetchat.R
import com.example.compose.jetchat.components.JetchatAppBar
Expand Down Expand Up @@ -128,41 +132,40 @@ fun ConversationContent(
mutableStateOf(Color.Transparent)
}

val dragAndDropCallback = remember {
object : DragAndDropTarget {
override fun onDrop(event: DragAndDropEvent): Boolean {
val clipData = event.toAndroidDragEvent().clipData
val textFieldState = rememberTextFieldState()
var contentReceiverImages by remember { mutableStateOf<List<Uri>>(emptyList()) }

if (clipData.itemCount < 1) {
return false
}

uiState.addMessage(
Message(authorMe, clipData.getItemAt(0).text.toString(), timeNow)
)

return true
}

override fun onStarted(event: DragAndDropEvent) {
super.onStarted(event)
borderStroke = Color.Red
val receiveContentListener = remember {
object : ReceiveContentListener {
override fun onDragEnd() {
background = Color.Transparent
borderStroke = Color.Transparent
}

override fun onEntered(event: DragAndDropEvent) {
super.onEntered(event)
override fun onDragEnter() {
background = Color.Red.copy(alpha = .3f)
}

override fun onExited(event: DragAndDropEvent) {
super.onExited(event)
override fun onDragExit() {
background = Color.Transparent
}

override fun onEnded(event: DragAndDropEvent) {
super.onEnded(event)
background = Color.Transparent
borderStroke = Color.Transparent
override fun onDragStart() {
borderStroke = Color.Red
}

override fun onReceive(transferableContent: TransferableContent): TransferableContent? {
return transferableContent.consume { clipDataItem ->
if (!clipDataItem.text.isNullOrBlank()) {
textFieldState.addText(clipDataItem.text?.toString() ?: "")
}
if (clipDataItem.uri != null) {
contentReceiverImages += clipDataItem.uri
true
} else {
false
}
}
}
}
}
Expand All @@ -187,13 +190,7 @@ fun ConversationContent(
Modifier.fillMaxSize().padding(paddingValues)
.background(color = background)
.border(width = 2.dp, color = borderStroke)
.dragAndDropTarget(shouldStartDragAndDrop = { event ->
event
.mimeTypes()
.contains(
ClipDescription.MIMETYPE_TEXT_PLAIN
)
}, target = dragAndDropCallback)
.contentReceiver(receiveContentListener)
) {
Messages(
messages = uiState.messages,
Expand All @@ -202,16 +199,36 @@ fun ConversationContent(
scrollState = scrollState
)
UserInput(
textFieldState = textFieldState,
onMessageSent = { content ->
// first send every image as a separate message
contentReceiverImages.fastForEach {
uiState.addMessage(
Message(
author = authorMe,
content = "",
timestamp = timeNow,
image = it
)
)
}
// finally send the text content
uiState.addMessage(
Message(authorMe, content, timeNow)
)
contentReceiverImages = emptyList()
},
resetScroll = {
scope.launch {
scrollState.scrollToItem(0)
}
},
images = contentReceiverImages,
onClearImage = { removeIndex ->
contentReceiverImages = contentReceiverImages.filterIndexed { index, _ ->
index != removeIndex
}
},
// let this element handle the padding so that the elevation is shown behind the
// navigation bar
modifier = Modifier.navigationBarsPadding().imePadding()
Expand Down Expand Up @@ -491,15 +508,17 @@ fun ChatItemBubble(
}

Column {
Surface(
color = backgroundBubbleColor,
shape = ChatBubbleShape
) {
ClickableMessage(
message = message,
isUserMe = isUserMe,
authorClicked = authorClicked
)
if (message.content.isNotBlank()) {
Surface(
color = backgroundBubbleColor,
shape = ChatBubbleShape
) {
ClickableMessage(
message = message,
isUserMe = isUserMe,
authorClicked = authorClicked
)
}
}

message.image?.let {
Expand All @@ -508,11 +527,13 @@ fun ChatItemBubble(
color = backgroundBubbleColor,
shape = ChatBubbleShape
) {
Image(
painter = painterResource(it),
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(it)
.build(),
contentDescription = stringResource(id = R.string.attached_image),
contentScale = ContentScale.Fit,
modifier = Modifier.size(160.dp),
contentDescription = stringResource(id = R.string.attached_image)
modifier = Modifier.size(160.dp)
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,6 @@ data class Message(
val author: String,
val content: String,
val timestamp: String,
val image: Int? = null,
val authorImage: Int = if (author == "me") R.drawable.ali else R.drawable.someone_else,
val image: Any? = null,
val authorImage: Int = if (author == "me") R.drawable.ali else R.drawable.someone_else
)
Loading