From a2da943ed722856603f9f6aeee9e9b4c511989c4 Mon Sep 17 00:00:00 2001 From: Phil Oliver <3497406+poliver@users.noreply.github.com> Date: Wed, 5 Nov 2025 20:00:09 -0500 Subject: [PATCH] Clean up string access (#3629) --- .../java/com/geeksville/mesh/MainActivity.kt | 12 +++---- .../com/geeksville/mesh/ui/sharing/Channel.kt | 12 +++---- .../core/ui/util/ContextExtensions.kt | 34 +++++++++++++++++++ .../org/meshtastic/feature/map/MapView.kt | 25 +++++--------- .../CustomTileProviderManagerSheet.kt | 8 ++--- .../feature/map/component/WaypointMarkers.kt | 7 ++-- .../component/FirmwareReleaseSheetContent.kt | 22 ++++-------- .../node/component/LinkedCoordinatesItem.kt | 4 +-- .../feature/settings/SettingsScreen.kt | 20 +++++------ .../feature/settings/debugging/Debug.kt | 20 ++--------- .../DetectionSensorConfigItemList.kt | 6 ++-- .../radio/component/DeviceConfigItemList.kt | 3 +- .../radio/component/DisplayConfigItemList.kt | 6 ++-- .../ExternalNotificationConfigItemList.kt | 6 ++-- .../radio/component/MapReportingPreference.kt | 4 +-- .../component/PaxcounterConfigItemList.kt | 4 +-- .../radio/component/PositionConfigItemList.kt | 8 ++--- .../radio/component/PowerConfigItemList.kt | 10 +++--- .../component/RangeTestConfigItemList.kt | 4 +-- .../component/TelemetryConfigItemList.kt | 10 +++--- .../feature/settings/util/Formatting.kt | 8 +++-- 21 files changed, 106 insertions(+), 127 deletions(-) create mode 100644 core/ui/src/main/kotlin/org/meshtastic/core/ui/util/ContextExtensions.kt diff --git a/app/src/main/java/com/geeksville/mesh/MainActivity.kt b/app/src/main/java/com/geeksville/mesh/MainActivity.kt index 69f9285d2..ea3ccf816 100644 --- a/app/src/main/java/com/geeksville/mesh/MainActivity.kt +++ b/app/src/main/java/com/geeksville/mesh/MainActivity.kt @@ -25,7 +25,6 @@ import android.hardware.usb.UsbManager import android.net.Uri import android.os.Build import android.os.Bundle -import android.widget.Toast import androidx.activity.SystemBarStyle import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge @@ -40,13 +39,16 @@ import androidx.compose.ui.platform.LocalView import androidx.core.net.toUri import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.lifecycleScope import com.geeksville.mesh.model.UIViewModel import com.geeksville.mesh.ui.MainScreen import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch import org.meshtastic.core.datastore.UiPreferencesDataSource import org.meshtastic.core.navigation.DEEP_LINK_BASE_URI import org.meshtastic.core.ui.theme.AppTheme import org.meshtastic.core.ui.theme.MODE_DYNAMIC +import org.meshtastic.core.ui.util.showToast import org.meshtastic.feature.intro.AppIntroductionScreen import timber.log.Timber import javax.inject.Inject @@ -119,17 +121,13 @@ class MainActivity : AppCompatActivity() { Timber.d("App link data is a channel set") model.requestChannelUrl( url = it, - onFailure = { - Toast.makeText(this, getString(Res.string.channel_invalid), Toast.LENGTH_SHORT).show() - }, + onFailure = { lifecycleScope.launch { showToast(Res.string.channel_invalid) } }, ) } 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, getString(Res.string.contact_invalid), Toast.LENGTH_SHORT).show() - }, + onFailure = { lifecycleScope.launch { showToast(Res.string.contact_invalid) } }, ) } else { Timber.d("App link data is not a channel set") diff --git a/app/src/main/java/com/geeksville/mesh/ui/sharing/Channel.kt b/app/src/main/java/com/geeksville/mesh/ui/sharing/Channel.kt index 81d82b89a..3759f253e 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/sharing/Channel.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/sharing/Channel.kt @@ -21,7 +21,6 @@ import android.Manifest import android.content.ClipData import android.net.Uri import android.os.RemoteException -import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult import androidx.compose.foundation.Image import androidx.compose.foundation.border @@ -78,7 +77,6 @@ import androidx.compose.ui.platform.ClipEntry import androidx.compose.ui.platform.LocalClipboard import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager -import androidx.compose.ui.platform.LocalResources import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction @@ -107,6 +105,7 @@ import org.meshtastic.core.ui.component.ChannelSelection import org.meshtastic.core.ui.component.MainAppBar import org.meshtastic.core.ui.component.PreferenceFooter import org.meshtastic.core.ui.qr.ScannedQrCodeDialog +import org.meshtastic.core.ui.util.showToast import org.meshtastic.feature.settings.navigation.ConfigRoute import org.meshtastic.feature.settings.navigation.getNavRouteFrom import org.meshtastic.feature.settings.radio.RadioConfigViewModel @@ -181,13 +180,13 @@ fun ChannelScreen( settings.addAll(result) } + val scope = rememberCoroutineScope() val context = LocalContext.current - val resources = LocalResources.current val barcodeLauncher = rememberLauncherForActivityResult(ScanContract()) { result -> if (result.contents != null) { viewModel.requestChannelUrl(result.contents.toUri()) { - Toast.makeText(context, resources.getString(Res.string.channel_invalid), Toast.LENGTH_SHORT).show() + scope.launch { context.showToast(Res.string.channel_invalid) } } } } @@ -225,7 +224,7 @@ fun ChannelScreen( channelSet = channels // Throw away user edits // Tell the user to try again - Toast.makeText(context, resources.getString(Res.string.cant_change_no_radio), Toast.LENGTH_SHORT).show() + scope.launch { context.showToast(Res.string.cant_change_no_radio) } } } @@ -314,8 +313,7 @@ fun ChannelScreen( onTrackShare = viewModel::trackShare, onConfirm = { viewModel.requestChannelUrl(it) { - Toast.makeText(context, resources.getString(Res.string.channel_invalid), Toast.LENGTH_SHORT) - .show() + scope.launch { context.showToast(Res.string.channel_invalid) } } }, ) diff --git a/core/ui/src/main/kotlin/org/meshtastic/core/ui/util/ContextExtensions.kt b/core/ui/src/main/kotlin/org/meshtastic/core/ui/util/ContextExtensions.kt new file mode 100644 index 000000000..55318db91 --- /dev/null +++ b/core/ui/src/main/kotlin/org/meshtastic/core/ui/util/ContextExtensions.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.meshtastic.core.ui.util + +import android.content.Context +import android.widget.Toast +import androidx.annotation.StringRes + +suspend fun Context.showToast(@StringRes resId: Int) { + showToast(getString(resId)) +} + +suspend fun Context.showToast(text: CharSequence) { + Toast.makeText(this, text, Toast.LENGTH_SHORT).show() +} + +suspend fun Context.showToast(@StringRes resId: Int, vararg formatArgs: Any) { + Toast.makeText(this, getString(resId, formatArgs), Toast.LENGTH_SHORT).show() +} diff --git a/feature/map/src/fdroid/kotlin/org/meshtastic/feature/map/MapView.kt b/feature/map/src/fdroid/kotlin/org/meshtastic/feature/map/MapView.kt index a864d7cc5..ea9b60c4c 100644 --- a/feature/map/src/fdroid/kotlin/org/meshtastic/feature/map/MapView.kt +++ b/feature/map/src/fdroid/kotlin/org/meshtastic/feature/map/MapView.kt @@ -19,7 +19,6 @@ package org.meshtastic.feature.map import android.Manifest // Added for Accompanist import android.content.Context -import android.widget.Toast import androidx.appcompat.content.res.AppCompatResources import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -50,6 +49,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableDoubleStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -66,12 +66,14 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.google.accompanist.permissions.ExperimentalPermissionsApi // Added for Accompanist import com.google.accompanist.permissions.rememberMultiplePermissionsState // Added for Accompanist import com.google.android.material.dialog.MaterialAlertDialogBuilder +import kotlinx.coroutines.launch import org.meshtastic.core.common.gpsDisabled import org.meshtastic.core.common.hasGps import org.meshtastic.core.database.entity.Packet import org.meshtastic.core.database.model.Node import org.meshtastic.core.model.DataPacket import org.meshtastic.core.model.util.formatAgo +import org.meshtastic.core.ui.util.showToast import org.meshtastic.feature.map.cluster.RadiusMarkerClusterer import org.meshtastic.feature.map.component.CacheLayout import org.meshtastic.feature.map.component.DownloadButton @@ -223,6 +225,7 @@ fun MapView(mapViewModel: MapViewModel = hiltViewModel(), navigateToNodeDetails: var showEditWaypointDialog by remember { mutableStateOf(null) } var showCurrentCacheInfo by remember { mutableStateOf(false) } + val scope = rememberCoroutineScope() val context = LocalContext.current val resources = LocalResources.current val density = LocalDensity.current @@ -264,7 +267,7 @@ fun MapView(mapViewModel: MapViewModel = hiltViewModel(), navigateToNodeDetails: fun MapView.toggleMyLocation() { if (context.gpsDisabled()) { Timber.d("Telling user we need location turned on for MyLocationNewOverlay") - Toast.makeText(context, resources.getString(Res.string.location_disabled), Toast.LENGTH_SHORT).show() + scope.launch { context.showToast(Res.string.location_disabled) } return } Timber.d("user clicked MyLocationNewOverlay ${myLocationOverlay == null}") @@ -451,7 +454,7 @@ fun MapView(mapViewModel: MapViewModel = hiltViewModel(), navigateToNodeDetails: LaunchedEffect(showCurrentCacheInfo) { if (!showCurrentCacheInfo) return@LaunchedEffect - Toast.makeText(context, resources.getString(Res.string.calculating), Toast.LENGTH_SHORT).show() + context.showToast(Res.string.calculating) val cacheManager = CacheManager(map) val cacheCapacity = cacheManager.cacheCapacity() val currentCacheUsage = cacheManager.currentCacheUsage() @@ -560,21 +563,11 @@ fun MapView(mapViewModel: MapViewModel = hiltViewModel(), navigateToNodeDetails: zoomLevelMax.toInt(), cacheManagerCallback( onTaskComplete = { - Toast.makeText( - context, - resources.getString(Res.string.map_download_complete), - Toast.LENGTH_SHORT, - ) - .show() + scope.launch { context.showToast(Res.string.map_download_complete) } writer.onDetach() }, onTaskFailed = { errors -> - Toast.makeText( - context, - resources.getString(Res.string.map_download_errors, errors), - Toast.LENGTH_SHORT, - ) - .show() + scope.launch { context.showToast(Res.string.map_download_errors, errors) } writer.onDetach() }, ), @@ -619,7 +612,7 @@ fun MapView(mapViewModel: MapViewModel = hiltViewModel(), navigateToNodeDetails: dialog.dismiss() } - 2 -> purgeTileSource { Toast.makeText(this, it, Toast.LENGTH_SHORT).show() } + 2 -> purgeTileSource { scope.launch { context.showToast(it) } } else -> dialog.dismiss() } } diff --git a/feature/map/src/google/kotlin/org/meshtastic/feature/map/component/CustomTileProviderManagerSheet.kt b/feature/map/src/google/kotlin/org/meshtastic/feature/map/component/CustomTileProviderManagerSheet.kt index ab556923f..da2850657 100644 --- a/feature/map/src/google/kotlin/org/meshtastic/feature/map/component/CustomTileProviderManagerSheet.kt +++ b/feature/map/src/google/kotlin/org/meshtastic/feature/map/component/CustomTileProviderManagerSheet.kt @@ -17,7 +17,6 @@ package org.meshtastic.feature.map.component -import android.widget.Toast import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -53,6 +52,7 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import kotlinx.coroutines.flow.collectLatest import org.meshtastic.core.data.model.CustomTileProviderConfig +import org.meshtastic.core.ui.util.showToast import org.meshtastic.feature.map.MapViewModel import org.meshtastic.core.strings.R as Res @@ -64,11 +64,7 @@ fun CustomTileProviderManagerSheet(mapViewModel: MapViewModel) { var showEditDialog by remember { mutableStateOf(false) } val context = LocalContext.current - LaunchedEffect(Unit) { - mapViewModel.errorFlow.collectLatest { errorMessage -> - Toast.makeText(context, errorMessage, Toast.LENGTH_SHORT).show() - } - } + LaunchedEffect(Unit) { mapViewModel.errorFlow.collectLatest { errorMessage -> context.showToast(errorMessage) } } if (showEditDialog) { AddEditCustomTileProviderDialog( diff --git a/feature/map/src/google/kotlin/org/meshtastic/feature/map/component/WaypointMarkers.kt b/feature/map/src/google/kotlin/org/meshtastic/feature/map/component/WaypointMarkers.kt index abf807e80..92d4fcbe6 100644 --- a/feature/map/src/google/kotlin/org/meshtastic/feature/map/component/WaypointMarkers.kt +++ b/feature/map/src/google/kotlin/org/meshtastic/feature/map/component/WaypointMarkers.kt @@ -17,13 +17,15 @@ package org.meshtastic.feature.map.component -import android.widget.Toast import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.platform.LocalContext import com.google.android.gms.maps.model.BitmapDescriptor import com.google.android.gms.maps.model.LatLng import com.google.maps.android.compose.Marker import com.google.maps.android.compose.rememberUpdatedMarkerState +import kotlinx.coroutines.launch +import org.meshtastic.core.ui.util.showToast import org.meshtastic.feature.map.BaseMapViewModel import org.meshtastic.proto.MeshProtos import org.meshtastic.core.strings.R as Res @@ -39,6 +41,7 @@ fun WaypointMarkers( unicodeEmojiToBitmapProvider: (Int) -> BitmapDescriptor, onEditWaypointRequest: (MeshProtos.Waypoint) -> Unit, ) { + val scope = rememberCoroutineScope() val context = LocalContext.current if (mapFilterState.showWaypoints) { displayableWaypoints.forEach { waypoint -> @@ -60,7 +63,7 @@ fun WaypointMarkers( if (waypoint.lockedTo == 0 || waypoint.lockedTo == myNodeNum || !isConnected) { onEditWaypointRequest(waypoint) } else { - Toast.makeText(context, context.getString(Res.string.locked), Toast.LENGTH_SHORT).show() + scope.launch { context.showToast(Res.string.locked) } } }, ) diff --git a/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/FirmwareReleaseSheetContent.kt b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/FirmwareReleaseSheetContent.kt index 48f05c8cd..157ea2d34 100644 --- a/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/FirmwareReleaseSheetContent.kt +++ b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/FirmwareReleaseSheetContent.kt @@ -19,7 +19,6 @@ package org.meshtastic.feature.node.component import android.content.ActivityNotFoundException import android.content.Intent -import android.widget.Toast import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -37,21 +36,24 @@ import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalResources import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.core.net.toUri import com.mikepenz.markdown.m3.Markdown +import kotlinx.coroutines.launch import org.meshtastic.core.database.entity.FirmwareRelease +import org.meshtastic.core.ui.util.showToast import timber.log.Timber import org.meshtastic.core.strings.R as Res @Composable fun FirmwareReleaseSheetContent(firmwareRelease: FirmwareRelease, modifier: Modifier = Modifier) { + val scope = rememberCoroutineScope() val context = LocalContext.current - val resources = LocalResources.current + Column( modifier = modifier.verticalScroll(rememberScrollState()).padding(16.dp).fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(8.dp), @@ -66,12 +68,7 @@ fun FirmwareReleaseSheetContent(firmwareRelease: FirmwareRelease, modifier: Modi val intent = Intent(Intent.ACTION_VIEW, firmwareRelease.pageUrl.toUri()) context.startActivity(intent) } catch (e: ActivityNotFoundException) { - Toast.makeText( - context, - resources.getString(Res.string.error_no_app_to_handle_link), - Toast.LENGTH_LONG, - ) - .show() + scope.launch { context.showToast(Res.string.error_no_app_to_handle_link) } Timber.e(e) } }, @@ -87,12 +84,7 @@ fun FirmwareReleaseSheetContent(firmwareRelease: FirmwareRelease, modifier: Modi val intent = Intent(Intent.ACTION_VIEW, firmwareRelease.zipUrl.toUri()) context.startActivity(intent) } catch (e: ActivityNotFoundException) { - Toast.makeText( - context, - resources.getString(Res.string.error_no_app_to_handle_link), - Toast.LENGTH_LONG, - ) - .show() + scope.launch { context.showToast(Res.string.error_no_app_to_handle_link) } Timber.e(e) } }, diff --git a/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/LinkedCoordinatesItem.kt b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/LinkedCoordinatesItem.kt index 360f6d635..bb765dfb5 100644 --- a/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/LinkedCoordinatesItem.kt +++ b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/LinkedCoordinatesItem.kt @@ -20,7 +20,6 @@ package org.meshtastic.feature.node.component import android.content.ActivityNotFoundException import android.content.ClipData import android.content.Intent -import android.widget.Toast import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.rounded.KeyboardArrowRight @@ -41,6 +40,7 @@ import org.meshtastic.core.model.util.formatAgo import org.meshtastic.core.ui.component.BasicListItem import org.meshtastic.core.ui.component.icon import org.meshtastic.core.ui.theme.AppTheme +import org.meshtastic.core.ui.util.showToast import timber.log.Timber import java.net.URLEncoder import org.meshtastic.core.strings.R as Res @@ -69,7 +69,7 @@ fun LinkedCoordinatesItem(node: Node) { if (intent.resolveActivity(context.packageManager) != null) { context.startActivity(intent) } else { - Toast.makeText(context, "No application available to open this location!", Toast.LENGTH_LONG).show() + coroutineScope.launch { context.showToast("No application available to open this location!") } } } catch (ex: ActivityNotFoundException) { Timber.d("Failed to open geo intent: $ex") diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/SettingsScreen.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/SettingsScreen.kt index e45cf8421..891dcd778 100644 --- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/SettingsScreen.kt +++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/SettingsScreen.kt @@ -24,7 +24,6 @@ import android.net.Uri import android.os.Build import android.provider.Settings import android.provider.Settings.ACTION_APP_LOCALE_SETTINGS -import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity.RESULT_OK @@ -50,6 +49,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -62,6 +62,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.rememberMultiplePermissionsState import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import org.meshtastic.core.common.gpsDisabled import org.meshtastic.core.navigation.Route import org.meshtastic.core.ui.component.ListItem @@ -70,6 +71,7 @@ import org.meshtastic.core.ui.component.MultipleChoiceAlertDialog import org.meshtastic.core.ui.component.SwitchListItem import org.meshtastic.core.ui.component.TitledCard import org.meshtastic.core.ui.theme.MODE_DYNAMIC +import org.meshtastic.core.ui.util.showToast import org.meshtastic.feature.settings.navigation.getNavRouteFrom import org.meshtastic.feature.settings.radio.RadioConfigItemList import org.meshtastic.feature.settings.radio.RadioConfigViewModel @@ -230,8 +232,8 @@ fun SettingsScreen( onNavigate = onNavigate, ) + val scope = rememberCoroutineScope() val context = LocalContext.current - val resources = LocalResources.current TitledCard(title = stringResource(Res.string.app_settings), modifier = Modifier.padding(top = 16.dp)) { if (state.analyticsAvailable) { @@ -255,12 +257,7 @@ fun SettingsScreen( if (!isGpsDisabled) { settingsViewModel.meshService?.startProvideLocation() } else { - Toast.makeText( - context, - resources.getString(Res.string.location_disabled), - Toast.LENGTH_LONG, - ) - .show() + context.showToast(Res.string.location_disabled) } } else { // Request permissions if not granted and user wants to provide location @@ -393,8 +390,8 @@ private fun AppVersionButton( appVersionName: String, onUnlockExcludedModules: () -> Unit, ) { + val scope = rememberCoroutineScope() val context = LocalContext.current - val resources = LocalResources.current var clickCount by remember { mutableIntStateOf(0) } LaunchedEffect(clickCount) { @@ -415,14 +412,13 @@ private fun AppVersionButton( when { clickCount == UNLOCKED_CLICK_COUNT && excludedModulesUnlocked -> { clickCount = 0 - Toast.makeText(context, resources.getString(Res.string.modules_already_unlocked), Toast.LENGTH_LONG) - .show() + scope.launch { context.showToast(Res.string.modules_already_unlocked) } } clickCount == UNLOCK_CLICK_COUNT -> { clickCount = 0 onUnlockExcludedModules() - Toast.makeText(context, resources.getString(Res.string.modules_unlocked), Toast.LENGTH_LONG).show() + scope.launch { context.showToast(Res.string.modules_unlocked) } } } } diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/debugging/Debug.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/debugging/Debug.kt index 82b9a648a..32fed894f 100644 --- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/debugging/Debug.kt +++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/debugging/Debug.kt @@ -19,7 +19,6 @@ package org.meshtastic.feature.settings.debugging import android.content.Context import android.net.Uri -import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.core.animateFloatAsState @@ -86,6 +85,7 @@ import org.meshtastic.core.ui.component.MainAppBar import org.meshtastic.core.ui.component.SimpleAlertDialog import org.meshtastic.core.ui.theme.AnnotationColor import org.meshtastic.core.ui.theme.AppTheme +import org.meshtastic.core.ui.util.showToast import org.meshtastic.feature.settings.debugging.DebugViewModel.UiMeshLog import timber.log.Timber import java.io.IOException @@ -396,23 +396,9 @@ private suspend fun exportAllLogsToUri(context: Context, targetUri: Uri, logs: L } } ?: run { throw IOException("Unable to open output stream for URI: $targetUri") } - withContext(Dispatchers.Main) { - Toast.makeText( - context, - context.getString(Res.string.debug_export_success, logs.size), - Toast.LENGTH_LONG, - ) - .show() - } + withContext(Dispatchers.Main) { context.showToast(Res.string.debug_export_success, logs.size) } } catch (e: IOException) { - withContext(Dispatchers.Main) { - Toast.makeText( - context, - context.getString(Res.string.debug_export_failed, e.message ?: ""), - Toast.LENGTH_LONG, - ) - .show() - } + withContext(Dispatchers.Main) { context.showToast(Res.string.debug_export_failed, e.message ?: "") } Timber.w(e, "Error:IOException ") } } diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/DetectionSensorConfigItemList.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/DetectionSensorConfigItemList.kt index c5e809f04..99f64b605 100644 --- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/DetectionSensorConfigItemList.kt +++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/DetectionSensorConfigItemList.kt @@ -24,7 +24,6 @@ import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction @@ -50,7 +49,6 @@ fun DetectionSensorConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel( val detectionSensorConfig = state.moduleConfig.detectionSensor val formState = rememberConfigState(initialValue = detectionSensorConfig) val focusManager = LocalFocusManager.current - val context = LocalContext.current RadioConfigScreenList( title = stringResource(Res.string.detection_sensor), @@ -81,7 +79,7 @@ fun DetectionSensorConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel( title = stringResource(Res.string.minimum_broadcast_seconds), selectedItem = formState.value.minimumBroadcastSecs.toLong(), enabled = state.connected, - items = minimumBroadcastIntervals.map { it.value to it.toDisplayString(context = context) }, + items = minimumBroadcastIntervals.map { it.value to it.toDisplayString() }, onItemSelected = { formState.value = formState.value.copy { minimumBroadcastSecs = it.toInt() } }, ) @@ -90,7 +88,7 @@ fun DetectionSensorConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel( title = stringResource(Res.string.state_broadcast_seconds), selectedItem = formState.value.stateBroadcastSecs.toLong(), enabled = state.connected, - items = stateBroadcastIntervals.map { it.value to it.toDisplayString(context = context) }, + items = stateBroadcastIntervals.map { it.value to it.toDisplayString() }, onItemSelected = { formState.value = formState.value.copy { stateBroadcastSecs = it.toInt() } }, ) HorizontalDivider() diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/DeviceConfigItemList.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/DeviceConfigItemList.kt index c6311aebf..0348473bb 100644 --- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/DeviceConfigItemList.kt +++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/DeviceConfigItemList.kt @@ -130,7 +130,6 @@ fun DeviceConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBack } } val focusManager = LocalFocusManager.current - val context = LocalContext.current RadioConfigScreenList( title = stringResource(Res.string.device), onBack = onBack, @@ -170,7 +169,7 @@ fun DeviceConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBack title = stringResource(Res.string.nodeinfo_broadcast_interval), selectedItem = formState.value.nodeInfoBroadcastSecs.toLong(), enabled = state.connected, - items = nodeInfoBroadcastIntervals.map { it.value to it.toDisplayString(context = context) }, + items = nodeInfoBroadcastIntervals.map { it.value to it.toDisplayString() }, onItemSelected = { formState.value = formState.value.copy { nodeInfoBroadcastSecs = it.toInt() } }, ) } diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/DisplayConfigItemList.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/DisplayConfigItemList.kt index c522224d3..8eb7679d6 100644 --- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/DisplayConfigItemList.kt +++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/DisplayConfigItemList.kt @@ -22,7 +22,6 @@ import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -42,7 +41,6 @@ fun DisplayConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBac val state by viewModel.radioConfigState.collectAsStateWithLifecycle() val displayConfig = state.radioConfig.display val formState = rememberConfigState(initialValue = displayConfig) - val context = LocalContext.current RadioConfigScreenList( title = stringResource(Res.string.display), @@ -106,7 +104,7 @@ fun DisplayConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBac title = stringResource(Res.string.screen_on_for), summary = stringResource(Res.string.config_display_screen_on_secs_summary), enabled = state.connected, - items = screenOnIntervals.map { it to it.toDisplayString(context = context) }, + items = screenOnIntervals.map { it to it.toDisplayString() }, selectedItem = screenOnIntervals.find { it.value == formState.value.screenOnSecs.toLong() } ?: screenOnIntervals.first(), @@ -117,7 +115,7 @@ fun DisplayConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBac title = stringResource(Res.string.carousel_interval), summary = stringResource(Res.string.config_display_auto_screen_carousel_secs_summary), enabled = state.connected, - items = carouselIntervals.map { it to it.toDisplayString(context = context) }, + items = carouselIntervals.map { it to it.toDisplayString() }, selectedItem = carouselIntervals.find { it.value == formState.value.autoScreenCarouselSecs.toLong() } ?: carouselIntervals.first(), diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/ExternalNotificationConfigItemList.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/ExternalNotificationConfigItemList.kt index 0ed4921d8..8fc985e28 100644 --- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/ExternalNotificationConfigItemList.kt +++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/ExternalNotificationConfigItemList.kt @@ -27,7 +27,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction @@ -54,7 +53,6 @@ fun ExternalNotificationConfigScreen(viewModel: RadioConfigViewModel = hiltViewM val formState = rememberConfigState(initialValue = extNotificationConfig) var ringtoneInput by rememberSaveable(ringtone) { mutableStateOf(ringtone) } val focusManager = LocalFocusManager.current - val context = LocalContext.current RadioConfigScreenList( title = stringResource(Res.string.external_notification), @@ -191,7 +189,7 @@ fun ExternalNotificationConfigScreen(viewModel: RadioConfigViewModel = hiltViewM val outputItems = remember { IntervalConfiguration.OUTPUT.allowedIntervals } DropDownPreference( title = stringResource(Res.string.output_duration_milliseconds), - items = outputItems.map { it.value to it.toDisplayString(context = context) }, + items = outputItems.map { it.value to it.toDisplayString() }, selectedItem = formState.value.outputMs, enabled = state.connected, onItemSelected = { formState.value = formState.value.copy { outputMs = it.toInt() } }, @@ -200,7 +198,7 @@ fun ExternalNotificationConfigScreen(viewModel: RadioConfigViewModel = hiltViewM val nagItems = remember { IntervalConfiguration.NAG_TIMEOUT.allowedIntervals } DropDownPreference( title = stringResource(Res.string.nag_timeout_seconds), - items = nagItems.map { it.value to it.toDisplayString(context = context) }, + items = nagItems.map { it.value to it.toDisplayString() }, selectedItem = formState.value.nagTimeout, enabled = state.connected, onItemSelected = { formState.value = formState.value.copy { nagTimeout = it.toInt() } }, diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/MapReportingPreference.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/MapReportingPreference.kt index fb8f8de3b..bc1d41d28 100644 --- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/MapReportingPreference.kt +++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/MapReportingPreference.kt @@ -34,7 +34,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview @@ -65,7 +64,6 @@ fun MapReportingPreference( onPublishIntervalSecsChanged: (Int) -> Unit = {}, enabled: Boolean, ) { - val context = LocalContext.current Column { var showMapReportingWarning by rememberSaveable { mutableStateOf(mapReportingEnabled) } LaunchedEffect(mapReportingEnabled) { showMapReportingWarning = mapReportingEnabled } @@ -126,7 +124,7 @@ fun MapReportingPreference( DropDownPreference( modifier = Modifier.padding(bottom = 16.dp), title = stringResource(Res.string.map_reporting_interval_seconds), - items = publishItems.map { it.value to it.toDisplayString(context = context) }, + items = publishItems.map { it.value to it.toDisplayString() }, selectedItem = publishIntervalSecs, enabled = enabled, onItemSelected = { onPublishIntervalSecsChanged(it.toInt()) }, diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/PaxcounterConfigItemList.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/PaxcounterConfigItemList.kt index edfb223d4..ed66d2cbc 100644 --- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/PaxcounterConfigItemList.kt +++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/PaxcounterConfigItemList.kt @@ -23,7 +23,6 @@ import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel @@ -45,7 +44,6 @@ fun PaxcounterConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), on val paxcounterConfig = state.moduleConfig.paxcounter val formState = rememberConfigState(initialValue = paxcounterConfig) val focusManager = LocalFocusManager.current - val context = LocalContext.current RadioConfigScreenList( title = stringResource(Res.string.paxcounter), @@ -74,7 +72,7 @@ fun PaxcounterConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), on title = stringResource(Res.string.update_interval_seconds), selectedItem = formState.value.paxcounterUpdateInterval.toLong(), enabled = state.connected, - items = items.map { it.value to it.toDisplayString(context = context) }, + items = items.map { it.value to it.toDisplayString() }, onItemSelected = { formState.value = formState.value.copy { paxcounterUpdateInterval = it.toInt() } }, diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/PositionConfigItemList.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/PositionConfigItemList.kt index 9c417b686..96970194d 100644 --- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/PositionConfigItemList.kt +++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/PositionConfigItemList.kt @@ -34,7 +34,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource import androidx.core.location.LocationCompat @@ -119,7 +118,6 @@ fun PositionConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBa } } val focusManager = LocalFocusManager.current - val context = LocalContext.current RadioConfigScreenList( title = stringResource(Res.string.position), onBack = onBack, @@ -149,7 +147,7 @@ fun PositionConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBa title = stringResource(Res.string.broadcast_interval), summary = stringResource(Res.string.config_position_broadcast_secs_summary), enabled = state.connected, - items = items.map { it to it.toDisplayString(context = context) }, + items = items.map { it to it.toDisplayString() }, selectedItem = FixedUpdateIntervals.fromValue(formState.value.positionBroadcastSecs.toLong()) ?: items.first(), onItemSelected = { @@ -172,7 +170,7 @@ fun PositionConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBa summary = stringResource(Res.string.config_position_broadcast_smart_minimum_interval_secs_summary), enabled = state.connected, - items = smartItems.map { it to it.toDisplayString(context = context) }, + items = smartItems.map { it to it.toDisplayString() }, selectedItem = FixedUpdateIntervals.fromValue(formState.value.broadcastSmartMinimumIntervalSecs.toLong()) ?: smartItems.first(), @@ -262,7 +260,7 @@ fun PositionConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBa title = stringResource(Res.string.update_interval), summary = stringResource(Res.string.config_position_gps_update_interval_summary), enabled = state.connected, - items = items.map { it to it.toDisplayString(context = context) }, + items = items.map { it to it.toDisplayString() }, selectedItem = FixedUpdateIntervals.fromValue(formState.value.gpsUpdateInterval.toLong()) ?: items.first(), onItemSelected = { diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/PowerConfigItemList.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/PowerConfigItemList.kt index 959071f2d..b3e82f555 100644 --- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/PowerConfigItemList.kt +++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/PowerConfigItemList.kt @@ -23,7 +23,6 @@ import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel @@ -45,7 +44,6 @@ fun PowerConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBack: val powerConfig = state.radioConfig.power val formState = rememberConfigState(initialValue = powerConfig) val focusManager = LocalFocusManager.current - val context = LocalContext.current RadioConfigScreenList( title = stringResource(Res.string.power), @@ -75,7 +73,7 @@ fun PowerConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBack: title = stringResource(Res.string.shutdown_on_power_loss), selectedItem = formState.value.onBatteryShutdownAfterSecs.toLong(), enabled = state.connected, - items = items.map { it.value to it.toDisplayString(context = context) }, + items = items.map { it.value to it.toDisplayString() }, onItemSelected = { formState.value = formState.value.copy { onBatteryShutdownAfterSecs = it.toInt() } }, @@ -106,7 +104,7 @@ fun PowerConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBack: title = stringResource(Res.string.wait_for_bluetooth_duration_seconds), selectedItem = formState.value.waitBluetoothSecs.toLong(), enabled = state.connected, - items = waitBluetoothItems.map { it.value to it.toDisplayString(context = context) }, + items = waitBluetoothItems.map { it.value to it.toDisplayString() }, onItemSelected = { formState.value = formState.value.copy { waitBluetoothSecs = it.toInt() } }, ) HorizontalDivider() @@ -116,7 +114,7 @@ fun PowerConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBack: selectedItem = formState.value.sdsSecs.toLong(), onItemSelected = { formState.value = formState.value.copy { sdsSecs = it.toInt() } }, enabled = state.connected, - items = sdsSecsItems.map { it.value to it.toDisplayString(context = context) }, + items = sdsSecsItems.map { it.value to it.toDisplayString() }, ) HorizontalDivider() val minWakeItems = remember { IntervalConfiguration.NAG_TIMEOUT.allowedIntervals } @@ -124,7 +122,7 @@ fun PowerConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBack: title = stringResource(Res.string.minimum_wake_time_seconds), selectedItem = formState.value.minWakeSecs.toLong(), enabled = state.connected, - items = minWakeItems.map { it.value to it.toDisplayString(context = context) }, + items = minWakeItems.map { it.value to it.toDisplayString() }, onItemSelected = { formState.value = formState.value.copy { minWakeSecs = it.toInt() } }, ) HorizontalDivider() diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/RangeTestConfigItemList.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/RangeTestConfigItemList.kt index 90f5b88b6..2723c76ca 100644 --- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/RangeTestConfigItemList.kt +++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/RangeTestConfigItemList.kt @@ -22,7 +22,6 @@ import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -41,7 +40,6 @@ fun RangeTestConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onB val state by viewModel.radioConfigState.collectAsStateWithLifecycle() val rangeTestConfig = state.moduleConfig.rangeTest val formState = rememberConfigState(initialValue = rangeTestConfig) - val context = LocalContext.current RadioConfigScreenList( title = stringResource(Res.string.range_test), @@ -70,7 +68,7 @@ fun RangeTestConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onB title = stringResource(Res.string.sender_message_interval_seconds), selectedItem = formState.value.sender.toLong(), enabled = state.connected, - items = rangeItems.map { it.value to it.toDisplayString(context = context) }, + items = rangeItems.map { it.value to it.toDisplayString() }, onItemSelected = { formState.value = formState.value.copy { sender = it.toInt() } }, ) HorizontalDivider() diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/TelemetryConfigItemList.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/TelemetryConfigItemList.kt index e82853c28..6bc8e2e59 100644 --- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/TelemetryConfigItemList.kt +++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/TelemetryConfigItemList.kt @@ -22,7 +22,6 @@ import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -46,7 +45,6 @@ fun TelemetryConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onB val formState = rememberConfigState(initialValue = telemetryConfig) val firmwareVersion = state.metadata?.firmwareVersion ?: "1" - val context = LocalContext.current RadioConfigScreenList( title = stringResource(Res.string.telemetry), @@ -78,7 +76,7 @@ fun TelemetryConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onB title = stringResource(Res.string.device_metrics_update_interval_seconds), selectedItem = formState.value.deviceUpdateInterval.toLong(), enabled = state.connected, - items = items.map { it.value to it.toDisplayString(context = context) }, + items = items.map { it.value to it.toDisplayString() }, onItemSelected = { formState.value = formState.value.copy { deviceUpdateInterval = it.toInt() } }, ) HorizontalDivider() @@ -95,7 +93,7 @@ fun TelemetryConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onB title = stringResource(Res.string.environment_metrics_update_interval_seconds), selectedItem = formState.value.environmentUpdateInterval.toLong(), enabled = state.connected, - items = envItems.map { it.value to it.toDisplayString(context = context) }, + items = envItems.map { it.value to it.toDisplayString() }, onItemSelected = { formState.value = formState.value.copy { environmentUpdateInterval = it.toInt() } }, @@ -130,7 +128,7 @@ fun TelemetryConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onB title = stringResource(Res.string.air_quality_metrics_update_interval_seconds), selectedItem = formState.value.airQualityInterval.toLong(), enabled = state.connected, - items = airItems.map { it.value to it.toDisplayString(context = context) }, + items = airItems.map { it.value to it.toDisplayString() }, onItemSelected = { formState.value = formState.value.copy { airQualityInterval = it.toInt() } }, ) HorizontalDivider() @@ -147,7 +145,7 @@ fun TelemetryConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onB title = stringResource(Res.string.power_metrics_update_interval_seconds), selectedItem = formState.value.powerUpdateInterval.toLong(), enabled = state.connected, - items = powerItems.map { it.value to it.toDisplayString(context = context) }, + items = powerItems.map { it.value to it.toDisplayString() }, onItemSelected = { formState.value = formState.value.copy { powerUpdateInterval = it.toInt() } }, ) HorizontalDivider() diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/util/Formatting.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/util/Formatting.kt index 5d9273095..34f7c804c 100644 --- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/util/Formatting.kt +++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/util/Formatting.kt @@ -17,11 +17,13 @@ package org.meshtastic.feature.settings.util -import android.content.Context +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource import org.meshtastic.core.strings.R as Res -fun FixedUpdateIntervals.toDisplayString(context: Context): String = if (this == FixedUpdateIntervals.UNSET) { - context.getString(Res.string.unset) +@Composable +fun FixedUpdateIntervals.toDisplayString(): String = if (this == FixedUpdateIntervals.UNSET) { + stringResource(Res.string.unset) } else { name.split('_').joinToString(" ") { word -> word.lowercase().replaceFirstChar { it.uppercase() } } }