mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
Feat/2061 public ind (#2284)
This commit is contained in:
parent
80723c59cc
commit
3d9b69eda5
5 changed files with 92 additions and 14 deletions
|
|
@ -177,6 +177,7 @@ data class Contact(
|
|||
val isMuted: Boolean,
|
||||
val isUnmessageable: Boolean,
|
||||
val nodeColors: Pair<Int, Int>? = null,
|
||||
val isDefaultPSK: Boolean? = false
|
||||
)
|
||||
|
||||
@Suppress("LongParameterList", "LargeClass")
|
||||
|
|
@ -519,6 +520,15 @@ class UIViewModel @Inject constructor(
|
|||
} else {
|
||||
user.longName
|
||||
}
|
||||
val isDefaultPSK = if (toBroadcast) {
|
||||
val _channel = channelSet.getChannel(data.channel)
|
||||
val isDefaultPSK = (_channel?.settings?.psk?.size() == 1 &&
|
||||
_channel.settings.psk.byteAt(0) == 1.toByte()) ||
|
||||
_channel?.settings?.psk?.toByteArray()?.isEmpty() == true
|
||||
isDefaultPSK
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
Contact(
|
||||
contactKey = contactKey,
|
||||
|
|
@ -535,6 +545,7 @@ class UIViewModel @Inject constructor(
|
|||
} else {
|
||||
null
|
||||
},
|
||||
isDefaultPSK = isDefaultPSK
|
||||
)
|
||||
}
|
||||
}.stateIn(
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import androidx.compose.foundation.combinedClickable
|
|||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
|
|
@ -41,6 +42,7 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
|
|
@ -49,6 +51,7 @@ import androidx.compose.ui.unit.dp
|
|||
import com.geeksville.mesh.R
|
||||
import com.geeksville.mesh.model.Contact
|
||||
import com.geeksville.mesh.ui.common.theme.AppTheme
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
|
|
@ -108,10 +111,23 @@ fun ContactItem(
|
|||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Text(
|
||||
text = longName,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.weight(1f)) {
|
||||
Text(
|
||||
text = longName,
|
||||
)
|
||||
// Show unlock icon for broadcast with default PSK
|
||||
val isBroadcast = contact.contactKey.getOrNull(1) == '^' ||
|
||||
contact.contactKey.endsWith("^all") ||
|
||||
contact.contactKey.endsWith("^broadcast")
|
||||
|
||||
if (isBroadcast && isDefaultPSK == true) {
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_lock_open_right_24),
|
||||
contentDescription = "Unlocked"
|
||||
)
|
||||
}
|
||||
}
|
||||
Text(
|
||||
text = lastMessageTime.orEmpty(),
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
|
|
@ -172,7 +188,7 @@ private fun ContactItemPreview() {
|
|||
unreadCount = 2,
|
||||
messageCount = 10,
|
||||
isMuted = true,
|
||||
isUnmessageable = false,
|
||||
isUnmessageable = false
|
||||
),
|
||||
selected = false,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
|
|
@ -76,6 +77,7 @@ import androidx.compose.ui.platform.ClipEntry
|
|||
import androidx.compose.ui.platform.LocalClipboard
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||
|
|
@ -97,6 +99,7 @@ import com.geeksville.mesh.ui.node.components.NodeKeyStatusIcon
|
|||
import com.geeksville.mesh.ui.node.components.NodeMenuAction
|
||||
import com.geeksville.mesh.ui.sharing.SharedContactDialog
|
||||
import kotlinx.coroutines.launch
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
|
||||
private const val MESSAGE_CHARACTER_LIMIT = 200
|
||||
private const val SNIPPET_CHARACTER_LIMIT = 50
|
||||
|
|
@ -122,12 +125,20 @@ internal fun MessageScreen(
|
|||
val channels by viewModel.channels.collectAsStateWithLifecycle()
|
||||
val channelName by remember(channelIndex) {
|
||||
derivedStateOf {
|
||||
channelIndex?.let { channels.getChannel(it)?.name } ?: "Unknown Channel"
|
||||
channelIndex?.let {
|
||||
val channel = channels.getChannel(it)
|
||||
val name = channel?.name ?: "Unknown Channel"
|
||||
// Check if PSK is the default (base64 'AQ==', i.e., single byte 0x01)
|
||||
val isDefaultPSK = (channel?.settings?.psk?.size() == 1 &&
|
||||
channel.settings.psk.byteAt(0) == 1.toByte()) ||
|
||||
channel?.psk?.toByteArray()?.isEmpty() == true
|
||||
Pair(name, isDefaultPSK)
|
||||
} ?: Pair("Unknown Channel", false)
|
||||
}
|
||||
}
|
||||
|
||||
val (channelTitle, isDefaultPsk) = channelName
|
||||
val title = when (nodeId) {
|
||||
DataPacket.ID_BROADCAST -> channelName
|
||||
DataPacket.ID_BROADCAST -> channelTitle
|
||||
else -> viewModel.getUser(nodeId).longName
|
||||
}
|
||||
viewModel.setTitle(title)
|
||||
|
|
@ -201,7 +212,8 @@ internal fun MessageScreen(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
MessageTopBar(title, channelIndex, mismatchKey, onNavigateBack)
|
||||
MessageTopBar(title, channelIndex, mismatchKey, onNavigateBack, isDefaultPsk = isDefaultPsk
|
||||
)
|
||||
}
|
||||
},
|
||||
) { padding ->
|
||||
|
|
@ -442,9 +454,22 @@ private fun MessageTopBar(
|
|||
title: String,
|
||||
channelIndex: Int?,
|
||||
mismatchKey: Boolean = false,
|
||||
onNavigateBack: () -> Unit
|
||||
onNavigateBack: () -> Unit,
|
||||
isDefaultPsk: Boolean = false
|
||||
) = TopAppBar(
|
||||
title = { Text(text = title) },
|
||||
title = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(text = title)
|
||||
if (isDefaultPsk
|
||||
) {
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_lock_open_right_24),
|
||||
contentDescription = "Unlocked"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onNavigateBack) {
|
||||
Icon(
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
|
|
@ -61,6 +62,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -78,6 +80,7 @@ import com.geeksville.mesh.ui.common.components.dragContainer
|
|||
import com.geeksville.mesh.ui.common.components.dragDropItemsIndexed
|
||||
import com.geeksville.mesh.ui.common.components.rememberDragDropState
|
||||
import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
|
||||
@Composable
|
||||
private fun ChannelItem(
|
||||
|
|
@ -122,12 +125,20 @@ fun ChannelCard(
|
|||
enabled: Boolean,
|
||||
onEditClick: () -> Unit,
|
||||
onDeleteClick: () -> Unit,
|
||||
isDefaultPSK: Boolean = false,
|
||||
) = ChannelItem(
|
||||
index = index,
|
||||
title = title,
|
||||
enabled = enabled,
|
||||
onClick = onEditClick,
|
||||
) {
|
||||
if (isDefaultPSK) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_lock_open_right_24),
|
||||
contentDescription = "Unlocked"
|
||||
)
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
}
|
||||
IconButton(onClick = { onDeleteClick() }) {
|
||||
Icon(
|
||||
imageVector = Icons.TwoTone.Close,
|
||||
|
|
@ -143,13 +154,20 @@ fun ChannelSelection(
|
|||
title: String,
|
||||
enabled: Boolean,
|
||||
isSelected: Boolean,
|
||||
onSelected: (Boolean) -> Unit
|
||||
onSelected: (Boolean) -> Unit,
|
||||
isDefaultPSK: Boolean = false,
|
||||
) = ChannelItem(
|
||||
index = index,
|
||||
title = title,
|
||||
enabled = enabled,
|
||||
onClick = {},
|
||||
) {
|
||||
if (isDefaultPSK) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_lock_open_right_24),
|
||||
contentDescription = "Unlocked"
|
||||
)
|
||||
}
|
||||
Checkbox(
|
||||
enabled = enabled,
|
||||
checked = isSelected,
|
||||
|
|
@ -274,12 +292,15 @@ fun ChannelSettingsItemList(
|
|||
items = settingsListInput,
|
||||
dragDropState = dragDropState,
|
||||
) { index, channel, isDragging ->
|
||||
val isDefaultPSK = (channel.psk.size() == 1 && channel.psk.byteAt(0) == 1.toByte()) ||
|
||||
channel.psk.toByteArray().isEmpty()
|
||||
ChannelCard(
|
||||
index = index,
|
||||
title = channel.name.ifEmpty { primaryChannel.name },
|
||||
enabled = enabled,
|
||||
onEditClick = { showEditChannelDialog = index },
|
||||
onDeleteClick = { settingsListInput.removeAt(index) }
|
||||
onDeleteClick = { settingsListInput.removeAt(index) },
|
||||
isDefaultPSK = isDefaultPSK
|
||||
)
|
||||
if (index == 0 && !isDragging) {
|
||||
Text(
|
||||
|
|
|
|||
|
|
@ -448,9 +448,13 @@ private fun ChannelListView(
|
|||
AdaptiveTwoPane(
|
||||
first = {
|
||||
channelSet.settingsList.forEachIndexed { index, channel ->
|
||||
val isDefaultPSK = (channel.psk.size() == 1 && channel.psk.byteAt(0) == 1.toByte()) ||
|
||||
channel.psk.toByteArray().isEmpty()
|
||||
val displayTitle = channel.name.ifEmpty { modemPresetName }
|
||||
|
||||
ChannelSelection(
|
||||
index = index,
|
||||
title = channel.name.ifEmpty { modemPresetName },
|
||||
title = displayTitle,
|
||||
enabled = enabled,
|
||||
isSelected = channelSelections[index],
|
||||
onSelected = {
|
||||
|
|
@ -458,6 +462,7 @@ private fun ChannelListView(
|
|||
channelSelections[index] = it
|
||||
}
|
||||
},
|
||||
isDefaultPSK = isDefaultPSK
|
||||
)
|
||||
}
|
||||
OutlinedButton(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue