mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 05:05:20 +00:00
Merge branch 'main' of ssh://github.com/permissionlesstech/bitchat-android into prudhvir3ddy/upgrade_deps
This commit is contained in:
@@ -30,10 +30,11 @@ fun PermissionExplanationScreen(
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(24.dp)
|
||||
.padding(horizontal = 24.dp)
|
||||
.verticalScroll(scrollState),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
// Header
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
@@ -164,6 +165,7 @@ fun PermissionExplanationScreen(
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -284,9 +284,21 @@ class ChannelManager(
|
||||
state.setShowPasswordPrompt(false)
|
||||
state.setPasswordPromptChannel(null)
|
||||
}
|
||||
|
||||
fun setChannelPassword(channel: String, password: String): Boolean {
|
||||
return verifyChannelPassword(channel, password)
|
||||
|
||||
fun setChannelPassword(channel: String, password: String) {
|
||||
|
||||
channelPasswords[channel] = password
|
||||
|
||||
channelKeys[channel] = deriveChannelKey(password, channel)
|
||||
|
||||
state.setPasswordProtectedChannels(
|
||||
state.getPasswordProtectedChannelsValue().toMutableSet().apply { add(channel) }
|
||||
)
|
||||
|
||||
dataManager.saveChannelData(
|
||||
state.getJoinedChannelsValue(),
|
||||
state.getPasswordProtectedChannelsValue()
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - Emergency Clear
|
||||
|
||||
@@ -103,7 +103,7 @@ fun PeerCounter(
|
||||
imageVector = Icons.Filled.Email,
|
||||
contentDescription = "Unread private messages",
|
||||
modifier = Modifier.size(16.dp),
|
||||
tint = Color(0xFFFF8C00) // Orange to match private message theme
|
||||
tint = Color(0xFFFF9500) // Orange to match private message theme
|
||||
)
|
||||
Spacer(modifier = Modifier.width(6.dp))
|
||||
}
|
||||
@@ -201,19 +201,18 @@ private fun PrivateChatHeader(
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
val peerNickname = peerNicknames[peerID] ?: peerID
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// Fixed: Make back button wider to prevent text cropping
|
||||
Box(modifier = Modifier.fillMaxWidth()) {
|
||||
// Back button - positioned all the way to the left with minimal margin
|
||||
Button(
|
||||
onClick = onBackClick,
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color.Transparent,
|
||||
contentColor = colorScheme.primary
|
||||
),
|
||||
contentPadding = PaddingValues(horizontal = 12.dp, vertical = 4.dp)
|
||||
contentPadding = PaddingValues(horizontal = 4.dp, vertical = 4.dp), // Reduced horizontal padding
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterStart)
|
||||
.offset(x = (-8).dp) // Move even further left to minimize margin
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
@@ -233,27 +232,30 @@ private fun PrivateChatHeader(
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
// Title - perfectly centered regardless of other elements
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Lock,
|
||||
contentDescription = "Private chat",
|
||||
modifier = Modifier.size(16.dp),
|
||||
tint = Color(0xFFFF8C00) // Orange to match private message theme
|
||||
tint = Color(0xFFFF9500) // Orange to match private message theme
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text(
|
||||
text = peerNickname,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = Color(0xFFFF8C00) // Orange
|
||||
color = Color(0xFFFF9500) // Orange
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
// Favorite button with proper filled/outlined star
|
||||
IconButton(onClick = onToggleFavorite) {
|
||||
// Favorite button - positioned on the right
|
||||
IconButton(
|
||||
onClick = onToggleFavorite,
|
||||
modifier = Modifier.align(Alignment.CenterEnd)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = if (isFavorite) Icons.Filled.Star else Icons.Outlined.Star,
|
||||
contentDescription = if (isFavorite) "Remove from favorites" else "Add to favorites",
|
||||
@@ -273,12 +275,19 @@ private fun ChannelHeader(
|
||||
) {
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
IconButton(onClick = onBackClick) {
|
||||
Box(modifier = Modifier.fillMaxWidth()) {
|
||||
// Back button - positioned all the way to the left with minimal margin
|
||||
Button(
|
||||
onClick = onBackClick,
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color.Transparent,
|
||||
contentColor = colorScheme.primary
|
||||
),
|
||||
contentPadding = PaddingValues(horizontal = 4.dp, vertical = 4.dp), // Reduced horizontal padding
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterStart)
|
||||
.offset(x = (-8).dp) // Move even further left to minimize margin
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
@@ -297,18 +306,21 @@ private fun ChannelHeader(
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
// Title - perfectly centered regardless of other elements
|
||||
Text(
|
||||
text = "channel: $channel",
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = Color(0xFF0080FF), // Blue
|
||||
modifier = Modifier.clickable { onSidebarClick() }
|
||||
color = Color(0xFFFF9500), // Orange to match input field
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.clickable { onSidebarClick() }
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
TextButton(onClick = onLeaveChannel) {
|
||||
// Leave button - positioned on the right
|
||||
TextButton(
|
||||
onClick = onLeaveChannel,
|
||||
modifier = Modifier.align(Alignment.CenterEnd)
|
||||
) {
|
||||
Text(
|
||||
text = "leave",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
|
||||
@@ -139,7 +139,7 @@ private fun appendFormattedContent(
|
||||
}
|
||||
"mention" -> {
|
||||
builder.pushStyle(SpanStyle(
|
||||
color = Color(0xFFFF8C00), // Orange
|
||||
color = Color(0xFFFF9500), // Orange
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.SemiBold
|
||||
))
|
||||
|
||||
@@ -37,8 +37,9 @@ class CommandProcessor(
|
||||
when (cmd) {
|
||||
"/j", "/join" -> handleJoinCommand(parts, myPeerID)
|
||||
"/m", "/msg" -> handleMessageCommand(parts, meshService)
|
||||
"/w" -> handleWhoCommand()
|
||||
"/w" -> handleWhoCommand(meshService)
|
||||
"/clear" -> handleClearCommand()
|
||||
"/pass" -> handlePassCommand(parts, myPeerID)
|
||||
"/block" -> handleBlockCommand(parts, meshService)
|
||||
"/unblock" -> handleUnblockCommand(parts, meshService)
|
||||
"/hug" -> handleActionCommand(parts, "gives", "a warm hug 🫂", meshService, myPeerID, onSendMessage)
|
||||
@@ -54,7 +55,8 @@ class CommandProcessor(
|
||||
if (parts.size > 1) {
|
||||
val channelName = parts[1]
|
||||
val channel = if (channelName.startsWith("#")) channelName else "#$channelName"
|
||||
val success = channelManager.joinChannel(channel, null, myPeerID)
|
||||
val password = if (parts.size > 2) parts[2] else null
|
||||
val success = channelManager.joinChannel(channel, password, myPeerID)
|
||||
if (success) {
|
||||
val systemMessage = BitchatMessage(
|
||||
sender = "system",
|
||||
@@ -127,11 +129,11 @@ class CommandProcessor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleWhoCommand() {
|
||||
private fun handleWhoCommand(meshService: Any) {
|
||||
val connectedPeers = state.getConnectedPeersValue()
|
||||
val peerList = connectedPeers.joinToString(", ") { peerID ->
|
||||
// This would need mesh service access for nicknames
|
||||
peerID // For now just use peer ID
|
||||
// Convert peerID to nickname using the mesh service
|
||||
getPeerNickname(peerID, meshService)
|
||||
}
|
||||
|
||||
val systemMessage = BitchatMessage(
|
||||
@@ -165,6 +167,52 @@ class CommandProcessor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handlePassCommand(parts: List<String>, peerID: String) {
|
||||
val currentChannel = state.getCurrentChannelValue()
|
||||
|
||||
if (currentChannel == null) {
|
||||
val systemMessage = BitchatMessage(
|
||||
sender = "system",
|
||||
content = "you must be in a channel to set a password.",
|
||||
timestamp = Date(),
|
||||
isRelay = false
|
||||
)
|
||||
messageManager.addMessage(systemMessage)
|
||||
return
|
||||
}
|
||||
|
||||
if (parts.size == 2){
|
||||
if(!channelManager.isChannelCreator(channel = currentChannel, peerID = peerID)){
|
||||
val systemMessage = BitchatMessage(
|
||||
sender = "system",
|
||||
content = "you must be the channel creator to set a password.",
|
||||
timestamp = Date(),
|
||||
isRelay = false
|
||||
)
|
||||
channelManager.addChannelMessage(currentChannel,systemMessage,null)
|
||||
return
|
||||
}
|
||||
val newPassword = parts[1]
|
||||
channelManager.setChannelPassword(currentChannel, newPassword)
|
||||
val systemMessage = BitchatMessage(
|
||||
sender = "system",
|
||||
content = "password changed for channel $currentChannel",
|
||||
timestamp = Date(),
|
||||
isRelay = false
|
||||
)
|
||||
channelManager.addChannelMessage(currentChannel,systemMessage,null)
|
||||
}
|
||||
else{
|
||||
val systemMessage = BitchatMessage(
|
||||
sender = "system",
|
||||
content = "usage: /pass <password>",
|
||||
timestamp = Date(),
|
||||
isRelay = false
|
||||
)
|
||||
channelManager.addChannelMessage(currentChannel,systemMessage,null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleBlockCommand(parts: List<String>, meshService: Any) {
|
||||
if (parts.size > 1) {
|
||||
|
||||
@@ -44,20 +44,17 @@ fun MessageInput(
|
||||
modifier = modifier.padding(horizontal = 12.dp, vertical = 8.dp), // Reduced padding
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// Fixed: Remove arrow from private message input
|
||||
// Remove arrow from both private and channel inputs to match DM style
|
||||
Text(
|
||||
text = when {
|
||||
selectedPrivatePeer != null -> "<@$nickname>" // Removed arrow for private
|
||||
currentChannel != null -> "<@$nickname> →" // Keep arrow for channels
|
||||
else -> "<@$nickname>"
|
||||
},
|
||||
text = "<@$nickname>", // No arrow for both private and channel
|
||||
style = MaterialTheme.typography.bodySmall.copy(fontWeight = FontWeight.Medium),
|
||||
color = when {
|
||||
selectedPrivatePeer != null -> Color(0xFFFF8C00) // Orange for private
|
||||
currentChannel != null -> Color(0xFFFF8C00) // Orange if encrypted channel
|
||||
selectedPrivatePeer != null -> Color(0xFFFF9500) // Orange for private
|
||||
currentChannel != null -> Color(0xFFFF9500) // Orange for channels too
|
||||
else -> colorScheme.primary
|
||||
},
|
||||
fontFamily = FontFamily.Monospace
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontSize = 14.sp
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
@@ -78,7 +75,7 @@ fun MessageInput(
|
||||
|
||||
Spacer(modifier = Modifier.width(8.dp)) // Reduced spacing
|
||||
|
||||
// Fixed: Make send button orange in private mode to match nickname color
|
||||
// Update send button to match input field colors
|
||||
IconButton(
|
||||
onClick = onSend,
|
||||
modifier = Modifier.size(32.dp)
|
||||
@@ -87,9 +84,9 @@ fun MessageInput(
|
||||
modifier = Modifier
|
||||
.size(30.dp)
|
||||
.background(
|
||||
color = if (selectedPrivatePeer != null) {
|
||||
// Orange for private messages to match nickname color
|
||||
Color(0xFFFF8C00).copy(alpha = 0.75f)
|
||||
color = if (selectedPrivatePeer != null || currentChannel != null) {
|
||||
// Orange for both private messages and channels to match nickname color
|
||||
Color(0xFFFF9500).copy(alpha = 0.75f)
|
||||
} else if (colorScheme.background == Color.Black) {
|
||||
Color(0xFF00FF00).copy(alpha = 0.75f) // Bright green for dark theme
|
||||
} else {
|
||||
@@ -100,11 +97,11 @@ fun MessageInput(
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.KeyboardArrowUp,
|
||||
imageVector = Icons.Filled.KeyboardArrowRight,
|
||||
contentDescription = "Send message",
|
||||
modifier = Modifier.size(20.dp),
|
||||
tint = if (selectedPrivatePeer != null) {
|
||||
// Black arrow on orange in private mode
|
||||
tint = if (selectedPrivatePeer != null || currentChannel != null) {
|
||||
// Black arrow on orange for both private and channel modes
|
||||
Color.Black
|
||||
} else if (colorScheme.background == Color.Black) {
|
||||
Color.Black // Black arrow on bright green in dark theme
|
||||
|
||||
@@ -193,7 +193,7 @@ fun ChannelsSection(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = "#$channel",
|
||||
text = channel, // Channel already contains the # prefix
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = if (isSelected) colorScheme.primary else colorScheme.onSurface,
|
||||
fontWeight = if (isSelected) FontWeight.Medium else FontWeight.Normal,
|
||||
@@ -320,7 +320,7 @@ private fun PeerItem(
|
||||
imageVector = Icons.Filled.Email,
|
||||
contentDescription = "Unread messages",
|
||||
modifier = Modifier.size(16.dp),
|
||||
tint = Color(0xFFFF8C00) // Orange to match private message theme
|
||||
tint = Color(0xFFFF9500) // Orange to match private message theme
|
||||
)
|
||||
} else {
|
||||
// Signal strength indicators
|
||||
|
||||
Reference in New Issue
Block a user