slightly increase padding (#295)

* slightly increase padding

* better colors

* add copy to bottom sheet

* increase font size

* base font size

* anchor chat at the bottom
This commit is contained in:
callebtc
2025-08-23 14:14:42 +02:00
committed by GitHub
parent 26520991cf
commit a7604d9026
10 changed files with 185 additions and 144 deletions
@@ -14,6 +14,7 @@ import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.zIndex
import com.bitchat.android.model.BitchatMessage
/**
* Main ChatScreen - REFACTORED to use component-based architecture
@@ -52,6 +53,7 @@ fun ChatScreen(viewModel: ChatViewModel) {
var showLocationChannelsSheet by remember { mutableStateOf(false) }
var showUserSheet by remember { mutableStateOf(false) }
var selectedUserForSheet by remember { mutableStateOf("") }
var selectedMessageForSheet by remember { mutableStateOf<BitchatMessage?>(null) }
var forceScrollToBottom by remember { mutableStateOf(false) }
// Show password dialog when needed
@@ -126,11 +128,12 @@ fun ChatScreen(viewModel: ChatViewModel) {
selection = TextRange(newText.length)
)
},
onNicknameLongPress = { fullSenderName ->
// Long press - open user action sheet
// Extract base nickname from full sender name
val (baseName, _) = splitSuffix(fullSenderName)
onMessageLongPress = { message ->
// Message long press - open user action sheet with message context
// Extract base nickname from message sender (contains all necessary info)
val (baseName, _) = splitSuffix(message.sender)
selectedUserForSheet = baseName
selectedMessageForSheet = message
showUserSheet = true
}
)
@@ -261,8 +264,12 @@ fun ChatScreen(viewModel: ChatViewModel) {
showLocationChannelsSheet = showLocationChannelsSheet,
onLocationChannelsSheetDismiss = { showLocationChannelsSheet = false },
showUserSheet = showUserSheet,
onUserSheetDismiss = { showUserSheet = false },
onUserSheetDismiss = {
showUserSheet = false
selectedMessageForSheet = null // Reset message when dismissing
},
selectedUserForSheet = selectedUserForSheet,
selectedMessageForSheet = selectedMessageForSheet,
viewModel = viewModel
)
}
@@ -387,6 +394,7 @@ private fun ChatDialogs(
showUserSheet: Boolean,
onUserSheetDismiss: () -> Unit,
selectedUserForSheet: String,
selectedMessageForSheet: BitchatMessage?,
viewModel: ChatViewModel
) {
// Password dialog
@@ -420,6 +428,7 @@ private fun ChatDialogs(
isPresented = showUserSheet,
onDismiss = onUserSheetDismiss,
targetNickname = selectedUserForSheet,
selectedMessage = selectedMessageForSheet,
viewModel = viewModel
)
}
@@ -9,6 +9,7 @@ import androidx.compose.ui.unit.sp
import com.bitchat.android.model.BitchatMessage
import com.bitchat.android.mesh.BluetoothMeshService
import androidx.compose.material3.ColorScheme
import com.bitchat.android.ui.theme.BASE_FONT_SIZE
import java.text.SimpleDateFormat
import java.util.*
@@ -63,7 +64,7 @@ fun formatMessageAsAnnotatedString(
// Sender prefix "<@"
builder.pushStyle(SpanStyle(
color = baseColor,
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontWeight = if (isSelf) FontWeight.Bold else FontWeight.Medium
))
builder.append("<@")
@@ -72,7 +73,7 @@ fun formatMessageAsAnnotatedString(
// Base name (clickable)
builder.pushStyle(SpanStyle(
color = baseColor,
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontWeight = if (isSelf) FontWeight.Bold else FontWeight.Medium
))
val nicknameStart = builder.length
@@ -94,7 +95,7 @@ fun formatMessageAsAnnotatedString(
if (suffix.isNotEmpty()) {
builder.pushStyle(SpanStyle(
color = baseColor.copy(alpha = 0.6f),
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontWeight = if (isSelf) FontWeight.Bold else FontWeight.Medium
))
builder.append(suffix)
@@ -104,7 +105,7 @@ fun formatMessageAsAnnotatedString(
// Sender suffix "> "
builder.pushStyle(SpanStyle(
color = baseColor,
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontWeight = if (isSelf) FontWeight.Bold else FontWeight.Medium
))
builder.append("> ")
@@ -116,7 +117,7 @@ fun formatMessageAsAnnotatedString(
// iOS-style timestamp at the END (smaller, grey)
builder.pushStyle(SpanStyle(
color = Color.Gray.copy(alpha = 0.7f),
fontSize = 10.sp
fontSize = (BASE_FONT_SIZE - 4).sp
))
builder.append(" [${timeFormatter.format(message.timestamp)}]")
builder.pop()
@@ -125,7 +126,7 @@ fun formatMessageAsAnnotatedString(
// System message - iOS style
builder.pushStyle(SpanStyle(
color = Color.Gray,
fontSize = 12.sp,
fontSize = (BASE_FONT_SIZE - 2).sp,
fontStyle = androidx.compose.ui.text.font.FontStyle.Italic
))
builder.append("* ${message.content} *")
@@ -134,7 +135,7 @@ fun formatMessageAsAnnotatedString(
// Timestamp for system messages too
builder.pushStyle(SpanStyle(
color = Color.Gray.copy(alpha = 0.5f),
fontSize = 10.sp
fontSize = (BASE_FONT_SIZE - 4).sp
))
builder.append(" [${timeFormatter.format(message.timestamp)}]")
builder.pop()
@@ -190,7 +191,7 @@ fun colorForPeerSeed(seed: String, isDark: Boolean): Color {
}
val saturation = if (isDark) 0.50 else 0.70
val brightness = if (isDark) 0.95 else 0.45
val brightness = if (isDark) 0.85 else 0.35
return Color.hsv(
hue = (hue * 360).toFloat(),
@@ -269,7 +270,7 @@ private fun appendIOSFormattedContent(
if (beforeText.isNotEmpty()) {
builder.pushStyle(SpanStyle(
color = baseColor,
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontWeight = if (isSelf) FontWeight.Bold else FontWeight.Normal
))
if (isMentioned) {
@@ -299,7 +300,7 @@ private fun appendIOSFormattedContent(
// "@" symbol
builder.pushStyle(SpanStyle(
color = mentionColor,
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontWeight = if (isSelf) FontWeight.Bold else FontWeight.SemiBold
))
builder.append("@")
@@ -308,7 +309,7 @@ private fun appendIOSFormattedContent(
// Base name
builder.pushStyle(SpanStyle(
color = mentionColor,
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontWeight = if (isSelf) FontWeight.Bold else FontWeight.SemiBold
))
builder.append(mBase)
@@ -318,7 +319,7 @@ private fun appendIOSFormattedContent(
if (mSuffix.isNotEmpty()) {
builder.pushStyle(SpanStyle(
color = mentionColor.copy(alpha = 0.6f),
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontWeight = if (isSelf) FontWeight.Bold else FontWeight.SemiBold
))
builder.append(mSuffix)
@@ -329,7 +330,7 @@ private fun appendIOSFormattedContent(
// iOS-style: render hashtags like normal content (no special styling)
builder.pushStyle(SpanStyle(
color = baseColor,
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontWeight = if (isSelf) FontWeight.Bold else FontWeight.Normal
))
if (isMentioned) {
@@ -351,7 +352,7 @@ private fun appendIOSFormattedContent(
val remainingText = content.substring(lastEnd)
builder.pushStyle(SpanStyle(
color = baseColor,
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontWeight = if (isSelf) FontWeight.Bold else FontWeight.Normal
))
if (isMentioned) {
@@ -11,7 +11,11 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.bitchat.android.ui.theme.BASE_FONT_SIZE
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.text.AnnotatedString
import kotlinx.coroutines.launch
import com.bitchat.android.model.BitchatMessage
/**
* User Action Sheet for selecting actions on a specific user (slap, hug, block)
@@ -23,10 +27,12 @@ fun ChatUserSheet(
isPresented: Boolean,
onDismiss: () -> Unit,
targetNickname: String,
selectedMessage: BitchatMessage? = null,
viewModel: ChatViewModel,
modifier: Modifier = Modifier
) {
val coroutineScope = rememberCoroutineScope()
val clipboardManager = LocalClipboardManager.current
// Bottom sheet state
val sheetState = rememberModalBottomSheetState(
@@ -39,6 +45,7 @@ fun ChatUserSheet(
val standardGreen = if (isDark) Color(0xFF32D74B) else Color(0xFF248A3D) // iOS green
val standardBlue = Color(0xFF007AFF) // iOS blue
val standardRed = Color(0xFFFF3B30) // iOS red
val standardGrey = if (isDark) Color(0xFF8E8E93) else Color(0xFF6D6D70) // iOS grey
if (isPresented) {
ModalBottomSheet(
@@ -62,7 +69,7 @@ fun ChatUserSheet(
)
Text(
text = "choose an action for this user",
text = if (selectedMessage != null) "choose an action for this message or user" else "choose an action for this user",
fontSize = 12.sp,
fontFamily = FontFamily.Monospace,
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f)
@@ -72,53 +79,72 @@ fun ChatUserSheet(
LazyColumn(
modifier = Modifier.fillMaxWidth()
) {
// Slap action
item {
UserActionRow(
title = "slap $targetNickname",
subtitle = "send a playful slap message",
titleColor = standardBlue,
onClick = {
// Send slap command
viewModel.sendMessage("/slap $targetNickname")
onDismiss()
}
)
}
// Hug action
item {
UserActionRow(
title = "hug $targetNickname",
subtitle = "send a friendly hug message",
titleColor = standardGreen,
onClick = {
// Send hug command
viewModel.sendMessage("/hug $targetNickname")
onDismiss()
}
)
}
// Block action
item {
UserActionRow(
title = "block $targetNickname",
subtitle = "block all messages from this user",
titleColor = standardRed,
onClick = {
// Check if we're in a geohash channel
val selectedLocationChannel = viewModel.selectedLocationChannel.value
if (selectedLocationChannel is com.bitchat.android.geohash.ChannelID.Location) {
// Get user's nostr public key and add to geohash block list
viewModel.blockUserInGeohash(targetNickname)
} else {
// Regular mesh blocking
viewModel.sendMessage("/block $targetNickname")
// Copy message action (only show if we have a message)
selectedMessage?.let { message ->
item {
UserActionRow(
title = "copy message",
subtitle = "copy this message to clipboard",
titleColor = standardGrey,
onClick = {
// Copy the message content to clipboard
clipboardManager.setText(AnnotatedString(message.content))
onDismiss()
}
onDismiss()
}
)
)
}
}
// Only show user actions for other users' messages or when no message is selected
if (selectedMessage?.sender != viewModel.nickname.value) {
// Slap action
item {
UserActionRow(
title = "slap $targetNickname",
subtitle = "send a playful slap message",
titleColor = standardBlue,
onClick = {
// Send slap command
viewModel.sendMessage("/slap $targetNickname")
onDismiss()
}
)
}
// Hug action
item {
UserActionRow(
title = "hug $targetNickname",
subtitle = "send a friendly hug message",
titleColor = standardGreen,
onClick = {
// Send hug command
viewModel.sendMessage("/hug $targetNickname")
onDismiss()
}
)
}
// Block action
item {
UserActionRow(
title = "block $targetNickname",
subtitle = "block all messages from this user",
titleColor = standardRed,
onClick = {
// Check if we're in a geohash channel
val selectedLocationChannel = viewModel.selectedLocationChannel.value
if (selectedLocationChannel is com.bitchat.android.geohash.ChannelID.Location) {
// Get user's nostr public key and add to geohash block list
viewModel.blockUserInGeohash(targetNickname)
} else {
// Regular mesh blocking
viewModel.sendMessage("/block $targetNickname")
}
onDismiss()
}
)
}
}
}
@@ -133,7 +159,7 @@ fun ChatUserSheet(
) {
Text(
text = "cancel",
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontFamily = FontFamily.Monospace
)
}
@@ -164,7 +190,7 @@ private fun UserActionRow(
) {
Text(
text = title,
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Medium,
color = titleColor
@@ -15,6 +15,7 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.bitchat.android.ui.theme.BASE_FONT_SIZE
import java.util.*
/**
@@ -77,7 +78,7 @@ fun GeohashPeopleList(
text = "nobody around...",
style = MaterialTheme.typography.bodyMedium.copy(
fontFamily = FontFamily.Monospace,
fontSize = 14.sp
fontSize = BASE_FONT_SIZE.sp
),
color = colorScheme.onSurface.copy(alpha = 0.5f),
modifier = Modifier.padding(horizontal = 24.dp, vertical = 12.dp)
@@ -212,7 +213,7 @@ private fun GeohashPersonItem(
text = baseName,
style = MaterialTheme.typography.bodyMedium.copy(
fontFamily = FontFamily.Monospace,
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontWeight = if (isMe) FontWeight.Bold else FontWeight.Normal
),
color = baseColor
@@ -224,7 +225,7 @@ private fun GeohashPersonItem(
text = suffix,
style = MaterialTheme.typography.bodyMedium.copy(
fontFamily = FontFamily.Monospace,
fontSize = 14.sp
fontSize = BASE_FONT_SIZE.sp
),
color = baseColor.copy(alpha = 0.6f)
)
@@ -236,7 +237,7 @@ private fun GeohashPersonItem(
text = " (you)",
style = MaterialTheme.typography.bodyMedium.copy(
fontFamily = FontFamily.Monospace,
fontSize = 14.sp
fontSize = BASE_FONT_SIZE.sp
),
color = baseColor
)
@@ -34,6 +34,7 @@ import androidx.compose.ui.unit.sp
import com.bitchat.android.R
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.text.withStyle
import com.bitchat.android.ui.theme.BASE_FONT_SIZE
/**
* Input components for ChatScreen
@@ -326,7 +327,7 @@ fun CommandSuggestionItem(
fontWeight = FontWeight.Medium
),
color = colorScheme.primary,
fontSize = 11.sp
fontSize = (BASE_FONT_SIZE - 4).sp
)
// Show syntax if any
@@ -337,7 +338,7 @@ fun CommandSuggestionItem(
fontFamily = FontFamily.Monospace
),
color = colorScheme.onSurface.copy(alpha = 0.8f),
fontSize = 10.sp
fontSize = (BASE_FONT_SIZE - 5).sp
)
}
@@ -348,7 +349,7 @@ fun CommandSuggestionItem(
fontFamily = FontFamily.Monospace
),
color = colorScheme.onSurface.copy(alpha = 0.7f),
fontSize = 10.sp,
fontSize = (BASE_FONT_SIZE - 5).sp,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
@@ -400,7 +401,7 @@ fun MentionSuggestionItem(
fontWeight = FontWeight.SemiBold
),
color = Color(0xFFFF9500), // Orange like mentions
fontSize = 11.sp
fontSize = (BASE_FONT_SIZE - 4).sp
)
Spacer(modifier = Modifier.weight(1f))
@@ -411,7 +412,7 @@ fun MentionSuggestionItem(
fontFamily = FontFamily.Monospace
),
color = colorScheme.onSurface.copy(alpha = 0.7f),
fontSize = 10.sp
fontSize = (BASE_FONT_SIZE - 5).sp
)
}
}
@@ -21,6 +21,7 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.bitchat.android.ui.theme.BASE_FONT_SIZE
import java.net.URL
/**
@@ -109,7 +110,7 @@ fun LinkPreviewPill(
Text(
text = displayTitle,
fontFamily = FontFamily.Monospace,
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontWeight = FontWeight.SemiBold,
color = textColor,
maxLines = 2,
@@ -23,6 +23,7 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.bitchat.android.ui.theme.BASE_FONT_SIZE
import kotlinx.coroutines.launch
import com.bitchat.android.geohash.ChannelID
import com.bitchat.android.geohash.GeohashChannel
@@ -240,7 +241,7 @@ fun LocationChannelsSheet(
) {
Text(
text = "#",
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontFamily = FontFamily.Monospace,
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f)
)
@@ -260,7 +261,7 @@ fun LocationChannelsSheet(
customError = null
},
textStyle = androidx.compose.ui.text.TextStyle(
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontFamily = FontFamily.Monospace,
color = MaterialTheme.colorScheme.onSurface
),
@@ -283,7 +284,7 @@ fun LocationChannelsSheet(
if (customGeohash.isEmpty()) {
Text(
text = "geohash",
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontFamily = FontFamily.Monospace,
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.4f)
)
@@ -321,7 +322,7 @@ fun LocationChannelsSheet(
) {
Text(
text = "teleport",
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontFamily = FontFamily.Monospace
)
// iOS has a face.dashed icon, use closest Material equivalent
@@ -446,7 +447,7 @@ private fun ChannelRow(
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
Text(
text = baseTitle,
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontFamily = FontFamily.Monospace,
fontWeight = if (titleBold) FontWeight.Bold else FontWeight.Normal,
color = titleColor ?: MaterialTheme.colorScheme.onSurface
@@ -7,7 +7,7 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
@@ -37,7 +37,7 @@ fun MessagesList(
modifier: Modifier = Modifier,
forceScrollToBottom: Boolean = false,
onNicknameClick: ((String) -> Unit)? = null,
onNicknameLongPress: ((String) -> Unit)? = null
onMessageLongPress: ((BitchatMessage) -> Unit)? = null
) {
val listState = rememberLazyListState()
@@ -48,15 +48,14 @@ fun MessagesList(
LaunchedEffect(messages.size) {
if (messages.isNotEmpty()) {
val layoutInfo = listState.layoutInfo
val lastVisibleIndex = layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: -1
val totalItems = layoutInfo.totalItemsCount
val firstVisibleIndex = layoutInfo.visibleItemsInfo.firstOrNull()?.index ?: -1
// Always scroll to bottom on first load, or when user is near the bottom
// With reverseLayout=true and reversed data, index 0 is the latest message at the bottom
val isFirstLoad = !hasScrolledToInitialPosition
val isNearBottom = lastVisibleIndex >= totalItems - 3
val isNearLatest = firstVisibleIndex <= 2
if (isFirstLoad || isNearBottom) {
listState.animateScrollToItem(messages.size - 1)
if (isFirstLoad || isNearLatest) {
listState.animateScrollToItem(0)
if (isFirstLoad) {
hasScrolledToInitialPosition = true
}
@@ -67,25 +66,26 @@ fun MessagesList(
// Force scroll to bottom when requested (e.g., when user sends a message)
LaunchedEffect(forceScrollToBottom) {
if (forceScrollToBottom && messages.isNotEmpty()) {
listState.animateScrollToItem(messages.size - 1)
// With reverseLayout=true and reversed data, latest is at index 0
listState.animateScrollToItem(0)
}
}
SelectionContainer(modifier = modifier) {
LazyColumn(
state = listState,
contentPadding = PaddingValues(horizontal = 12.dp, vertical = 8.dp),
verticalArrangement = Arrangement.spacedBy(2.dp)
) {
items(messages) { message ->
LazyColumn(
state = listState,
contentPadding = PaddingValues(horizontal = 12.dp, vertical = 8.dp),
verticalArrangement = Arrangement.spacedBy(4.dp),
modifier = modifier,
reverseLayout = true
) {
items(messages.asReversed()) { message ->
MessageItem(
message = message,
currentUserNickname = currentUserNickname,
meshService = meshService,
onNicknameClick = onNicknameClick,
onNicknameLongPress = onNicknameLongPress
onMessageLongPress = onMessageLongPress
)
}
}
}
}
@@ -97,7 +97,7 @@ fun MessageItem(
currentUserNickname: String,
meshService: BluetoothMeshService,
onNicknameClick: ((String) -> Unit)? = null,
onNicknameLongPress: ((String) -> Unit)? = null
onMessageLongPress: ((BitchatMessage) -> Unit)? = null
) {
val colorScheme = MaterialTheme.colorScheme
val timeFormatter = remember { SimpleDateFormat("HH:mm:ss", Locale.getDefault()) }
@@ -119,7 +119,7 @@ fun MessageItem(
colorScheme = colorScheme,
timeFormatter = timeFormatter,
onNicknameClick = onNicknameClick,
onNicknameLongPress = onNicknameLongPress,
onMessageLongPress = onMessageLongPress,
modifier = Modifier.weight(1f)
)
@@ -164,7 +164,7 @@ private fun MessageTextWithClickableNicknames(
colorScheme: ColorScheme,
timeFormatter: SimpleDateFormat,
onNicknameClick: ((String) -> Unit)?,
onNicknameLongPress: ((String) -> Unit)?,
onMessageLongPress: ((BitchatMessage) -> Unit)?,
modifier: Modifier = Modifier
) {
val annotatedText = formatMessageAsAnnotatedString(
@@ -180,8 +180,8 @@ private fun MessageTextWithClickableNicknames(
message.sender == currentUserNickname ||
message.sender.startsWith("$currentUserNickname#")
if (!isSelf && (onNicknameClick != null || onNicknameLongPress != null)) {
// Use Text with combinedClickable for nickname interactions
if (!isSelf && (onNicknameClick != null || onMessageLongPress != null)) {
// Use Text with combinedClickable for nickname interactions and message long press
Text(
text = annotatedText,
modifier = modifier.combinedClickable(
@@ -198,16 +198,8 @@ private fun MessageTextWithClickableNicknames(
}
},
onLongClick = {
// Handle long press for the first nickname
val nicknameAnnotations = annotatedText.getStringAnnotations(
tag = "nickname_click",
start = 0,
end = annotatedText.length
)
if (nicknameAnnotations.isNotEmpty()) {
val nickname = nicknameAnnotations.first().item
onNicknameLongPress?.invoke(nickname)
}
// Always use message long press - contains all necessary information
onMessageLongPress?.invoke(message)
}
),
fontFamily = FontFamily.Monospace,
@@ -218,19 +210,24 @@ private fun MessageTextWithClickableNicknames(
)
)
} else {
// Use selectable text when no interactions needed
SelectionContainer {
Text(
text = annotatedText,
modifier = modifier,
fontFamily = FontFamily.Monospace,
softWrap = true,
overflow = TextOverflow.Visible,
style = androidx.compose.ui.text.TextStyle(
color = colorScheme.onSurface
// Use regular text with message long press support for own messages
Text(
text = annotatedText,
modifier = if (onMessageLongPress != null) {
modifier.combinedClickable(
onClick = { /* No action for own messages */ },
onLongClick = { onMessageLongPress.invoke(message) }
)
} else {
modifier
},
fontFamily = FontFamily.Monospace,
softWrap = true,
overflow = TextOverflow.Visible,
style = androidx.compose.ui.text.TextStyle(
color = colorScheme.onSurface
)
}
)
}
}
@@ -21,6 +21,7 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.bitchat.android.ui.theme.BASE_FONT_SIZE
/**
@@ -400,7 +401,7 @@ private fun PeerItem(
text = baseName,
style = MaterialTheme.typography.bodyMedium.copy(
fontFamily = FontFamily.Monospace,
fontSize = 14.sp,
fontSize = BASE_FONT_SIZE.sp,
fontWeight = if (isMe) FontWeight.Bold else FontWeight.Normal
),
color = baseColor
@@ -412,7 +413,7 @@ private fun PeerItem(
text = suffix,
style = MaterialTheme.typography.bodyMedium.copy(
fontFamily = FontFamily.Monospace,
fontSize = 14.sp
fontSize = BASE_FONT_SIZE.sp
),
color = baseColor.copy(alpha = 0.6f)
)
@@ -6,48 +6,51 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
// Typography matching the iOS monospace design - increased font sizes for better readability
// Base font size for consistent scaling across the app
const val BASE_FONT_SIZE = 15 // sp - increased from 14sp for better readability
// Typography matching the iOS monospace design - using BASE_FONT_SIZE for consistency
val Typography = Typography(
bodyLarge = TextStyle(
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 22.sp
fontSize = (BASE_FONT_SIZE + 1).sp,
lineHeight = (BASE_FONT_SIZE + 7).sp
),
bodyMedium = TextStyle(
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Normal,
fontSize = 14.sp,
lineHeight = 18.sp
fontSize = BASE_FONT_SIZE.sp,
lineHeight = (BASE_FONT_SIZE + 3).sp
),
bodySmall = TextStyle(
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Normal,
fontSize = 12.sp,
lineHeight = 16.sp
fontSize = (BASE_FONT_SIZE - 3).sp,
lineHeight = (BASE_FONT_SIZE + 1).sp
),
headlineSmall = TextStyle(
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Medium,
fontSize = 18.sp,
lineHeight = 24.sp
fontSize = (BASE_FONT_SIZE + 3).sp,
lineHeight = (BASE_FONT_SIZE + 9).sp
),
titleMedium = TextStyle(
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Medium,
fontSize = 16.sp,
lineHeight = 22.sp
fontSize = (BASE_FONT_SIZE + 1).sp,
lineHeight = (BASE_FONT_SIZE + 7).sp
),
labelMedium = TextStyle(
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Medium,
fontSize = 13.sp,
lineHeight = 18.sp
fontSize = (BASE_FONT_SIZE - 2).sp,
lineHeight = (BASE_FONT_SIZE + 3).sp
),
labelSmall = TextStyle(
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Normal,
fontSize = 11.sp,
lineHeight = 16.sp
fontSize = (BASE_FONT_SIZE - 4).sp,
lineHeight = (BASE_FONT_SIZE + 1).sp
)
)