Alias strings R to Res (#3619)

This commit is contained in:
Phil Oliver 2025-11-04 22:32:42 -05:00 committed by GitHub
parent a687328f08
commit 0833a6767e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
153 changed files with 1403 additions and 1350 deletions

View file

@ -45,12 +45,12 @@ import com.geeksville.mesh.ui.MainScreen
import dagger.hilt.android.AndroidEntryPoint
import org.meshtastic.core.datastore.UiPreferencesDataSource
import org.meshtastic.core.navigation.DEEP_LINK_BASE_URI
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.theme.AppTheme
import org.meshtastic.core.ui.theme.MODE_DYNAMIC
import org.meshtastic.feature.intro.AppIntroductionScreen
import timber.log.Timber
import javax.inject.Inject
import org.meshtastic.core.strings.R as Res
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@ -119,13 +119,13 @@ class MainActivity : AppCompatActivity() {
Timber.d("App link data is a channel set")
model.requestChannelUrl(
url = it,
onFailure = { Toast.makeText(this, R.string.channel_invalid, Toast.LENGTH_SHORT).show() },
onFailure = { Toast.makeText(this, Res.string.channel_invalid, Toast.LENGTH_SHORT).show() },
)
} else if (it.path?.startsWith("/v/") == true || it.path?.startsWith("/V/") == true) {
Timber.d("App link data is a shared contact")
model.setSharedContactRequested(
url = it,
onFailure = { Toast.makeText(this, R.string.contact_invalid, Toast.LENGTH_SHORT).show() },
onFailure = { Toast.makeText(this, Res.string.contact_invalid, Toast.LENGTH_SHORT).show() },
)
} else {
Timber.d("App link data is not a channel set")

View file

@ -51,10 +51,10 @@ import org.meshtastic.core.datastore.RecentAddressesDataSource
import org.meshtastic.core.datastore.model.RecentAddress
import org.meshtastic.core.model.util.anonymize
import org.meshtastic.core.service.ServiceRepository
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.viewmodel.stateInWhileSubscribed
import timber.log.Timber
import javax.inject.Inject
import org.meshtastic.core.strings.R as Res
/**
* A sealed class is used here to represent the different types of devices that can be displayed in the list. This is
@ -135,7 +135,8 @@ constructor(
val idBytes = txtRecords["id"]
val shortName =
shortNameBytes?.let { String(it, Charsets.UTF_8) } ?: context.getString(R.string.meshtastic)
shortNameBytes?.let { String(it, Charsets.UTF_8) }
?: context.getString(Res.string.meshtastic)
val deviceId = idBytes?.let { String(it, Charsets.UTF_8) }?.replace("!", "")
var displayName = recentMap[address] ?: shortName
if (deviceId != null && !displayName.split("_").none { it == deviceId }) {
@ -282,10 +283,10 @@ constructor(
if (state != BluetoothDevice.BOND_BONDING) {
Timber.d("Bonding completed, state=$state")
if (state == BluetoothDevice.BOND_BONDED) {
setErrorText(context.getString(R.string.pairing_completed))
setErrorText(context.getString(Res.string.pairing_completed))
changeDeviceAddress("x${device.address}")
} else {
setErrorText(context.getString(R.string.pairing_failed_try_again))
setErrorText(context.getString(Res.string.pairing_failed_try_again))
}
}
}

View file

@ -51,7 +51,6 @@ import org.meshtastic.core.model.util.toChannelSet
import org.meshtastic.core.service.IMeshService
import org.meshtastic.core.service.MeshServiceNotifications
import org.meshtastic.core.service.ServiceRepository
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.toSharedContact
import org.meshtastic.core.ui.viewmodel.stateInWhileSubscribed
import org.meshtastic.proto.AdminProtos
@ -59,6 +58,7 @@ import org.meshtastic.proto.AppOnlyProtos
import org.meshtastic.proto.MeshProtos
import timber.log.Timber
import javax.inject.Inject
import org.meshtastic.core.strings.R as Res
// Given a human name, strip out the first letter of the first three words and return that as the
// initials for
@ -178,7 +178,7 @@ constructor(
.filterNotNull()
.onEach {
showAlert(
title = app.getString(R.string.client_notification),
title = app.getString(Res.string.client_notification),
message = it,
onConfirm = { serviceRepository.clearErrorMessage() },
dismissable = false,

View file

@ -44,7 +44,6 @@ import org.meshtastic.core.navigation.DEEP_LINK_BASE_URI
import org.meshtastic.core.navigation.NodeDetailRoutes
import org.meshtastic.core.navigation.NodesRoutes
import org.meshtastic.core.navigation.Route
import org.meshtastic.core.strings.R
import org.meshtastic.feature.map.node.NodeMapScreen
import org.meshtastic.feature.map.node.NodeMapViewModel
import org.meshtastic.feature.node.detail.NodeDetailScreen
@ -58,6 +57,7 @@ import org.meshtastic.feature.node.metrics.PositionLogScreen
import org.meshtastic.feature.node.metrics.PowerMetricsScreen
import org.meshtastic.feature.node.metrics.SignalMetricsScreen
import org.meshtastic.feature.node.metrics.TracerouteLogScreen
import org.meshtastic.core.strings.R as Res
fun NavGraphBuilder.nodesGraph(navController: NavHostController) {
navigation<NodesRoutes.NodesGraph>(startDestination = NodesRoutes.Nodes) {
@ -204,49 +204,49 @@ enum class NodeDetailRoute(
val screenComposable: @Composable (metricsViewModel: MetricsViewModel, onNavigateUp: () -> Unit) -> Unit,
) {
DEVICE(
R.string.device,
Res.string.device,
NodeDetailRoutes.DeviceMetrics,
Icons.Default.Router,
{ metricsVM, onNavigateUp -> DeviceMetricsScreen(metricsVM, onNavigateUp) },
),
POSITION_LOG(
R.string.position_log,
Res.string.position_log,
NodeDetailRoutes.PositionLog,
Icons.Default.LocationOn,
{ metricsVM, onNavigateUp -> PositionLogScreen(metricsVM, onNavigateUp) },
),
ENVIRONMENT(
R.string.environment,
Res.string.environment,
NodeDetailRoutes.EnvironmentMetrics,
Icons.Default.LightMode,
{ metricsVM, onNavigateUp -> EnvironmentMetricsScreen(metricsVM, onNavigateUp) },
),
SIGNAL(
R.string.signal,
Res.string.signal,
NodeDetailRoutes.SignalMetrics,
Icons.Default.CellTower,
{ metricsVM, onNavigateUp -> SignalMetricsScreen(metricsVM, onNavigateUp) },
),
TRACEROUTE(
R.string.traceroute,
Res.string.traceroute,
NodeDetailRoutes.TracerouteLog,
Icons.Default.PermScanWifi,
{ metricsVM, onNavigateUp -> TracerouteLogScreen(viewModel = metricsVM, onNavigateUp = onNavigateUp) },
),
POWER(
R.string.power,
Res.string.power,
NodeDetailRoutes.PowerMetrics,
Icons.Default.Power,
{ metricsVM, onNavigateUp -> PowerMetricsScreen(metricsVM, onNavigateUp) },
),
HOST(
R.string.host,
Res.string.host,
NodeDetailRoutes.HostMetricsLog,
Icons.Default.Memory,
{ metricsVM, onNavigateUp -> HostMetricsLogScreen(metricsVM, onNavigateUp) },
),
PAX(
R.string.pax,
Res.string.pax,
NodeDetailRoutes.PaxMetrics,
Icons.Default.People,
{ metricsVM, onNavigateUp -> PaxMetricsScreen(metricsVM, onNavigateUp) },

View file

@ -85,7 +85,6 @@ import org.meshtastic.core.service.MeshServiceNotifications
import org.meshtastic.core.service.SERVICE_NOTIFY_ID
import org.meshtastic.core.service.ServiceAction
import org.meshtastic.core.service.ServiceRepository
import org.meshtastic.core.strings.R
import org.meshtastic.proto.AdminProtos
import org.meshtastic.proto.AppOnlyProtos
import org.meshtastic.proto.ChannelProtos
@ -114,6 +113,7 @@ import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
import kotlin.math.absoluteValue
import org.meshtastic.core.strings.R as Res
/**
* Handles all the communication with android apps. Also keeps an internal model of the network state.
@ -224,7 +224,7 @@ class MeshService : Service() {
private fun getSenderName(packet: DataPacket?): String {
val name = nodeDBbyID[packet?.from]?.user?.longName
return name ?: getString(R.string.unknown_username)
return name ?: getString(Res.string.unknown_username)
}
/** start our location requests (if they weren't already running) */
@ -269,7 +269,7 @@ class MeshService : Service() {
serviceNotifications.showAlertNotification(
contactKey,
getSenderName(dataPacket),
dataPacket.alert ?: getString(R.string.critical_alert),
dataPacket.alert ?: getString(Res.string.critical_alert),
)
}
@ -278,7 +278,7 @@ class MeshService : Service() {
when (dataPacket.dataType) {
Portnums.PortNum.TEXT_MESSAGE_APP_VALUE -> dataPacket.text!!
Portnums.PortNum.WAYPOINT_APP_VALUE -> {
getString(R.string.waypoint_received, dataPacket.waypoint!!.name)
getString(Res.string.waypoint_received, dataPacket.waypoint!!.name)
}
else -> return
@ -786,7 +786,7 @@ class MeshService : Service() {
val u = MeshProtos.Routing.parseFrom(data.payload)
if (u.errorReason == MeshProtos.Routing.Error.DUTY_CYCLE_LIMIT) {
serviceRepository.setErrorMessage(getString(R.string.error_duty_cycle))
serviceRepository.setErrorMessage(getString(Res.string.error_duty_cycle))
}
handleAckNak(data.requestId, fromId, u.errorReasonValue, dataPacket.relayNode)
@ -1317,10 +1317,10 @@ class MeshService : Service() {
private fun updateServiceStatusNotification(telemetry: TelemetryProtos.Telemetry? = null): Notification {
val notificationSummary =
when (connectionStateHolder.getState()) {
ConnectionState.CONNECTED -> getString(R.string.connected_count).format(numOnlineNodes)
ConnectionState.CONNECTED -> getString(Res.string.connected_count).format(numOnlineNodes)
ConnectionState.DISCONNECTED -> getString(R.string.disconnected)
ConnectionState.DEVICE_SLEEP -> getString(R.string.device_sleeping)
ConnectionState.DISCONNECTED -> getString(Res.string.disconnected)
ConnectionState.DEVICE_SLEEP -> getString(Res.string.device_sleeping)
}
return serviceNotifications.updateServiceStateNotification(
summaryString = notificationSummary,

View file

@ -43,11 +43,11 @@ import org.meshtastic.core.model.util.formatUptime
import org.meshtastic.core.navigation.DEEP_LINK_BASE_URI
import org.meshtastic.core.service.MeshServiceNotifications
import org.meshtastic.core.service.SERVICE_NOTIFY_ID
import org.meshtastic.core.strings.R
import org.meshtastic.proto.MeshProtos
import org.meshtastic.proto.TelemetryProtos
import org.meshtastic.proto.TelemetryProtos.LocalStats
import javax.inject.Inject
import org.meshtastic.core.strings.R as Res
/**
* Manages the creation and display of all app notifications.
@ -79,54 +79,58 @@ class MeshServiceNotificationsImpl @Inject constructor(@ApplicationContext priva
object ServiceState :
NotificationType(
"my_service",
R.string.meshtastic_service_notifications,
Res.string.meshtastic_service_notifications,
NotificationManager.IMPORTANCE_MIN,
)
object DirectMessage :
NotificationType(
"my_messages",
R.string.meshtastic_messages_notifications,
Res.string.meshtastic_messages_notifications,
NotificationManager.IMPORTANCE_HIGH,
)
object BroadcastMessage :
NotificationType(
"my_broadcasts",
R.string.meshtastic_broadcast_notifications,
Res.string.meshtastic_broadcast_notifications,
NotificationManager.IMPORTANCE_DEFAULT,
)
object Alert :
NotificationType(
"my_alerts",
R.string.meshtastic_alerts_notifications,
Res.string.meshtastic_alerts_notifications,
NotificationManager.IMPORTANCE_HIGH,
)
object NewNode :
NotificationType(
"new_nodes",
R.string.meshtastic_new_nodes_notifications,
Res.string.meshtastic_new_nodes_notifications,
NotificationManager.IMPORTANCE_DEFAULT,
)
object LowBatteryLocal :
NotificationType(
"low_battery",
R.string.meshtastic_low_battery_notifications,
Res.string.meshtastic_low_battery_notifications,
NotificationManager.IMPORTANCE_DEFAULT,
)
object LowBatteryRemote :
NotificationType(
"low_battery_remote",
R.string.meshtastic_low_battery_temporary_remote_notifications,
Res.string.meshtastic_low_battery_temporary_remote_notifications,
NotificationManager.IMPORTANCE_DEFAULT,
)
object Client :
NotificationType("client_notifications", R.string.client_notification, NotificationManager.IMPORTANCE_HIGH)
NotificationType(
"client_notifications",
Res.string.client_notification,
NotificationManager.IMPORTANCE_HIGH,
)
companion object {
// A list of all types for easy initialization.
@ -241,7 +245,7 @@ class MeshServiceNotificationsImpl @Inject constructor(@ApplicationContext priva
null
}
cachedMessage = message ?: cachedMessage ?: context.getString(R.string.no_local_stats)
cachedMessage = message ?: cachedMessage ?: context.getString(Res.string.no_local_stats)
val notification =
createServiceStateNotification(
@ -277,7 +281,7 @@ class MeshServiceNotificationsImpl @Inject constructor(@ApplicationContext priva
override fun showClientNotification(clientNotification: MeshProtos.ClientNotification) {
val notification =
createClientNotification(context.getString(R.string.client_notification), clientNotification.message)
createClientNotification(context.getString(Res.string.client_notification), clientNotification.message)
notificationManager.notify(clientNotification.toString().hashCode(), notification)
}
@ -357,7 +361,7 @@ class MeshServiceNotificationsImpl @Inject constructor(@ApplicationContext priva
}
private fun createNewNodeSeenNotification(name: String, message: String?): Notification {
val title = context.getString(R.string.new_node_seen).format(name)
val title = context.getString(Res.string.new_node_seen).format(name)
val builder =
commonBuilder(NotificationType.NewNode)
.setCategory(Notification.CATEGORY_STATUS)
@ -375,9 +379,9 @@ class MeshServiceNotificationsImpl @Inject constructor(@ApplicationContext priva
private fun createLowBatteryNotification(node: NodeEntity, isRemote: Boolean): Notification {
val type = if (isRemote) NotificationType.LowBatteryRemote else NotificationType.LowBatteryLocal
val title = context.getString(R.string.low_battery_title).format(node.shortName)
val title = context.getString(Res.string.low_battery_title).format(node.shortName)
val message =
context.getString(R.string.low_battery_message).format(node.longName, node.deviceMetrics.batteryLevel)
context.getString(Res.string.low_battery_message).format(node.longName, node.deviceMetrics.batteryLevel)
return commonBuilder(type)
.setCategory(Notification.CATEGORY_STATUS)
@ -427,7 +431,7 @@ class MeshServiceNotificationsImpl @Inject constructor(@ApplicationContext priva
}
private fun createReplyAction(contactKey: String): NotificationCompat.Action {
val replyLabel = context.getString(R.string.reply)
val replyLabel = context.getString(Res.string.reply)
val remoteInput = RemoteInput.Builder(KEY_TEXT_REPLY).setLabel(replyLabel).build()
val replyIntent =

View file

@ -108,7 +108,6 @@ import org.meshtastic.core.navigation.NodesRoutes
import org.meshtastic.core.navigation.Route
import org.meshtastic.core.navigation.SettingsRoutes
import org.meshtastic.core.service.ConnectionState
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.MultipleChoiceAlertDialog
import org.meshtastic.core.ui.component.SimpleAlertDialog
import org.meshtastic.core.ui.icon.Conversations
@ -123,13 +122,14 @@ import org.meshtastic.core.ui.theme.StatusColors.StatusGreen
import org.meshtastic.feature.node.metrics.annotateTraceroute
import org.meshtastic.proto.MeshProtos
import timber.log.Timber
import org.meshtastic.core.strings.R as Res
enum class TopLevelDestination(@StringRes val label: Int, val icon: ImageVector, val route: Route) {
Conversations(R.string.conversations, MeshtasticIcons.Conversations, ContactsRoutes.ContactsGraph),
Nodes(R.string.nodes, MeshtasticIcons.Nodes, NodesRoutes.NodesGraph),
Map(R.string.map, MeshtasticIcons.Map, MapRoutes.Map),
Settings(R.string.bottom_nav_settings, MeshtasticIcons.Settings, SettingsRoutes.SettingsGraph()),
Connections(R.string.connections, Icons.Rounded.Wifi, ConnectionsRoutes.ConnectionsGraph),
Conversations(Res.string.conversations, MeshtasticIcons.Conversations, ContactsRoutes.ContactsGraph),
Nodes(Res.string.nodes, MeshtasticIcons.Nodes, NodesRoutes.NodesGraph),
Map(Res.string.map, MeshtasticIcons.Map, MapRoutes.Map),
Settings(Res.string.bottom_nav_settings, MeshtasticIcons.Settings, SettingsRoutes.SettingsGraph()),
Connections(Res.string.connections, Icons.Rounded.Wifi, ConnectionsRoutes.ConnectionsGraph),
;
companion object {
@ -195,13 +195,13 @@ fun MainScreen(uIViewModel: UIViewModel = hiltViewModel(), scanModel: BTScanMode
var message = notification.message
val compromisedKeys =
if (notification.hasLowEntropyKey() || notification.hasDuplicatedPublicKey()) {
message = stringResource(R.string.compromised_keys)
message = stringResource(Res.string.compromised_keys)
true
} else {
false
}
SimpleAlertDialog(
title = R.string.client_notification,
title = Res.string.client_notification,
text = { Text(text = message) },
onConfirm = {
if (compromisedKeys) {
@ -216,13 +216,13 @@ fun MainScreen(uIViewModel: UIViewModel = hiltViewModel(), scanModel: BTScanMode
val traceRouteResponse by uIViewModel.tracerouteResponse.observeAsState()
traceRouteResponse?.let { response ->
SimpleAlertDialog(
title = R.string.traceroute,
title = Res.string.traceroute,
text = {
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
Text(text = annotateTraceroute(response))
}
},
dismissText = stringResource(R.string.okay),
dismissText = stringResource(Res.string.okay),
onDismiss = { uIViewModel.clearTracerouteResponse() },
)
}
@ -278,9 +278,10 @@ fun MainScreen(uIViewModel: UIViewModel = hiltViewModel(), scanModel: BTScanMode
Text(
if (isConnectionsRoute) {
when (connectionState) {
ConnectionState.CONNECTED -> stringResource(R.string.connected)
ConnectionState.DEVICE_SLEEP -> stringResource(R.string.device_sleeping)
ConnectionState.DISCONNECTED -> stringResource(R.string.disconnected)
ConnectionState.CONNECTED -> stringResource(Res.string.connected)
ConnectionState.DEVICE_SLEEP ->
stringResource(Res.string.device_sleeping)
ConnectionState.DISCONNECTED -> stringResource(Res.string.disconnected)
}
} else {
stringResource(destination.label)
@ -423,8 +424,8 @@ private fun VersionChecks(viewModel: UIViewModel) {
val isOld = info.minAppVersion > BuildConfig.VERSION_CODE && BuildConfig.DEBUG.not()
if (isOld) {
viewModel.showAlert(
resources.getString(R.string.app_too_old),
resources.getString(R.string.must_update),
resources.getString(Res.string.app_too_old),
resources.getString(Res.string.must_update),
dismissable = false,
onConfirm = {
val service = viewModel.meshService ?: return@showAlert
@ -435,8 +436,8 @@ private fun VersionChecks(viewModel: UIViewModel) {
myFirmwareVersion?.let {
val curVer = DeviceVersion(it)
if (curVer < MeshService.absoluteMinDeviceVersion) {
val title = resources.getString(R.string.firmware_too_old)
val message = resources.getString(R.string.firmware_old)
val title = resources.getString(Res.string.firmware_too_old)
val message = resources.getString(Res.string.firmware_old)
viewModel.showAlert(
title = title,
html = message,
@ -447,9 +448,9 @@ private fun VersionChecks(viewModel: UIViewModel) {
},
)
} else if (curVer < MeshService.minDeviceVersion) {
val title = resources.getString(R.string.should_update_firmware)
val title = resources.getString(Res.string.should_update_firmware)
val message =
resources.getString(R.string.should_update, latestStableFirmwareRelease.asString)
resources.getString(Res.string.should_update, latestStableFirmwareRelease.asString)
viewModel.showAlert(title = title, message = message, dismissable = false, onConfirm = {})
}
}

View file

@ -65,7 +65,6 @@ import kotlinx.coroutines.delay
import org.meshtastic.core.navigation.Route
import org.meshtastic.core.navigation.SettingsRoutes
import org.meshtastic.core.service.ConnectionState
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.ListItem
import org.meshtastic.core.ui.component.MainAppBar
import org.meshtastic.core.ui.component.TitledCard
@ -74,6 +73,7 @@ import org.meshtastic.feature.settings.navigation.getNavRouteFrom
import org.meshtastic.feature.settings.radio.RadioConfigViewModel
import org.meshtastic.feature.settings.radio.component.PacketResponseStateDialog
import org.meshtastic.proto.ConfigProtos
import org.meshtastic.core.strings.R as Res
fun String?.isIPAddress(): Boolean = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
@Suppress("DEPRECATION")
@ -153,18 +153,18 @@ fun ConnectionsScreen(
LaunchedEffect(connectionState, regionUnset) {
when (connectionState) {
ConnectionState.CONNECTED -> {
if (regionUnset) R.string.must_set_region else R.string.connected
if (regionUnset) Res.string.must_set_region else Res.string.connected
}
ConnectionState.DISCONNECTED -> R.string.not_connected
ConnectionState.DEVICE_SLEEP -> R.string.connected_sleeping
ConnectionState.DISCONNECTED -> Res.string.not_connected
ConnectionState.DEVICE_SLEEP -> Res.string.connected_sleeping
}.let { scanModel.setErrorText(context.getString(it)) }
}
Scaffold(
topBar = {
MainAppBar(
title = stringResource(R.string.connections),
title = stringResource(Res.string.connections),
ourNode = ourNode,
showNodeChip = ourNode != null && connectionState.isConnected(),
canNavigateUp = false,
@ -190,7 +190,7 @@ fun ConnectionsScreen(
) {
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
ourNode?.let { node ->
TitledCard(title = stringResource(R.string.connected_device)) {
TitledCard(title = stringResource(Res.string.connected_device)) {
CurrentlyConnectedInfo(
node = node,
onNavigateToNodeDetails = onNavigateToNodeDetails,
@ -203,7 +203,7 @@ fun ConnectionsScreen(
TitledCard(title = null) {
ListItem(
leadingIcon = Icons.Rounded.Language,
text = stringResource(R.string.set_your_region),
text = stringResource(Res.string.set_your_region),
) {
isWaiting = true
radioConfigViewModel.setResponseStateLoading(ConfigRoute.LORA)
@ -272,7 +272,7 @@ fun ConnectionsScreen(
bondedBleDevices.none { it is DeviceListEntry.Ble && it.bonded }
if (showWarningNotPaired) {
Text(
text = stringResource(R.string.warning_not_paired),
text = stringResource(Res.string.warning_not_paired),
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(horizontal = 16.dp),

View file

@ -52,8 +52,8 @@ import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.MultiplePermissionsState
import com.google.accompanist.permissions.rememberMultiplePermissionsState
import org.meshtastic.core.service.ConnectionState
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.TitledCard
import org.meshtastic.core.strings.R as Res
/**
* Composable that displays a list of Bluetooth Low Energy (BLE) devices and allows scanning. It handles Bluetooth
@ -118,12 +118,12 @@ fun BLEDevices(
val context = LocalContext.current
EmptyStateContent(
imageVector = Icons.Rounded.BluetoothDisabled,
text = stringResource(R.string.bluetooth_disabled),
text = stringResource(Res.string.bluetooth_disabled),
actionButton = {
val intent = Intent(ACTION_BLUETOOTH_SETTINGS)
if (intent.resolveActivity(context.packageManager) != null) {
Button(onClick = { settingsLauncher.launch(intent) }) {
Text(text = stringResource(R.string.open_settings))
Text(text = stringResource(Res.string.open_settings))
}
}
},
@ -142,9 +142,9 @@ fun BLEDevices(
Row(modifier = Modifier.alpha(if (isScanning) 0f else 1f)) {
Icon(
imageVector = Icons.Rounded.Search,
contentDescription = stringResource(R.string.scan),
contentDescription = stringResource(Res.string.scan),
)
Text(stringResource(R.string.scan))
Text(stringResource(Res.string.scan))
}
if (isScanning) {
@ -159,22 +159,22 @@ fun BLEDevices(
imageVector = Icons.Rounded.BluetoothDisabled,
text =
if (isScanning) {
stringResource(R.string.scanning_bluetooth)
stringResource(Res.string.scanning_bluetooth)
} else {
stringResource(R.string.no_ble_devices)
stringResource(Res.string.no_ble_devices)
},
actionButton = scanButton,
)
} else {
bondedDevices.Section(
title = stringResource(R.string.bluetooth_paired_devices),
title = stringResource(Res.string.bluetooth_paired_devices),
connectionState = connectionState,
selectedDevice = selectedDevice,
onSelect = scanModel::onSelected,
)
availableDevices.Section(
title = stringResource(R.string.bluetooth_available_devices),
title = stringResource(Res.string.bluetooth_available_devices),
connectionState = connectionState,
selectedDevice = selectedDevice,
onSelect = scanModel::onSelected,
@ -189,13 +189,13 @@ fun BLEDevices(
EmptyStateContent(
text =
if (permissionsState.shouldShowRationale) {
stringResource(R.string.permission_missing)
stringResource(Res.string.permission_missing)
} else {
stringResource(R.string.permission_missing_31)
stringResource(Res.string.permission_missing_31)
},
actionButton = {
Button(onClick = { checkPermissionsAndScan(permissionsState, scanModel, bluetoothEnabled) }) {
Text(text = stringResource(R.string.grant_permissions))
Text(text = stringResource(Res.string.grant_permissions))
}
},
)

View file

@ -34,8 +34,8 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.ui.connections.DeviceType
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.theme.AppTheme
import org.meshtastic.core.strings.R as Res
@Suppress("LambdaParameterEventTrailing")
@Composable
@ -59,9 +59,9 @@ fun ConnectionsSegmentedBar(
}
private enum class Item(val imageVector: ImageVector, @StringRes val textRes: Int, val deviceType: DeviceType) {
BLUETOOTH(imageVector = Icons.Rounded.Bluetooth, textRes = R.string.bluetooth, deviceType = DeviceType.BLE),
NETWORK(imageVector = Icons.Rounded.Wifi, textRes = R.string.network, deviceType = DeviceType.TCP),
SERIAL(imageVector = Icons.Rounded.Usb, textRes = R.string.serial, deviceType = DeviceType.USB),
BLUETOOTH(imageVector = Icons.Rounded.Bluetooth, textRes = Res.string.bluetooth, deviceType = DeviceType.BLE),
NETWORK(imageVector = Icons.Rounded.Wifi, textRes = Res.string.network, deviceType = DeviceType.TCP),
SERIAL(imageVector = Icons.Rounded.Usb, textRes = Res.string.serial, deviceType = DeviceType.USB),
}
@Preview(showBackground = true)

View file

@ -37,7 +37,6 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.MaterialBatteryInfo
import org.meshtastic.core.ui.component.NodeChip
import org.meshtastic.core.ui.theme.AppTheme
@ -45,6 +44,7 @@ import org.meshtastic.core.ui.theme.StatusColors.StatusRed
import org.meshtastic.proto.MeshProtos
import org.meshtastic.proto.PaxcountProtos
import org.meshtastic.proto.TelemetryProtos
import org.meshtastic.core.strings.R as Res
/** Converts Bluetooth RSSI to a 0-4 bar signal strength level. */
@Composable
@ -75,7 +75,7 @@ fun CurrentlyConnectedInfo(
node.metadata?.firmwareVersion?.let { firmwareVersion ->
Text(
text = stringResource(R.string.firmware_version, firmwareVersion),
text = stringResource(Res.string.firmware_version, firmwareVersion),
style = MaterialTheme.typography.bodySmall,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
@ -94,7 +94,7 @@ fun CurrentlyConnectedInfo(
),
onClick = onClickDisconnect,
) {
Text(stringResource(R.string.disconnect))
Text(stringResource(Res.string.disconnect))
}
}
}

View file

@ -35,7 +35,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import com.geeksville.mesh.model.DeviceListEntry
import org.meshtastic.core.strings.R
import org.meshtastic.core.strings.R as Res
@Suppress("LongMethod", "CyclomaticComplexMethod")
@Composable
@ -55,10 +55,10 @@ fun DeviceListItem(connected: Boolean, device: DeviceListEntry, onSelect: () ->
val contentDescription =
when (device) {
is DeviceListEntry.Ble -> stringResource(R.string.bluetooth)
is DeviceListEntry.Usb -> stringResource(R.string.serial)
is DeviceListEntry.Tcp -> stringResource(R.string.network)
is DeviceListEntry.Mock -> stringResource(R.string.add)
is DeviceListEntry.Ble -> stringResource(Res.string.bluetooth)
is DeviceListEntry.Usb -> stringResource(Res.string.serial)
is DeviceListEntry.Tcp -> stringResource(Res.string.network)
is DeviceListEntry.Mock -> stringResource(Res.string.add)
}
val useSelectable = modifier == Modifier

View file

@ -57,9 +57,9 @@ import com.geeksville.mesh.repository.network.NetworkRepository
import com.geeksville.mesh.ui.connections.isIPAddress
import kotlinx.coroutines.launch
import org.meshtastic.core.service.ConnectionState
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.TitledCard
import org.meshtastic.core.ui.theme.AppTheme
import org.meshtastic.core.strings.R as Res
@OptIn(ExperimentalMaterial3Api::class)
@Suppress("MagicNumber", "LongMethod")
@ -102,8 +102,11 @@ fun NetworkDevices(
Column(verticalArrangement = Arrangement.spacedBy(16.dp), horizontalAlignment = Alignment.CenterHorizontally) {
val addButton: @Composable () -> Unit = {
Button(onClick = { showSearchDialog = true }) {
Icon(imageVector = Icons.Rounded.Add, contentDescription = stringResource(R.string.add_network_device))
Text(stringResource(R.string.add_network_device))
Icon(
imageVector = Icons.Rounded.Add,
contentDescription = stringResource(Res.string.add_network_device),
)
Text(stringResource(Res.string.add_network_device))
}
}
@ -111,14 +114,14 @@ fun NetworkDevices(
discoveredNetworkDevices.isEmpty() && recentNetworkDevices.isEmpty() -> {
EmptyStateContent(
imageVector = Icons.Rounded.Wifi,
text = stringResource(R.string.no_network_devices),
text = stringResource(Res.string.no_network_devices),
actionButton = addButton,
)
}
else -> {
if (recentNetworkDevices.isNotEmpty()) {
TitledCard(title = stringResource(R.string.recent_network_devices)) {
TitledCard(title = stringResource(Res.string.recent_network_devices)) {
recentNetworkDevices.forEach { device ->
DeviceListItem(
connected =
@ -140,7 +143,7 @@ fun NetworkDevices(
}
if (discoveredNetworkDevices.isNotEmpty()) {
TitledCard(title = stringResource(R.string.discovered_network_devices)) {
TitledCard(title = stringResource(Res.string.discovered_network_devices)) {
discoveredNetworkDevices.forEach { device ->
DeviceListItem(
connected =
@ -179,7 +182,7 @@ private fun AddDeviceDialog(
state = ipState,
labelPosition = TextFieldLabelPosition.Above(),
lineLimits = TextFieldLineLimits.SingleLine,
label = { Text(stringResource(R.string.ip_address)) },
label = { Text(stringResource(Res.string.ip_address)) },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal, imeAction = ImeAction.Next),
modifier = Modifier.weight(.7f),
)
@ -189,7 +192,7 @@ private fun AddDeviceDialog(
labelPosition = TextFieldLabelPosition.Above(),
placeholder = { Text(NetworkRepository.SERVICE_PORT.toString()) },
lineLimits = TextFieldLineLimits.SingleLine,
label = { Text(stringResource(R.string.ip_port)) },
label = { Text(stringResource(Res.string.ip_port)) },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal, imeAction = ImeAction.Done),
modifier = Modifier.weight(.3f),
)
@ -197,7 +200,7 @@ private fun AddDeviceDialog(
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
Button(modifier = Modifier.weight(1f), onClick = { onHideDialog() }) {
Text(stringResource(R.string.cancel))
Text(stringResource(Res.string.cancel))
}
Button(
@ -226,7 +229,7 @@ private fun AddDeviceDialog(
}
},
) {
Text(stringResource(R.string.add_network_device))
Text(stringResource(Res.string.add_network_device))
}
}
}
@ -241,8 +244,8 @@ private fun ConfirmDeleteDialog(
) {
AlertDialog(
onDismissRequest = onHideDialog,
title = { Text(stringResource(R.string.delete)) },
text = { Text(stringResource(R.string.confirm_delete_node)) },
title = { Text(stringResource(Res.string.delete)) },
text = { Text(stringResource(Res.string.confirm_delete_node)) },
confirmButton = {
Button(
onClick = {
@ -250,10 +253,10 @@ private fun ConfirmDeleteDialog(
onHideDialog()
},
) {
Text(stringResource(R.string.delete))
Text(stringResource(Res.string.delete))
}
},
dismissButton = { Button(onClick = { onHideDialog() }) { Text(stringResource(R.string.cancel)) } },
dismissButton = { Button(onClick = { onHideDialog() }) { Text(stringResource(Res.string.cancel)) } },
)
}

View file

@ -26,9 +26,9 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark
import com.geeksville.mesh.model.BTScanModel
import com.geeksville.mesh.model.DeviceListEntry
import org.meshtastic.core.service.ConnectionState
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.TitledCard
import org.meshtastic.core.ui.theme.AppTheme
import org.meshtastic.core.strings.R as Res
@Composable
fun UsbDevices(
@ -54,7 +54,7 @@ private fun UsbDevices(
) {
when {
usbDevices.isEmpty() ->
EmptyStateContent(imageVector = Icons.Rounded.UsbOff, text = stringResource(R.string.no_usb_devices))
EmptyStateContent(imageVector = Icons.Rounded.UsbOff, text = stringResource(Res.string.no_usb_devices))
else ->
TitledCard(title = null) {

View file

@ -53,10 +53,10 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.model.Contact
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.SecurityIcon
import org.meshtastic.core.ui.theme.AppTheme
import org.meshtastic.proto.AppOnlyProtos
import org.meshtastic.core.strings.R as Res
@Suppress("LongMethod")
@Composable
@ -197,10 +197,10 @@ private fun ContactItemPreview() {
val sampleContact =
Contact(
contactKey = "0^all",
shortName = stringResource(R.string.some_username),
longName = stringResource(R.string.unknown_username),
shortName = stringResource(Res.string.some_username),
longName = stringResource(Res.string.unknown_username),
lastMessageTime = "Mon",
lastMessageText = stringResource(R.string.sample_message),
lastMessageText = stringResource(Res.string.sample_message),
unreadCount = 2,
messageCount = 10,
isMuted = true,

View file

@ -64,10 +64,10 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.model.Contact
import org.meshtastic.core.database.entity.ContactSettings
import org.meshtastic.core.model.util.formatMuteRemainingTime
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.MainAppBar
import org.meshtastic.proto.AppOnlyProtos
import java.util.concurrent.TimeUnit
import org.meshtastic.core.strings.R as Res
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Suppress("LongMethod")
@ -143,7 +143,7 @@ fun ContactsScreen(
Scaffold(
topBar = {
MainAppBar(
title = stringResource(R.string.conversations),
title = stringResource(Res.string.conversations),
ourNode = ourNode,
showNodeChip = ourNode != null && connectionState.isConnected(),
canNavigateUp = false,
@ -232,10 +232,10 @@ fun MuteNotificationsDialog(
// Options for mute duration
val muteOptions = remember {
listOf(
R.string.unmute to 0L,
R.string.mute_8_hours to TimeUnit.HOURS.toMillis(8),
R.string.mute_1_week to TimeUnit.DAYS.toMillis(7),
R.string.mute_always to Long.MAX_VALUE,
Res.string.unmute to 0L,
Res.string.mute_8_hours to TimeUnit.HOURS.toMillis(8),
Res.string.mute_1_week to TimeUnit.DAYS.toMillis(7),
Res.string.mute_always to Long.MAX_VALUE,
)
}
@ -244,7 +244,7 @@ fun MuteNotificationsDialog(
AlertDialog(
onDismissRequest = onDismiss, // Dismiss the dialog when clicked outside
title = { Text(text = stringResource(R.string.mute_notifications)) },
title = { Text(text = stringResource(Res.string.mute_notifications)) },
text = {
Column {
// Show current mute status
@ -258,19 +258,20 @@ fun MuteNotificationsDialog(
if (remaining > 0) {
val (days, hours) = formatMuteRemainingTime(remaining)
if (days >= 1) {
stringResource(R.string.mute_status_muted_for_days, days, hours)
stringResource(Res.string.mute_status_muted_for_days, days, hours)
} else {
stringResource(R.string.mute_status_muted_for_hours, hours)
stringResource(Res.string.mute_status_muted_for_hours, hours)
}
} else {
stringResource(R.string.mute_status_unmuted)
stringResource(Res.string.mute_status_unmuted)
}
}
settings.muteUntil == Long.MAX_VALUE -> stringResource(R.string.mute_status_always)
else -> stringResource(R.string.mute_status_unmuted)
settings.muteUntil == Long.MAX_VALUE ->
stringResource(Res.string.mute_status_always)
else -> stringResource(Res.string.mute_status_unmuted)
}
Text(
text = stringResource(R.string.currently) + " " + statusText,
text = stringResource(Res.string.currently) + " " + statusText,
modifier = Modifier.padding(bottom = 8.dp),
)
}
@ -300,14 +301,14 @@ fun MuteNotificationsDialog(
onDismiss() // Dismiss the dialog after confirming
},
) {
Text(stringResource(R.string.okay))
Text(stringResource(Res.string.okay))
}
},
dismissButton = {
Button(
onClick = onDismiss, // Dismiss the dialog on cancel
) {
Text(stringResource(R.string.cancel))
Text(stringResource(Res.string.cancel))
}
},
)
@ -324,7 +325,7 @@ fun DeleteConfirmationDialog(
if (showDialog) {
val deleteMessage =
pluralStringResource(
id = R.plurals.delete_messages,
id = Res.plurals.delete_messages,
count = selectedCount,
formatArgs = arrayOf(selectedCount), // Pass the count as a format argument
)
@ -342,10 +343,10 @@ fun DeleteConfirmationDialog(
onDismiss() // Dismiss the dialog after confirming
},
) {
Text(stringResource(R.string.delete))
Text(stringResource(Res.string.delete))
}
},
dismissButton = { Button(onClick = onDismiss) { Text(stringResource(R.string.cancel)) } },
dismissButton = { Button(onClick = onDismiss) { Text(stringResource(Res.string.cancel)) } },
properties =
DialogProperties(
dismissOnClickOutside = true, // Allow dismissing by clicking outside
@ -369,7 +370,7 @@ fun SelectionToolbar(
title = { Text(text = "$selectedCount") },
navigationIcon = {
IconButton(onClick = onCloseSelection) {
Icon(Icons.Default.Close, contentDescription = stringResource(R.string.close_selection))
Icon(Icons.Default.Close, contentDescription = stringResource(Res.string.close_selection))
}
},
actions = {
@ -390,10 +391,10 @@ fun SelectionToolbar(
)
}
IconButton(onClick = onDeleteSelected) {
Icon(Icons.Default.Delete, contentDescription = stringResource(R.string.delete_selection))
Icon(Icons.Default.Delete, contentDescription = stringResource(Res.string.delete_selection))
}
IconButton(onClick = onSelectAll) {
Icon(Icons.Default.SelectAll, contentDescription = stringResource(R.string.select_all))
Icon(Icons.Default.SelectAll, contentDescription = stringResource(Res.string.select_all))
}
},
)

View file

@ -34,11 +34,11 @@ import org.meshtastic.core.model.DataPacket
import org.meshtastic.core.model.util.getChannel
import org.meshtastic.core.model.util.getShortDate
import org.meshtastic.core.service.ServiceRepository
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.viewmodel.stateInWhileSubscribed
import org.meshtastic.proto.channelSet
import javax.inject.Inject
import kotlin.collections.map
import org.meshtastic.core.strings.R as Res
@HiltViewModel
class ContactsViewModel
@ -87,7 +87,7 @@ constructor(
val shortName = user.shortName
val longName =
if (toBroadcast) {
channelSet.getChannel(data.channel)?.name ?: context.getString(R.string.channel_name)
channelSet.getChannel(data.channel)?.name ?: context.getString(Res.string.channel_name)
} else {
user.longName
}

View file

@ -101,7 +101,6 @@ import org.meshtastic.core.model.util.qrCode
import org.meshtastic.core.model.util.toChannelSet
import org.meshtastic.core.navigation.Route
import org.meshtastic.core.service.ConnectionState
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.AdaptiveTwoPane
import org.meshtastic.core.ui.component.ChannelSelection
import org.meshtastic.core.ui.component.MainAppBar
@ -117,6 +116,7 @@ import org.meshtastic.proto.ConfigProtos
import org.meshtastic.proto.channelSet
import org.meshtastic.proto.copy
import timber.log.Timber
import org.meshtastic.core.strings.R as Res
/**
* Composable screen for managing and sharing Meshtastic channels. Allows users to view, edit, and share channel
@ -185,7 +185,7 @@ fun ChannelScreen(
rememberLauncherForActivityResult(ScanContract()) { result ->
if (result.contents != null) {
viewModel.requestChannelUrl(result.contents.toUri()) {
Toast.makeText(context, R.string.channel_invalid, Toast.LENGTH_SHORT).show()
Toast.makeText(context, Res.string.channel_invalid, Toast.LENGTH_SHORT).show()
}
}
}
@ -223,7 +223,7 @@ fun ChannelScreen(
channelSet = channels // Throw away user edits
// Tell the user to try again
Toast.makeText(context, R.string.cant_change_no_radio, Toast.LENGTH_SHORT).show()
Toast.makeText(context, Res.string.cant_change_no_radio, Toast.LENGTH_SHORT).show()
}
}
@ -241,8 +241,8 @@ fun ChannelScreen(
channelSet = channels // throw away any edits
showResetDialog = false
},
title = { Text(text = stringResource(R.string.reset_to_defaults)) },
text = { Text(text = stringResource(R.string.are_you_sure_change_default)) },
title = { Text(text = stringResource(Res.string.reset_to_defaults)) },
text = { Text(text = stringResource(Res.string.are_you_sure_change_default)) },
confirmButton = {
TextButton(
onClick = {
@ -257,7 +257,7 @@ fun ChannelScreen(
showResetDialog = false
},
) {
Text(text = stringResource(R.string.apply))
Text(text = stringResource(Res.string.apply))
}
},
dismissButton = {
@ -267,7 +267,7 @@ fun ChannelScreen(
showResetDialog = false
},
) {
Text(text = stringResource(R.string.cancel))
Text(text = stringResource(Res.string.cancel))
}
},
)
@ -312,7 +312,7 @@ fun ChannelScreen(
onTrackShare = viewModel::trackShare,
onConfirm = {
viewModel.requestChannelUrl(it) {
Toast.makeText(context, R.string.channel_invalid, Toast.LENGTH_SHORT).show()
Toast.makeText(context, Res.string.channel_invalid, Toast.LENGTH_SHORT).show()
}
},
)
@ -320,13 +320,13 @@ fun ChannelScreen(
item {
SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth().padding(8.dp)) {
SegmentedButton(
label = { Text(text = stringResource(R.string.replace)) },
label = { Text(text = stringResource(Res.string.replace)) },
onClick = { shouldAddChannelsState = false },
selected = !shouldAddChannelsState,
shape = SegmentedButtonDefaults.itemShape(0, 2),
)
SegmentedButton(
label = { Text(text = stringResource(R.string.add)) },
label = { Text(text = stringResource(Res.string.add)) },
onClick = { shouldAddChannelsState = true },
selected = shouldAddChannelsState,
shape = SegmentedButtonDefaults.itemShape(1, 2),
@ -345,12 +345,12 @@ fun ChannelScreen(
item {
PreferenceFooter(
enabled = enabled,
negativeText = R.string.reset,
negativeText = Res.string.reset,
onNegativeClicked = {
focusManager.clearFocus()
showResetDialog = true
},
positiveText = R.string.scan,
positiveText = Res.string.scan,
onPositiveClicked = {
focusManager.clearFocus()
if (cameraPermissionState.status.isGranted) {
@ -400,11 +400,11 @@ private fun EditChannelUrl(
},
modifier = modifier.fillMaxWidth(),
enabled = enabled,
label = { Text(stringResource(R.string.url)) },
label = { Text(stringResource(Res.string.url)) },
isError = isError,
shape = RoundedCornerShape(8.dp),
trailingIcon = {
val label = stringResource(R.string.url)
val label = stringResource(Res.string.url)
val isUrlEqual = valueState == channelUrl
IconButton(
onClick = {
@ -440,9 +440,9 @@ private fun EditChannelUrl(
},
contentDescription =
when {
isError -> stringResource(R.string.copy)
!isUrlEqual -> stringResource(R.string.send)
else -> stringResource(R.string.copy)
isError -> stringResource(Res.string.copy)
!isUrlEqual -> stringResource(Res.string.send)
else -> stringResource(Res.string.copy)
},
tint =
if (isError) {
@ -470,7 +470,7 @@ private fun QrCodeImage(
painter =
channelSet.qrCode(shouldAddChannel)?.let { BitmapPainter(it.asImageBitmap()) }
?: painterResource(id = org.meshtastic.core.ui.R.drawable.qrcode),
contentDescription = stringResource(R.string.qr_code),
contentDescription = stringResource(Res.string.qr_code),
modifier = modifier,
contentScale = ContentScale.Inside,
alpha = if (enabled) 1.0f else 0.7f,
@ -518,7 +518,7 @@ private fun ChannelListView(
enabled = enabled,
colors = ButtonDefaults.outlinedButtonColors(contentColor = MaterialTheme.colorScheme.onSurface),
) {
Text(text = stringResource(R.string.edit))
Text(text = stringResource(Res.string.edit))
}
},
second = {
@ -543,13 +543,13 @@ private fun ModemPresetInfo(modemPresetName: String, onClick: () -> Unit) {
verticalAlignment = Alignment.CenterVertically,
) {
Column(modifier = Modifier.weight(1f).padding(16.dp)) {
Text(text = stringResource(R.string.modem_preset), fontSize = 16.sp)
Text(text = stringResource(Res.string.modem_preset), fontSize = 16.sp)
Text(text = modemPresetName, fontSize = 14.sp)
}
Spacer(modifier = Modifier.width(16.dp))
Icon(
imageVector = Icons.Default.ChevronRight,
contentDescription = stringResource(R.string.navigate_into_label),
contentDescription = stringResource(Res.string.navigate_into_label),
modifier = Modifier.padding(end = 16.dp),
)
}

View file

@ -43,9 +43,9 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.model.Contact
import com.geeksville.mesh.ui.contact.ContactItem
import com.geeksville.mesh.ui.contact.ContactsViewModel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.MainAppBar
import org.meshtastic.core.ui.theme.AppTheme
import org.meshtastic.core.strings.R as Res
@Composable
fun ShareScreen(viewModel: ContactsViewModel = hiltViewModel(), onConfirm: (String) -> Unit, onNavigateUp: () -> Unit) {
@ -61,7 +61,7 @@ fun ShareScreen(contacts: List<Contact>, onConfirm: (String) -> Unit, onNavigate
Scaffold(
topBar = {
MainAppBar(
title = stringResource(R.string.share_to),
title = stringResource(Res.string.share_to),
ourNode = null,
showNodeChip = false,
canNavigateUp = true,
@ -92,7 +92,10 @@ fun ShareScreen(contacts: List<Contact>, onConfirm: (String) -> Unit, onNavigate
modifier = Modifier.fillMaxWidth().padding(24.dp),
enabled = selectedContact.isNotEmpty(),
) {
Icon(imageVector = Icons.AutoMirrored.Default.Send, contentDescription = stringResource(R.string.share))
Icon(
imageVector = Icons.AutoMirrored.Default.Send,
contentDescription = stringResource(Res.string.share),
)
}
}
}
@ -107,10 +110,10 @@ private fun ShareScreenPreview() {
listOf(
Contact(
contactKey = "0^all",
shortName = stringResource(R.string.some_username),
longName = stringResource(R.string.unknown_username),
shortName = stringResource(Res.string.some_username),
longName = stringResource(Res.string.unknown_username),
lastMessageTime = "3 minutes ago",
lastMessageText = stringResource(R.string.sample_message),
lastMessageText = stringResource(Res.string.sample_message),
unreadCount = 2,
messageCount = 10,
isMuted = true,