diff --git a/app/src/main/kotlin/com/tutpro/baresip/ChatActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/ChatActivity.kt index bc03c3d4..e7ac4df1 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/ChatActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/ChatActivity.kt @@ -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"] diff --git a/app/src/main/kotlin/com/tutpro/baresip/ChatsActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/ChatsActivity.kt index 7413c54c..7198eb9d 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/ChatsActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/ChatsActivity.kt @@ -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 { val res = mutableListOf() 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 } diff --git a/app/src/main/kotlin/com/tutpro/baresip/CustomElements.kt b/app/src/main/kotlin/com/tutpro/baresip/CustomElements.kt index bba968c9..0d5d1dee 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/CustomElements.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/CustomElements.kt @@ -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(