Chat UI improvements
This commit is contained in:
@ -6,7 +6,6 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.SystemClock
|
||||
import android.text.format.DateUtils.isToday
|
||||
import android.view.Menu
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Toast
|
||||
import androidx.activity.ComponentActivity
|
||||
@ -15,7 +14,6 @@ import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@ -125,7 +123,7 @@ class ChatActivity : ComponentActivity() {
|
||||
|
||||
val userAgent = UserAgent.ofAor(aor)
|
||||
if (userAgent == null) {
|
||||
Log.w(TAG, "MessageActivity did not find ua of $aor")
|
||||
Log.w(TAG, "ChatActivity did not find ua of $aor")
|
||||
MainActivity.activityAor = aor
|
||||
returnResult(RESULT_CANCELED)
|
||||
return
|
||||
@ -135,7 +133,7 @@ class ChatActivity : ComponentActivity() {
|
||||
|
||||
chatPeer = Utils.friendlyUri(this, peerUri, userAgent.account, true)
|
||||
|
||||
imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
|
||||
val title = String.format(getString(R.string.chat_with), chatPeer)
|
||||
|
||||
@ -169,7 +167,6 @@ class ChatActivity : ComponentActivity() {
|
||||
.fillMaxHeight()
|
||||
.imePadding()
|
||||
.safeDrawingPadding(),
|
||||
containerColor = LocalCustomColors.current.background,
|
||||
topBar = { TopAppBar(ctx, title, navigateBack) },
|
||||
bottomBar = { NewMessage(ctx, peerUri) },
|
||||
content = { contentPadding ->
|
||||
@ -232,8 +229,6 @@ class ChatActivity : ComponentActivity() {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight()
|
||||
.background(LocalCustomColors.current.background)
|
||||
.padding(contentPadding),
|
||||
verticalArrangement = Arrangement.Bottom
|
||||
) {
|
||||
@ -287,8 +282,7 @@ class ChatActivity : ComponentActivity() {
|
||||
state = lazyListState,
|
||||
width = 4.dp,
|
||||
color = LocalCustomColors.current.gray
|
||||
)
|
||||
.background(LocalCustomColors.current.background),
|
||||
),
|
||||
reverseLayout = true,
|
||||
state = lazyListState,
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
@ -390,31 +384,48 @@ class ChatActivity : ComponentActivity() {
|
||||
else
|
||||
RoundedCornerShape(20.dp, 10.dp, 50.dp, 20.dp),
|
||||
colors = ButtonDefaults.buttonColors(containerColor =
|
||||
if (message.direction == MESSAGE_DOWN)
|
||||
LocalCustomColors.current.secondaryLight
|
||||
else
|
||||
LocalCustomColors.current.primaryLight),
|
||||
if (message.direction == MESSAGE_DOWN) {
|
||||
if (BaresipService.darkTheme.value)
|
||||
LocalCustomColors.current.secondaryDark
|
||||
else
|
||||
LocalCustomColors.current.secondaryLight
|
||||
}
|
||||
else {
|
||||
if (BaresipService.darkTheme.value)
|
||||
LocalCustomColors.current.primaryDark
|
||||
else
|
||||
LocalCustomColors.current.primaryLight
|
||||
}),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(start = if (message.direction == MESSAGE_DOWN) 0.dp else 24.dp,
|
||||
end = if (message.direction == MESSAGE_DOWN) 24.dp else 0.dp)
|
||||
) {
|
||||
Column {
|
||||
Row {
|
||||
Text(
|
||||
peer, color = LocalCustomColors.current.dark,
|
||||
fontSize = 12.sp
|
||||
)
|
||||
val textColor =
|
||||
if (message.direction == MESSAGE_DOWN) {
|
||||
if (BaresipService.darkTheme.value)
|
||||
LocalCustomColors.current.secondaryLight
|
||||
else
|
||||
LocalCustomColors.current.secondaryDark
|
||||
}
|
||||
else {
|
||||
if (BaresipService.darkTheme.value)
|
||||
LocalCustomColors.current.primaryLight
|
||||
else
|
||||
LocalCustomColors.current.primaryDark
|
||||
}
|
||||
Text(text = peer, fontSize = 12.sp, color = textColor)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Text(
|
||||
info, color = LocalCustomColors.current.dark,
|
||||
fontSize = 12.sp
|
||||
)
|
||||
Text(text = info, fontSize = 12.sp, color = textColor)
|
||||
}
|
||||
Row {
|
||||
SelectionContainer {
|
||||
Text(
|
||||
text = message.message,
|
||||
color = LocalCustomColors.current.dark,
|
||||
color = LocalCustomColors.current.itemText,
|
||||
fontWeight = if (message.direction == MESSAGE_DOWN && message.new)
|
||||
FontWeight.Bold else FontWeight.Normal
|
||||
)
|
||||
@ -505,7 +516,7 @@ class ChatActivity : ComponentActivity() {
|
||||
},
|
||||
onLongClick = {
|
||||
val clipboardManager =
|
||||
ctx.getSystemService(Context.CLIPBOARD_SERVICE) as
|
||||
ctx.getSystemService(CLIPBOARD_SERVICE) as
|
||||
android.content.ClipboardManager
|
||||
val clipData = clipboardManager.primaryClip
|
||||
if (clipData != null && clipData.itemCount > 0) {
|
||||
@ -597,11 +608,6 @@ class ChatActivity : ComponentActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.call_icon, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
val chatText = BaresipService.chatTexts["$aor::$peerUri"]
|
||||
|
||||
@ -17,7 +17,6 @@ import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@ -41,14 +40,13 @@ import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicText
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Menu
|
||||
import androidx.compose.material.icons.outlined.Clear
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
@ -75,6 +73,7 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import coil.compose.AsyncImage
|
||||
@ -233,13 +232,11 @@ class ChatsActivity: ComponentActivity() {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight()
|
||||
.background(LocalCustomColors.current.background)
|
||||
.padding(contentPadding),
|
||||
verticalArrangement = Arrangement.Bottom
|
||||
verticalArrangement = Arrangement.Top
|
||||
) {
|
||||
Account(account)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
// Spacer(modifier = Modifier.weight(1f))
|
||||
Chats(ctx, account)
|
||||
}
|
||||
}
|
||||
@ -269,7 +266,7 @@ class ChatsActivity: ComponentActivity() {
|
||||
modifier = Modifier
|
||||
.imePadding()
|
||||
.fillMaxWidth()
|
||||
.padding(start = 16.dp, end = 4.dp)
|
||||
.padding(start = 8.dp, end = 4.dp)
|
||||
.verticalScrollbar(
|
||||
state = lazyListState,
|
||||
width = 4.dp,
|
||||
@ -281,9 +278,37 @@ class ChatsActivity: ComponentActivity() {
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
) {
|
||||
items(items = uaMessages, key = { message -> message.timeStamp }) { message ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.combinedClickable(
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
when (val contact = Contact.findContact(message.peerUri)) {
|
||||
is Contact.BaresipContact -> {
|
||||
val avatarImage = contact.avatarImage
|
||||
if (avatarImage != null)
|
||||
ImageAvatar(avatarImage)
|
||||
else
|
||||
TextAvatar(contact.name, contact.color)
|
||||
}
|
||||
is Contact.AndroidContact -> {
|
||||
val thumbNailUri = contact.thumbnailUri
|
||||
if (thumbNailUri != null)
|
||||
AsyncImage(
|
||||
model = thumbNailUri,
|
||||
contentDescription = "Avatar",
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier
|
||||
.size(36.dp)
|
||||
.clip(CircleShape),
|
||||
)
|
||||
else
|
||||
TextAvatar(contact.name, contact.color)
|
||||
}
|
||||
null -> {
|
||||
val avatarImage = BitmapFactory
|
||||
.decodeResource(ctx.resources, R.drawable.person_image)
|
||||
ImageAvatar(avatarImage)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.width(6.dp))
|
||||
CustomElements.Button(
|
||||
onClick = {
|
||||
val i = Intent(ctx, ChatActivity::class.java)
|
||||
val b = Bundle()
|
||||
@ -305,16 +330,13 @@ class ChatsActivity: ComponentActivity() {
|
||||
i.putExtras(b)
|
||||
startActivity(i)
|
||||
}
|
||||
|
||||
DialogInterface.BUTTON_NEGATIVE -> {
|
||||
Message.deleteAorPeerMessages(aor, message.peerUri)
|
||||
}
|
||||
|
||||
DialogInterface.BUTTON_NEUTRAL -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val builder = MaterialAlertDialogBuilder(
|
||||
this@ChatsActivity,
|
||||
R.style.AlertDialogTheme
|
||||
@ -362,62 +384,28 @@ class ChatsActivity: ComponentActivity() {
|
||||
)
|
||||
show()
|
||||
}
|
||||
}
|
||||
)) {
|
||||
when (val contact = Contact.findContact(message.peerUri)) {
|
||||
is Contact.BaresipContact -> {
|
||||
val avatarImage = contact.avatarImage
|
||||
if (avatarImage != null)
|
||||
ImageAvatar(avatarImage)
|
||||
else
|
||||
TextAvatar(contact.name, contact.color)
|
||||
}
|
||||
|
||||
is Contact.AndroidContact -> {
|
||||
val thumbNailUri = contact.thumbnailUri
|
||||
if (thumbNailUri != null)
|
||||
AsyncImage(
|
||||
model = thumbNailUri,
|
||||
contentDescription = "Avatar",
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier
|
||||
.size(36.dp)
|
||||
.clip(CircleShape),
|
||||
)
|
||||
else
|
||||
TextAvatar(contact.name, contact.color)
|
||||
}
|
||||
|
||||
null -> {
|
||||
val avatarImage = BitmapFactory
|
||||
.decodeResource(ctx.resources, R.drawable.person_image)
|
||||
ImageAvatar(avatarImage)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(6.dp))
|
||||
|
||||
Button(
|
||||
onClick = {
|
||||
val i = Intent(this@ChatsActivity, ChatActivity::class.java)
|
||||
val b = Bundle()
|
||||
b.putString("aor", aor)
|
||||
b.putString("peer", message.peerUri)
|
||||
i.putExtras(b)
|
||||
chatRequest.launch(i) },
|
||||
shape = if (message.direction == MESSAGE_DOWN)
|
||||
RoundedCornerShape(50.dp, 20.dp, 20.dp, 10.dp)
|
||||
else
|
||||
RoundedCornerShape(20.dp, 50.dp, 20.dp, 10.dp),
|
||||
colors = ButtonDefaults.buttonColors(containerColor =
|
||||
if (message.direction == MESSAGE_DOWN)
|
||||
LocalCustomColors.current.secondaryLight
|
||||
else
|
||||
LocalCustomColors.current.primaryLight),
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(start = 8.dp, end = 16.dp)
|
||||
.padding(end = 6.dp),
|
||||
shape = if (message.direction == MESSAGE_DOWN)
|
||||
RoundedCornerShape(50.dp, 20.dp, 20.dp, 10.dp)
|
||||
else
|
||||
RoundedCornerShape(20.dp, 10.dp, 50.dp, 20.dp),
|
||||
color = //ButtonDefaults.buttonColors(containerColor =
|
||||
if (message.direction == MESSAGE_DOWN) {
|
||||
if (BaresipService.darkTheme.value)
|
||||
LocalCustomColors.current.secondaryDark
|
||||
else
|
||||
LocalCustomColors.current.secondaryLight
|
||||
}
|
||||
else {
|
||||
if (BaresipService.darkTheme.value)
|
||||
LocalCustomColors.current.primaryDark
|
||||
else
|
||||
LocalCustomColors.current.primaryLight
|
||||
},
|
||||
) {
|
||||
val peer = Utils.friendlyUri(ctx, message.peerUri, account)
|
||||
val cal = GregorianCalendar()
|
||||
@ -429,20 +417,34 @@ class ChatsActivity: ComponentActivity() {
|
||||
val info = fmt.format(cal.time)
|
||||
Column {
|
||||
Row {
|
||||
Text(
|
||||
peer, color = LocalCustomColors.current.dark,
|
||||
fontSize = 12.sp
|
||||
)
|
||||
val textColor =
|
||||
if (message.direction == MESSAGE_DOWN) {
|
||||
if (BaresipService.darkTheme.value)
|
||||
LocalCustomColors.current.secondaryLight
|
||||
else
|
||||
LocalCustomColors.current.secondaryDark
|
||||
}
|
||||
else {
|
||||
if (BaresipService.darkTheme.value)
|
||||
LocalCustomColors.current.primaryLight
|
||||
else
|
||||
LocalCustomColors.current.primaryDark
|
||||
}
|
||||
Text(text = peer, color = textColor, fontSize = 12.sp)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Text(
|
||||
info, color = LocalCustomColors.current.dark,
|
||||
fontSize = 12.sp
|
||||
)
|
||||
Text(text = info, color = textColor, fontSize = 12.sp)
|
||||
}
|
||||
Row {
|
||||
Text(
|
||||
text = message.message, color = LocalCustomColors.current.dark,
|
||||
maxLines = 1
|
||||
BasicText(
|
||||
text = message.message,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = TextStyle(
|
||||
color = LocalCustomColors.current.itemText,
|
||||
fontWeight = if (message.direction == MESSAGE_DOWN && message.new)
|
||||
FontWeight.Bold else FontWeight.Normal,
|
||||
fontSize = 16.sp
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -666,7 +668,7 @@ class ChatsActivity: ComponentActivity() {
|
||||
private fun uaMessages(aor: String) : List<Message> {
|
||||
val res = mutableListOf<Message>()
|
||||
account.unreadMessages = false
|
||||
for (m in BaresipService.messages) {
|
||||
for (m in BaresipService.messages.reversed()) {
|
||||
if (m.aor != aor) continue
|
||||
var found = false
|
||||
for (r in res)
|
||||
@ -675,7 +677,7 @@ class ChatsActivity: ComponentActivity() {
|
||||
break
|
||||
}
|
||||
if (!found) {
|
||||
res.add(m)
|
||||
res.add(0, m)
|
||||
if (m.new)
|
||||
account.unreadMessages = true
|
||||
}
|
||||
|
||||
@ -9,11 +9,13 @@ import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.ScrollState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@ -26,6 +28,7 @@ import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.AlertDialogDefaults
|
||||
import androidx.compose.material3.BasicAlertDialog
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.CheckboxDefaults
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
@ -59,9 +62,11 @@ import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.SoftwareKeyboardController
|
||||
import androidx.compose.ui.res.painterResource
|
||||
@ -103,6 +108,33 @@ object CustomElements {
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Button(
|
||||
onClick: () -> Unit,
|
||||
onLongClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
shape: Shape,
|
||||
color: Color,
|
||||
content: @Composable RowScope.() -> Unit
|
||||
) {
|
||||
Surface(
|
||||
shape = shape,
|
||||
color = color,
|
||||
modifier = modifier.pointerInput(Unit) {
|
||||
detectTapGestures(
|
||||
onTap = { onClick() },
|
||||
onLongPress = { onLongClick() },
|
||||
) }
|
||||
.then(modifier),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.padding(ButtonDefaults.ContentPadding),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun PullToRefreshBox(
|
||||
|
||||
Reference in New Issue
Block a user