refactor(R): Move R file imports to core UI module (#3159)

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
pull/3171/head
James Rich 2025-09-22 20:59:39 -05:00 zatwierdzone przez GitHub
rodzic e8e7608e52
commit d2db37e0d4
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
176 zmienionych plików z 579 dodań i 647 usunięć

Wyświetl plik

@ -183,6 +183,7 @@ dependencies {
implementation(projects.core.network)
implementation(projects.core.prefs)
implementation(projects.core.proto)
implementation(projects.core.strings)
implementation(projects.feature.map)
// Bundles

Wyświetl plik

@ -31,11 +31,11 @@ import androidx.compose.ui.test.performTextInput
import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.debug.FilterMode
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.meshtastic.core.strings.R
@RunWith(AndroidJUnit4::class)
class DebugFiltersTest {

Wyświetl plik

@ -32,13 +32,13 @@ import androidx.compose.ui.test.performTextInput
import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.geeksville.mesh.R
import com.geeksville.mesh.model.LogSearchManager.SearchState
import com.geeksville.mesh.ui.debug.DebugSearchBar
import com.geeksville.mesh.ui.debug.FilterMode
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.meshtastic.core.strings.R
@RunWith(AndroidJUnit4::class)
class DebugSearchTest {

Wyświetl plik

@ -24,7 +24,6 @@ import androidx.compose.ui.test.performClick
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.geeksville.mesh.ClientOnlyProtos.DeviceProfile
import com.geeksville.mesh.R
import com.geeksville.mesh.deviceProfile
import com.geeksville.mesh.position
import com.geeksville.mesh.ui.settings.radio.components.EditDeviceProfileDialog
@ -32,6 +31,7 @@ import org.junit.Assert
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.meshtastic.core.strings.R
@RunWith(AndroidJUnit4::class)
class EditDeviceProfileDialogTest {

Wyświetl plik

@ -26,12 +26,12 @@ import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.settings.radio.components.MapReportingPreference
import org.junit.Assert
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.meshtastic.core.strings.R
@RunWith(AndroidJUnit4::class)
class MapReportingPreferenceTest {

Wyświetl plik

@ -22,9 +22,7 @@ import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.geeksville.mesh.MessageStatus
import com.geeksville.mesh.R
import com.geeksville.mesh.model.Message
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.ui.common.preview.NodePreviewParameterProvider
import com.geeksville.mesh.ui.message.components.MessageItem
import org.junit.Rule
@ -34,30 +32,30 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class MessageItemTest {
@get:Rule
val composeTestRule = createComposeRule()
@get:Rule val composeTestRule = createComposeRule()
@Test
fun mqttIconIsDisplayedWhenViaMqttIsTrue() {
val testNode = NodePreviewParameterProvider().minnieMouse
val messageWithMqtt = Message(
text = "Test message via MQTT",
time = "10:00",
fromLocal = false,
status = MessageStatus.RECEIVED,
snr = 2.5f,
rssi = 90,
hopsAway = 0,
uuid = 1L,
receivedTime = System.currentTimeMillis(),
node = testNode,
read = false,
routingError = 0,
packetId = 1234,
emojis = listOf(),
replyId = null,
viaMqtt = true
)
val messageWithMqtt =
Message(
text = "Test message via MQTT",
time = "10:00",
fromLocal = false,
status = MessageStatus.RECEIVED,
snr = 2.5f,
rssi = 90,
hopsAway = 0,
uuid = 1L,
receivedTime = System.currentTimeMillis(),
node = testNode,
read = false,
routingError = 0,
packetId = 1234,
emojis = listOf(),
replyId = null,
viaMqtt = true,
)
composeTestRule.setContent {
MessageItem(
@ -79,24 +77,25 @@ class MessageItemTest {
@Test
fun mqttIconIsNotDisplayedWhenViaMqttIsFalse() {
val testNode = NodePreviewParameterProvider().minnieMouse
val messageWithoutMqtt = Message(
text = "Test message not via MQTT",
time = "10:00",
fromLocal = false,
status = MessageStatus.RECEIVED,
snr = 2.5f,
rssi = 90,
hopsAway = 0,
uuid = 1L,
receivedTime = System.currentTimeMillis(),
node = testNode,
read = false,
routingError = 0,
packetId = 1234,
emojis = listOf(),
replyId = null,
viaMqtt = false
)
val messageWithoutMqtt =
Message(
text = "Test message not via MQTT",
time = "10:00",
fromLocal = false,
status = MessageStatus.RECEIVED,
snr = 2.5f,
rssi = 90,
hopsAway = 0,
uuid = 1L,
receivedTime = System.currentTimeMillis(),
node = testNode,
read = false,
routingError = 0,
packetId = 1234,
emojis = listOf(),
replyId = null,
viaMqtt = false,
)
composeTestRule.setContent {
MessageItem(
@ -114,4 +113,4 @@ class MessageItemTest {
// Check that the MQTT icon is not displayed
composeTestRule.onNodeWithContentDescription("via MQTT").assertDoesNotExist()
}
}
}

Wyświetl plik

@ -25,7 +25,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.geeksville.mesh.AppOnlyProtos.ChannelSet
import com.geeksville.mesh.ConfigProtos
import com.geeksville.mesh.R
import com.geeksville.mesh.channelSet
import com.geeksville.mesh.channelSettings
import com.geeksville.mesh.copy
@ -35,6 +34,7 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.meshtastic.core.model.Channel
import org.meshtastic.core.strings.R
@RunWith(AndroidJUnit4::class)
class ScannedQrCodeDialogTest {

Wyświetl plik

@ -64,7 +64,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import com.geeksville.mesh.DataPacket
import com.geeksville.mesh.MeshProtos.Waypoint
import com.geeksville.mesh.R
import com.geeksville.mesh.android.BuildUtils.debug
import com.geeksville.mesh.android.gpsDisabled
import com.geeksville.mesh.android.hasGps
@ -85,6 +84,7 @@ import com.geeksville.mesh.waypoint
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 org.meshtastic.core.strings.R
import org.meshtastic.feature.map.cluster.RadiusMarkerClusterer
import org.meshtastic.feature.map.model.CustomTileSource
import org.meshtastic.feature.map.model.MarkerWithLabel
@ -276,11 +276,11 @@ fun MapView(
MyLocationNewOverlay(this).apply {
enableMyLocation()
enableFollowLocation()
getBitmapFromVectorDrawable(context, R.drawable.ic_map_location_dot_24)?.let {
getBitmapFromVectorDrawable(context, com.geeksville.mesh.R.drawable.ic_map_location_dot_24)?.let {
setPersonIcon(it)
setPersonAnchor(0.5f, 0.5f)
}
getBitmapFromVectorDrawable(context, R.drawable.ic_map_navigation_24)?.let {
getBitmapFromVectorDrawable(context, com.geeksville.mesh.R.drawable.ic_map_navigation_24)?.let {
setDirectionIcon(it)
setDirectionAnchor(0.5f, 0.5f)
}
@ -307,7 +307,9 @@ fun MapView(
val nodes by mapViewModel.nodes.collectAsStateWithLifecycle()
val waypoints by mapViewModel.waypoints.collectAsStateWithLifecycle(emptyMap())
val markerIcon = remember { AppCompatResources.getDrawable(context, R.drawable.ic_baseline_location_on_24) }
val markerIcon = remember {
AppCompatResources.getDrawable(context, com.geeksville.mesh.R.drawable.ic_baseline_location_on_24)
}
fun MapView.onNodesChanged(nodes: Collection<Node>): List<MarkerWithLabel> {
val nodesWithPosition = nodes.filter { it.validPosition != null }

Wyświetl plik

@ -36,7 +36,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import org.meshtastic.core.strings.R
@OptIn(ExperimentalLayoutApi::class)
@Composable

Wyświetl plik

@ -31,7 +31,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.res.stringResource
import com.geeksville.mesh.R
import org.meshtastic.core.strings.R
@Composable
internal fun DownloadButton(enabled: Boolean, onClick: () -> Unit) {

Wyświetl plik

@ -63,12 +63,12 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.geeksville.mesh.MeshProtos.Waypoint
import com.geeksville.mesh.R
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.EmojiPickerDialog
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.waypoint
import org.meshtastic.core.strings.R
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale

Wyświetl plik

@ -29,8 +29,8 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.strings.R
@Composable
fun MapButton(

Wyświetl plik

@ -26,7 +26,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.content.ContextCompat
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.R
import org.meshtastic.core.strings.R
import org.osmdroid.util.GeoPoint
import org.osmdroid.views.MapView
import org.osmdroid.views.overlay.CopyrightOverlay
@ -126,7 +126,7 @@ fun MapView.addPolyline(density: Density, geoPoints: List<GeoPoint>, onClick: ()
}
fun MapView.addPositionMarkers(positions: List<MeshProtos.Position>, onClick: () -> Unit): List<Marker> {
val navIcon = ContextCompat.getDrawable(context, R.drawable.ic_map_navigation_24)
val navIcon = ContextCompat.getDrawable(context, com.geeksville.mesh.R.drawable.ic_map_navigation_24)
val markers =
positions.map {
Marker(this).apply {

Wyświetl plik

@ -68,7 +68,6 @@ import com.geeksville.mesh.ConfigProtos.Config.DisplayConfig.DisplayUnits
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.MeshProtos.Position
import com.geeksville.mesh.MeshProtos.Waypoint
import com.geeksville.mesh.R
import com.geeksville.mesh.android.BuildUtils.debug
import com.geeksville.mesh.android.BuildUtils.warn
import com.geeksville.mesh.copy
@ -121,6 +120,7 @@ import com.google.maps.android.compose.rememberUpdatedMarkerState
import com.google.maps.android.compose.widgets.ScaleBar
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import org.meshtastic.core.strings.R
import timber.log.Timber
import java.text.DateFormat

Wyświetl plik

@ -31,9 +31,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.map.NodeClusterItem
import com.geeksville.mesh.ui.node.components.NodeChip
import org.meshtastic.core.strings.R
@Composable
fun ClusterItemsListDialog(

Wyświetl plik

@ -39,8 +39,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.map.MapLayerItem
import org.meshtastic.core.strings.R
@Suppress("LongMethod")
@Composable

Wyświetl plik

@ -51,10 +51,10 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.map.CustomTileProviderConfig
import com.geeksville.mesh.ui.map.MapViewModel
import kotlinx.coroutines.flow.collectLatest
import org.meshtastic.core.strings.R
@Suppress("LongMethod")
@Composable

Wyświetl plik

@ -63,9 +63,9 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.geeksville.mesh.MeshProtos.Waypoint
import com.geeksville.mesh.R
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.common.components.EmojiPickerDialog
import org.meshtastic.core.strings.R
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale

Wyświetl plik

@ -33,9 +33,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.res.stringResource
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusRed
import com.geeksville.mesh.ui.map.MapViewModel
import org.meshtastic.core.strings.R
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable

Wyświetl plik

@ -30,8 +30,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.map.MapViewModel
import org.meshtastic.core.strings.R
@Composable
internal fun MapFilterDropdown(expanded: Boolean, onDismissRequest: () -> Unit, mapViewModel: MapViewModel) {

Wyświetl plik

@ -28,9 +28,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.map.MapViewModel
import com.google.maps.android.compose.MapType
import org.meshtastic.core.strings.R
@Suppress("LongMethod")
@Composable

Wyświetl plik

@ -21,13 +21,13 @@ import android.widget.Toast
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.map.BaseMapViewModel
import com.geeksville.mesh.ui.node.DEG_D
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 org.meshtastic.core.strings.R
@Composable
fun WaypointMarkers(

Wyświetl plik

@ -26,7 +26,6 @@ import android.os.RemoteException
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.geeksville.mesh.R
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.repository.bluetooth.BluetoothRepository
import com.geeksville.mesh.repository.datastore.recentaddresses.RecentAddress
@ -53,6 +52,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import org.meshtastic.core.strings.R
import javax.inject.Inject
/**

Wyświetl plik

@ -20,8 +20,8 @@ package com.geeksville.mesh.model
import androidx.annotation.StringRes
import com.geeksville.mesh.MeshProtos.Routing
import com.geeksville.mesh.MessageStatus
import com.geeksville.mesh.R
import com.geeksville.mesh.database.entity.Reaction
import org.meshtastic.core.strings.R
@Suppress("CyclomaticComplexMethod")
@StringRes
@ -67,12 +67,13 @@ data class Message(
) {
fun getStatusStringRes(): Pair<Int, Int> {
val title = if (routingError > 0) R.string.error else R.string.message_delivery_status
val text = when (status) {
MessageStatus.RECEIVED -> R.string.delivery_confirmed
MessageStatus.QUEUED -> R.string.message_status_queued
MessageStatus.ENROUTE -> R.string.message_status_enroute
else -> getStringResFrom(routingError)
}
val text =
when (status) {
MessageStatus.RECEIVED -> R.string.delivery_confirmed
MessageStatus.QUEUED -> R.string.message_status_queued
MessageStatus.ENROUTE -> R.string.message_status_enroute
else -> getStringResFrom(routingError)
}
return title to text
}
}

Wyświetl plik

@ -34,7 +34,6 @@ import com.geeksville.mesh.MeshProtos.MeshPacket
import com.geeksville.mesh.MeshProtos.Position
import com.geeksville.mesh.Portnums
import com.geeksville.mesh.Portnums.PortNum
import com.geeksville.mesh.R
import com.geeksville.mesh.TelemetryProtos.Telemetry
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.android.prefs.MapPrefs
@ -63,6 +62,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.meshtastic.core.model.DeviceHardware
import org.meshtastic.core.navigation.NodesRoutes
import org.meshtastic.core.strings.R
import org.meshtastic.feature.map.model.CustomTileSource
import java.io.BufferedWriter
import java.io.FileNotFoundException

Wyświetl plik

@ -18,7 +18,7 @@
package com.geeksville.mesh.model
import androidx.annotation.StringRes
import com.geeksville.mesh.R
import org.meshtastic.core.strings.R
enum class NodeSortOption(val sqlValue: String, @StringRes val stringRes: Int) {
LAST_HEARD("last_heard", R.string.node_sort_last_heard),

Wyświetl plik

@ -38,7 +38,6 @@ import com.geeksville.mesh.LocalOnlyProtos.LocalConfig
import com.geeksville.mesh.LocalOnlyProtos.LocalModuleConfig
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.Position
import com.geeksville.mesh.R
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.android.prefs.UiPrefs
import com.geeksville.mesh.channel
@ -84,6 +83,7 @@ import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.meshtastic.core.model.DeviceHardware
import org.meshtastic.core.strings.R
import javax.inject.Inject
// Given a human name, strip out the first letter of the first three words and return that as the

Wyświetl plik

@ -39,7 +39,6 @@ import androidx.navigation.NavHostController
import androidx.navigation.compose.composable
import androidx.navigation.compose.navigation
import androidx.navigation.navDeepLink
import com.geeksville.mesh.R
import com.geeksville.mesh.model.MetricsViewModel
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.ui.metrics.DeviceMetricsScreen
@ -58,6 +57,7 @@ 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
fun NavGraphBuilder.nodesGraph(navController: NavHostController, uiViewModel: UIViewModel) {
navigation<NodesRoutes.NodesGraph>(startDestination = NodesRoutes.Nodes) {

Wyświetl plik

@ -56,7 +56,6 @@ import androidx.navigation.navDeepLink
import androidx.navigation.navigation
import com.geeksville.mesh.AdminProtos
import com.geeksville.mesh.MeshProtos.DeviceMetadata
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.debug.DebugScreen
import com.geeksville.mesh.ui.settings.SettingsScreen
import com.geeksville.mesh.ui.settings.radio.CleanNodeDatabaseScreen
@ -88,6 +87,7 @@ import org.meshtastic.core.navigation.DEEP_LINK_BASE_URI
import org.meshtastic.core.navigation.NodesRoutes
import org.meshtastic.core.navigation.Route
import org.meshtastic.core.navigation.SettingsRoutes
import org.meshtastic.core.strings.R
fun getNavRouteFrom(routeName: String): Route? =
ConfigRoute.entries.find { it.name == routeName }?.route ?: ModuleRoute.entries.find { it.name == routeName }?.route

Wyświetl plik

@ -22,11 +22,8 @@ import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import com.geeksville.mesh.R
import com.geeksville.mesh.android.Logging
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
@ -34,6 +31,9 @@ import kotlinx.serialization.SerializationException
import kotlinx.serialization.json.Json
import org.json.JSONArray
import org.json.JSONObject
import org.meshtastic.core.strings.R
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class RecentAddressesRepository
@ -53,15 +53,11 @@ constructor(
try {
Json.decodeFromString<List<RecentAddress>>(jsonString)
} catch (e: IllegalArgumentException) {
warn(
"Could not parse recent addresses, falling back to legacy parsing: ${e.message}"
)
warn("Could not parse recent addresses, falling back to legacy parsing: ${e.message}")
// Fallback to legacy parsing
parseLegacyRecentAddresses(jsonString)
} catch (e: SerializationException) {
warn(
"Could not parse recent addresses, falling back to legacy parsing: ${e.message}"
)
warn("Could not parse recent addresses, falling back to legacy parsing: ${e.message}")
// Fallback to legacy parsing
parseLegacyRecentAddresses(jsonString)
}
@ -76,10 +72,7 @@ constructor(
when (val item = jsonArray.get(i)) {
is JSONObject -> {
// Modern format: JSONObject with address and name
RecentAddress(
address = item.getString("address"),
name = item.getString("name"),
)
RecentAddress(address = item.getString("address"), name = item.getString("name"))
}
is String -> {
// Old format: just the address string

Wyświetl plik

@ -50,7 +50,6 @@ import com.geeksville.mesh.NodeInfo
import com.geeksville.mesh.PaxcountProtos
import com.geeksville.mesh.Portnums
import com.geeksville.mesh.Position
import com.geeksville.mesh.R
import com.geeksville.mesh.StoreAndForwardProtos
import com.geeksville.mesh.TelemetryProtos
import com.geeksville.mesh.TelemetryProtos.LocalStats
@ -104,6 +103,7 @@ import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.meshtastic.core.model.getFullTracerouteResponse
import org.meshtastic.core.strings.R
import java.util.Random
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap

Wyświetl plik

@ -22,7 +22,7 @@ import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.TaskStackBuilder
import android.content.ContentResolver
import android.content.ContentResolver.SCHEME_ANDROID_RESOURCE
import android.content.Context
import android.content.Intent
import android.graphics.Color
@ -36,12 +36,13 @@ import androidx.core.content.getSystemService
import androidx.core.net.toUri
import com.geeksville.mesh.MainActivity
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.R
import com.geeksville.mesh.R.raw
import com.geeksville.mesh.TelemetryProtos.LocalStats
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.service.ReplyReceiver.Companion.KEY_TEXT_REPLY
import com.geeksville.mesh.util.formatUptime
import org.meshtastic.core.navigation.DEEP_LINK_BASE_URI
import org.meshtastic.core.strings.R
/**
* Manages the creation and display of all app notifications.
@ -184,8 +185,7 @@ class MeshServiceNotifications(private val context: Context) {
enableLights(true)
enableVibration(true)
setBypassDnd(true)
val alertSoundUri =
"${ContentResolver.SCHEME_ANDROID_RESOURCE}://${context.packageName}/${R.raw.alert}".toUri()
val alertSoundUri = "${SCHEME_ANDROID_RESOURCE}://${context.packageName}/${raw.alert}".toUri()
setSound(
alertSoundUri,
AudioAttributes.Builder()
@ -415,7 +415,7 @@ class MeshServiceNotifications(private val context: Context) {
type: NotificationType,
contentIntent: PendingIntent? = null,
): NotificationCompat.Builder {
val smallIcon = R.drawable.app_icon
val smallIcon = com.geeksville.mesh.R.drawable.app_icon
return NotificationCompat.Builder(context, type.channelId)
.setSmallIcon(smallIcon)

Wyświetl plik

@ -76,7 +76,6 @@ import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.geeksville.mesh.BuildConfig
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.R
import com.geeksville.mesh.android.AddNavigationTracking
import com.geeksville.mesh.android.BuildUtils.debug
import com.geeksville.mesh.android.setAttributes
@ -120,6 +119,7 @@ import org.meshtastic.core.navigation.NodeDetailRoutes
import org.meshtastic.core.navigation.NodesRoutes
import org.meshtastic.core.navigation.Route
import org.meshtastic.core.navigation.SettingsRoutes
import org.meshtastic.core.strings.R
import kotlin.reflect.KClass
enum class TopLevelDestination(@StringRes val label: Int, val icon: ImageVector, val route: Route) {

Wyświetl plik

@ -37,7 +37,7 @@ import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.fromHtml
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import org.meshtastic.core.strings.R
@Composable
fun SimpleAlertDialog(
@ -45,40 +45,34 @@ fun SimpleAlertDialog(
message: String?,
html: String? = null,
onDismissRequest: () -> Unit,
onConfirmRequest: () -> Unit = onDismissRequest // Default confirm to dismiss
onConfirmRequest: () -> Unit = onDismissRequest, // Default confirm to dismiss
) {
val annotatedString = html?.let {
AnnotatedString.fromHtml(
html,
linkStyles = TextLinkStyles(
style = SpanStyle(
textDecoration = TextDecoration.Underline,
fontStyle = FontStyle.Italic,
color = MaterialTheme.colorScheme.primary
)
val annotatedString =
html?.let {
AnnotatedString.fromHtml(
html,
linkStyles =
TextLinkStyles(
style =
SpanStyle(
textDecoration = TextDecoration.Underline,
fontStyle = FontStyle.Italic,
color = MaterialTheme.colorScheme.primary,
),
),
)
)
}
}
AlertDialog(
onDismissRequest = onDismissRequest,
title = { Text(text = title) },
text = {
if (annotatedString != null) {
Text(
text = annotatedString,
)
Text(text = annotatedString)
} else {
Text(
text = message.orEmpty()
)
}
},
confirmButton = {
TextButton(onClick = onConfirmRequest) {
Text(stringResource(id = R.string.okay))
Text(text = message.orEmpty())
}
},
confirmButton = { TextButton(onClick = onConfirmRequest) { Text(stringResource(id = R.string.okay)) } },
)
}
@ -94,15 +88,8 @@ fun MultipleChoiceAlertDialog(
onDismissRequest = onDismissRequest,
title = { Text(text = title) },
text = {
Column(
modifier = Modifier.verticalScroll(rememberScrollState())
) {
message?.let {
Text(
text = it,
modifier = Modifier.padding(bottom = 8.dp)
)
}
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
message?.let { Text(text = it, modifier = Modifier.padding(bottom = 8.dp)) }
choices.forEach { (choice, action) ->
Button(
modifier = Modifier.fillMaxWidth().padding(8.dp),
@ -116,7 +103,6 @@ fun MultipleChoiceAlertDialog(
}
}
},
confirmButton = {
}
confirmButton = {},
)
}

Wyświetl plik

@ -36,26 +36,20 @@ import com.geeksville.mesh.R
import com.geeksville.mesh.ui.common.theme.AppTheme
@Composable
fun BatteryInfo(
modifier: Modifier = Modifier,
batteryLevel: Int?,
voltage: Float?
) {
fun BatteryInfo(modifier: Modifier = Modifier, batteryLevel: Int?, voltage: Float?) {
val infoString = "%d%% %.2fV".format(batteryLevel, voltage)
val (image, level) = when (batteryLevel) {
in 0 .. 4 -> R.drawable.ic_battery_alert to " $infoString"
in 5 .. 14 -> R.drawable.ic_battery_outline to infoString
in 15..34 -> R.drawable.ic_battery_low to infoString
in 35..79 -> R.drawable.ic_battery_medium to infoString
in 80..100 -> R.drawable.ic_battery_high to infoString
101 -> R.drawable.ic_power_plug_24 to "%.2fV".format(voltage)
else -> R.drawable.ic_battery_unknown to (voltage?.let { "%.2fV".format(it) } ?: "")
}
val (image, level) =
when (batteryLevel) {
in 0..4 -> R.drawable.ic_battery_alert to " $infoString"
in 5..14 -> R.drawable.ic_battery_outline to infoString
in 15..34 -> R.drawable.ic_battery_low to infoString
in 35..79 -> R.drawable.ic_battery_medium to infoString
in 80..100 -> R.drawable.ic_battery_high to infoString
101 -> R.drawable.ic_power_plug_24 to "%.2fV".format(voltage)
else -> R.drawable.ic_battery_unknown to (voltage?.let { "%.2fV".format(it) } ?: "")
}
Row(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically
) {
Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) {
Icon(
modifier = Modifier.height(18.dp),
imageVector = ImageVector.vectorResource(id = image),
@ -65,46 +59,34 @@ fun BatteryInfo(
Text(
text = level,
color = MaterialTheme.colorScheme.onSurface,
fontSize = MaterialTheme.typography.labelLarge.fontSize
fontSize = MaterialTheme.typography.labelLarge.fontSize,
)
}
}
@PreviewLightDark
@Composable
fun BatteryInfoPreview(
@PreviewParameter(BatteryInfoPreviewParameterProvider::class)
batteryInfo: Pair<Int?, Float?>
) {
AppTheme {
BatteryInfo(
batteryLevel = batteryInfo.first,
voltage = batteryInfo.second
)
}
fun BatteryInfoPreview(@PreviewParameter(BatteryInfoPreviewParameterProvider::class) batteryInfo: Pair<Int?, Float?>) {
AppTheme { BatteryInfo(batteryLevel = batteryInfo.first, voltage = batteryInfo.second) }
}
@Composable
@Preview
fun BatteryInfoPreviewSimple() {
AppTheme {
BatteryInfo(
batteryLevel = 85,
voltage = 3.7F
)
}
AppTheme { BatteryInfo(batteryLevel = 85, voltage = 3.7F) }
}
class BatteryInfoPreviewParameterProvider : PreviewParameterProvider<Pair<Int?, Float?>> {
override val values: Sequence<Pair<Int?, Float?>>
get() = sequenceOf(
85 to 3.7F,
2 to 3.7F,
12 to 3.7F,
28 to 3.7F,
50 to 3.7F,
101 to 4.9F,
null to 4.5F,
null to null
)
get() =
sequenceOf(
85 to 3.7F,
2 to 3.7F,
12 to 3.7F,
28 to 3.7F,
50 to 3.7F,
101 to 4.9F,
null to 4.5F,
null to null,
)
}

Wyświetl plik

@ -38,7 +38,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import org.meshtastic.core.strings.R
@OptIn(ExperimentalMaterial3Api::class)
@Composable

Wyświetl plik

@ -28,8 +28,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ClipEntry
import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.res.stringResource
import com.geeksville.mesh.R
import kotlinx.coroutines.launch
import org.meshtastic.core.strings.R
@Composable
fun CopyIconButton(
@ -47,11 +47,8 @@ fun CopyIconButton(
val clipEntry = ClipEntry(clipData)
clipboardManager.setClipEntry(clipEntry)
}
}
},
) {
Icon(
imageVector = Icons.TwoTone.ContentCopy,
contentDescription = label
)
Icon(imageVector = Icons.TwoTone.ContentCopy, contentDescription = label)
}
}

Wyświetl plik

@ -44,11 +44,11 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.util.encodeToString
import com.geeksville.mesh.util.toByteString
import com.google.protobuf.ByteString
import org.meshtastic.core.model.Channel
import org.meshtastic.core.strings.R
@Suppress("LongMethod")
@Composable

Wyświetl plik

@ -42,10 +42,10 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.ModuleConfigProtos.RemoteHardwarePin
import com.geeksville.mesh.ModuleConfigProtos.RemoteHardwarePinType
import com.geeksville.mesh.R
import com.geeksville.mesh.copy
import com.geeksville.mesh.remoteHardwarePin
import com.google.protobuf.ByteString
import org.meshtastic.core.strings.R
@Suppress("LongMethod")
@Composable

Wyświetl plik

@ -35,7 +35,7 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.R
import org.meshtastic.core.strings.R
@Composable
fun EditPasswordPreference(
@ -55,20 +55,18 @@ fun EditPasswordPreference(
maxSize = maxSize,
enabled = enabled,
isError = false,
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Password, imeAction = ImeAction.Done
),
keyboardOptions =
KeyboardOptions.Default.copy(keyboardType = KeyboardType.Password, imeAction = ImeAction.Done),
keyboardActions = keyboardActions,
onValueChanged = {
onValueChanged(it)
},
onValueChanged = { onValueChanged(it) },
onFocusChanged = {},
visualTransformation = if (isPasswordVisible) VisualTransformation.None else PasswordVisualTransformation(),
trailingIcon = {
IconButton(onClick = { isPasswordVisible = !isPasswordVisible }) {
Icon(
imageVector = if (isPasswordVisible) Icons.TwoTone.VisibilityOff else Icons.TwoTone.VisibilityOff,
contentDescription = if (isPasswordVisible) {
contentDescription =
if (isPasswordVisible) {
stringResource(R.string.hide_password)
} else {
stringResource(R.string.show_password)
@ -76,7 +74,7 @@ fun EditPasswordPreference(
)
}
},
modifier = modifier
modifier = modifier,
)
}
@ -89,6 +87,6 @@ private fun EditPasswordPreferencePreview() {
maxSize = 63,
enabled = true,
keyboardActions = KeyboardActions {},
onValueChanged = {}
onValueChanged = {},
)
}

Wyświetl plik

@ -44,7 +44,7 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import org.meshtastic.core.strings.R
@Composable
fun SignedIntegerEditTextPreference(

Wyświetl plik

@ -57,7 +57,6 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.common.theme.IAQColors.IAQDangerouslyPolluted
import com.geeksville.mesh.ui.common.theme.IAQColors.IAQExcellent
import com.geeksville.mesh.ui.common.theme.IAQColors.IAQExtremelyPolluted
@ -66,6 +65,7 @@ import com.geeksville.mesh.ui.common.theme.IAQColors.IAQHeavilyPolluted
import com.geeksville.mesh.ui.common.theme.IAQColors.IAQLightlyPolluted
import com.geeksville.mesh.ui.common.theme.IAQColors.IAQModeratelyPolluted
import com.geeksville.mesh.ui.common.theme.IAQColors.IAQSeverelyPolluted
import org.meshtastic.core.strings.R
@Suppress("MagicNumber")
enum class Iaq(val color: Color, val description: String, val range: IntRange) {

Wyświetl plik

@ -47,11 +47,11 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusGreen
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusOrange
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusRed
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusYellow
import org.meshtastic.core.strings.R
private const val SNR_GOOD_THRESHOLD = -7f
private const val SNR_FAIR_THRESHOLD = -15f

Wyświetl plik

@ -46,7 +46,6 @@ import androidx.navigation.NavDestination
import androidx.navigation.NavDestination.Companion.hasRoute
import androidx.navigation.NavHostController
import androidx.navigation.compose.currentBackStackEntryAsState
import com.geeksville.mesh.R
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.navigation.isConfigRoute
@ -59,6 +58,7 @@ import com.geeksville.mesh.ui.node.components.NodeMenuAction
import org.meshtastic.core.navigation.ContactsRoutes
import org.meshtastic.core.navigation.NodesRoutes
import org.meshtastic.core.navigation.SettingsRoutes
import org.meshtastic.core.strings.R
@Suppress("CyclomaticComplexMethod")
@Composable
@ -153,7 +153,7 @@ fun MainAppBar(
{
IconButton(enabled = false, onClick = {}) {
Icon(
imageVector = ImageVector.vectorResource(id = R.drawable.app_icon),
imageVector = ImageVector.vectorResource(id = com.geeksville.mesh.R.drawable.app_icon),
contentDescription = stringResource(id = R.string.application_icon),
)
}

Wyświetl plik

@ -31,9 +31,9 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.util.DistanceUnit
import com.geeksville.mesh.util.toDistanceString
import org.meshtastic.core.strings.R
import kotlin.math.pow
import kotlin.math.roundToInt

Wyświetl plik

@ -30,7 +30,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import org.meshtastic.core.strings.R
@Composable
fun PreferenceFooter(
@ -59,32 +59,15 @@ fun PreferenceFooter(
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier
.fillMaxWidth()
.height(64.dp),
modifier = modifier.fillMaxWidth().height(64.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
OutlinedButton(
modifier = modifier
.height(48.dp)
.weight(1f),
onClick = onNegativeClicked,
) {
Text(
text = stringResource(id = negativeText),
)
OutlinedButton(modifier = Modifier.height(48.dp).weight(1f), onClick = onNegativeClicked) {
Text(text = stringResource(id = negativeText))
}
OutlinedButton(
modifier = modifier
.height(48.dp)
.weight(1f),
enabled = enabled,
onClick = onPositiveClicked,
) {
Text(
text = stringResource(id = positiveText),
)
OutlinedButton(modifier = Modifier.height(48.dp).weight(1f), enabled = enabled, onClick = onPositiveClicked) {
Text(text = stringResource(id = positiveText))
}
}
}

Wyświetl plik

@ -52,12 +52,12 @@ import androidx.compose.ui.window.DialogProperties
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.AppOnlyProtos.ChannelSet
import com.geeksville.mesh.ConfigProtos.Config.LoRaConfig.ModemPreset
import com.geeksville.mesh.R
import com.geeksville.mesh.channelSet
import com.geeksville.mesh.copy
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.ui.settings.radio.components.ChannelSelection
import org.meshtastic.core.model.Channel
import org.meshtastic.core.strings.R
@Composable
fun ScannedQrCodeDialog(viewModel: UIViewModel, incoming: ChannelSet) {

Wyświetl plik

@ -63,12 +63,12 @@ import androidx.compose.ui.unit.dp
import com.geeksville.mesh.AppOnlyProtos
import com.geeksville.mesh.ChannelProtos.ChannelSettings
import com.geeksville.mesh.ConfigProtos.Config.LoRaConfig
import com.geeksville.mesh.R
import com.geeksville.mesh.model.getChannel
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusGreen
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusRed
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusYellow
import org.meshtastic.core.model.Channel
import org.meshtastic.core.strings.R
private const val PRECISE_POSITION_BITS = 32

Wyświetl plik

@ -26,48 +26,46 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.tooling.preview.PreviewParameter
import com.geeksville.mesh.R
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.ui.common.preview.NodePreviewParameterProvider
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.strings.R
const val MAX_VALID_SNR = 100F
const val MAX_VALID_RSSI = 0
@Composable
fun SignalInfo(
modifier: Modifier = Modifier,
node: Node,
isThisNode: Boolean
) {
val text = if (isThisNode) {
stringResource(R.string.channel_air_util).format(
node.deviceMetrics.channelUtilization,
node.deviceMetrics.airUtilTx
)
} else {
buildList {
val hopsString = "%s: %s".format(
stringResource(R.string.hops_away),
if (node.hopsAway == -1) {
"?"
} else {
node.hopsAway.toString()
fun SignalInfo(modifier: Modifier = Modifier, node: Node, isThisNode: Boolean) {
val text =
if (isThisNode) {
stringResource(R.string.channel_air_util)
.format(node.deviceMetrics.channelUtilization, node.deviceMetrics.airUtilTx)
} else {
buildList {
val hopsString =
"%s: %s"
.format(
stringResource(R.string.hops_away),
if (node.hopsAway == -1) {
"?"
} else {
node.hopsAway.toString()
},
)
if (node.channel > 0) {
add("ch:${node.channel}")
}
)
if (node.channel > 0) {
add("ch:${node.channel}")
if (node.hopsAway != 0) add(hopsString)
}
if (node.hopsAway != 0) add(hopsString)
}.joinToString(" ")
}
.joinToString(" ")
}
Column {
if (text.isNotEmpty()) {
Text(
modifier = modifier,
text = text,
color = MaterialTheme.colorScheme.onSurface,
fontSize = MaterialTheme.typography.bodySmall.fontSize
fontSize = MaterialTheme.typography.bodySmall.fontSize,
)
}
/* We only know the Signal Quality from direct nodes aka 0 hop. */
@ -84,43 +82,20 @@ fun SignalInfo(
fun SignalInfoSimplePreview() {
AppTheme {
SignalInfo(
node = Node(
num = 1,
lastHeard = 0,
channel = 0,
snr = 12.5F,
rssi = -42,
hopsAway = 0
),
isThisNode = false
node = Node(num = 1, lastHeard = 0, channel = 0, snr = 12.5F, rssi = -42, hopsAway = 0),
isThisNode = false,
)
}
}
@PreviewLightDark
@Composable
fun SignalInfoPreview(
@PreviewParameter(NodePreviewParameterProvider::class)
node: Node
) {
AppTheme {
SignalInfo(
node = node,
isThisNode = false
)
}
fun SignalInfoPreview(@PreviewParameter(NodePreviewParameterProvider::class) node: Node) {
AppTheme { SignalInfo(node = node, isThisNode = false) }
}
@Composable
@PreviewLightDark
fun SignalInfoSelfPreview(
@PreviewParameter(NodePreviewParameterProvider::class)
node: Node
) {
AppTheme {
SignalInfo(
node = node,
isThisNode = true
)
}
fun SignalInfoSelfPreview(@PreviewParameter(NodePreviewParameterProvider::class) node: Node) {
AppTheme { SignalInfo(node = node, isThisNode = true) }
}

Wyświetl plik

@ -32,8 +32,8 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.strings.R
@Composable
fun SimpleAlertDialog(
@ -48,31 +48,25 @@ fun SimpleAlertDialog(
dismissButton = {
TextButton(
onClick = onDismiss,
modifier = Modifier
.padding(horizontal = 16.dp),
colors = ButtonDefaults.textButtonColors(
contentColor = MaterialTheme.colorScheme.onSurface,
),
) { Text(text = dismissText ?: stringResource(id = R.string.cancel)) }
modifier = Modifier.padding(horizontal = 16.dp),
colors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colorScheme.onSurface),
) {
Text(text = dismissText ?: stringResource(id = R.string.cancel))
}
},
confirmButton = {
onConfirm?.let {
TextButton(
onClick = onConfirm,
modifier = Modifier
.padding(horizontal = 16.dp),
colors = ButtonDefaults.textButtonColors(
contentColor = MaterialTheme.colorScheme.onSurface,
),
) { Text(text = confirmText ?: stringResource(id = R.string.okay)) }
TextButton(
onClick = onConfirm,
modifier = Modifier.padding(horizontal = 16.dp),
colors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colorScheme.onSurface),
) {
Text(text = confirmText ?: stringResource(id = R.string.okay))
}
}
},
title = {
Text(
text = stringResource(id = title),
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
)
Text(text = stringResource(id = title), modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center)
},
text = text,
shape = RoundedCornerShape(16.dp),
@ -89,11 +83,7 @@ fun SimpleAlertDialog(
onDismiss = onDismiss,
title = title,
text = {
Text(
text = stringResource(id = text),
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
)
Text(text = stringResource(id = text), modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center)
},
)
@ -107,22 +97,11 @@ fun SimpleAlertDialog(
onConfirm = onConfirm,
onDismiss = onDismiss,
title = title,
text = {
Text(
text = text,
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
)
},
text = { Text(text = text, modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center) },
)
@PreviewLightDark
@Composable
private fun SimpleAlertDialogPreview() {
AppTheme {
SimpleAlertDialog(
title = R.string.message,
text = R.string.sample_message,
)
}
AppTheme { SimpleAlertDialog(title = R.string.message, text = R.string.sample_message) }
}

Wyświetl plik

@ -60,7 +60,6 @@ import androidx.compose.ui.window.Dialog
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.ConfigProtos
import com.geeksville.mesh.R
import com.geeksville.mesh.model.BTScanModel
import com.geeksville.mesh.model.DeviceListEntry
import com.geeksville.mesh.model.Node
@ -83,6 +82,7 @@ import com.google.accompanist.permissions.ExperimentalPermissionsApi
import kotlinx.coroutines.delay
import org.meshtastic.core.navigation.Route
import org.meshtastic.core.navigation.SettingsRoutes
import org.meshtastic.core.strings.R
fun String?.isIPAddress(): Boolean = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
@Suppress("DEPRECATION")

Wyświetl plik

@ -46,7 +46,6 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.R
import com.geeksville.mesh.model.BTScanModel
import com.geeksville.mesh.model.DeviceListEntry
import com.geeksville.mesh.service.ConnectionState
@ -54,6 +53,7 @@ import com.geeksville.mesh.ui.common.components.TitledCard
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.MultiplePermissionsState
import com.google.accompanist.permissions.rememberMultiplePermissionsState
import org.meshtastic.core.strings.R
/**
* Composable that displays a list of Bluetooth Low Energy (BLE) devices and allows scanning. It handles Bluetooth

Wyświetl plik

@ -33,9 +33,9 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.connections.DeviceType
import org.meshtastic.core.strings.R
@Suppress("LambdaParameterEventTrailing")
@Composable

Wyświetl plik

@ -42,7 +42,6 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.PaxcountProtos
import com.geeksville.mesh.R
import com.geeksville.mesh.TelemetryProtos
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.ui.common.components.MaterialBatteryInfo
@ -50,6 +49,7 @@ import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusRed
import com.geeksville.mesh.ui.node.components.NodeChip
import com.geeksville.mesh.ui.node.components.NodeMenuAction
import org.meshtastic.core.strings.R
@Composable
fun CurrentlyConnectedInfo(

Wyświetl plik

@ -34,8 +34,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import com.geeksville.mesh.R
import com.geeksville.mesh.model.DeviceListEntry
import org.meshtastic.core.strings.R
@Suppress("LongMethod", "CyclomaticComplexMethod")
@Composable

Wyświetl plik

@ -51,7 +51,6 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.model.BTScanModel
import com.geeksville.mesh.model.DeviceListEntry
import com.geeksville.mesh.repository.network.NetworkRepository
@ -60,6 +59,7 @@ import com.geeksville.mesh.ui.common.components.TitledCard
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.connections.isIPAddress
import kotlinx.coroutines.launch
import org.meshtastic.core.strings.R
@OptIn(ExperimentalMaterial3Api::class)
@Suppress("MagicNumber", "LongMethod")

Wyświetl plik

@ -23,12 +23,12 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import com.geeksville.mesh.R
import com.geeksville.mesh.model.BTScanModel
import com.geeksville.mesh.model.DeviceListEntry
import com.geeksville.mesh.service.ConnectionState
import com.geeksville.mesh.ui.common.components.TitledCard
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.strings.R
@Composable
fun UsbDevices(

Wyświetl plik

@ -50,10 +50,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.AppOnlyProtos
import com.geeksville.mesh.R
import com.geeksville.mesh.model.Contact
import com.geeksville.mesh.ui.common.components.SecurityIcon
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.strings.R
@Suppress("LongMethod")
@Composable

Wyświetl plik

@ -62,11 +62,11 @@ import androidx.compose.ui.window.DialogProperties
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.AppOnlyProtos
import com.geeksville.mesh.R
import com.geeksville.mesh.model.Contact
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.ui.common.components.MainAppBar
import com.geeksville.mesh.ui.node.components.NodeMenuAction
import org.meshtastic.core.strings.R
import java.util.concurrent.TimeUnit
@OptIn(ExperimentalMaterial3ExpressiveApi::class)

Wyświetl plik

@ -78,7 +78,6 @@ import androidx.compose.ui.unit.sp
import androidx.datastore.core.IOException
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.R
import com.geeksville.mesh.android.BuildUtils.warn
import com.geeksville.mesh.model.DebugViewModel
import com.geeksville.mesh.model.DebugViewModel.UiMeshLog
@ -90,6 +89,7 @@ import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.meshtastic.core.strings.R
import java.io.OutputStreamWriter
import java.nio.charset.StandardCharsets
import java.text.SimpleDateFormat

Wyświetl plik

@ -21,6 +21,7 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
@ -28,7 +29,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Clear
@ -56,8 +56,8 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.model.DebugViewModel.UiMeshLog
import org.meshtastic.core.strings.R
@Composable
fun DebugCustomFilterInput(
@ -65,14 +65,9 @@ fun DebugCustomFilterInput(
onCustomFilterTextChange: (String) -> Unit,
filterTexts: List<String>,
onFilterTextsChange: (List<String>) -> Unit,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier
.fillMaxWidth()
.padding(bottom = 4.dp),
verticalAlignment = Alignment.CenterVertically
) {
Row(modifier = modifier.fillMaxWidth().padding(bottom = 4.dp), verticalAlignment = Alignment.CenterVertically) {
OutlinedTextField(
value = customFilterText,
onValueChange = onCustomFilterTextChange,
@ -80,14 +75,15 @@ fun DebugCustomFilterInput(
placeholder = { Text("Add custom filter") },
singleLine = true,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(
keyboardActions =
KeyboardActions(
onDone = {
if (customFilterText.isNotBlank()) {
onFilterTextsChange(filterTexts + customFilterText)
onCustomFilterTextChange("")
}
}
)
},
),
)
Spacer(modifier = Modifier.padding(horizontal = 8.dp))
IconButton(
@ -97,12 +93,9 @@ fun DebugCustomFilterInput(
onCustomFilterTextChange("")
}
},
enabled = customFilterText.isNotBlank()
enabled = customFilterText.isNotBlank(),
) {
Icon(
imageVector = Icons.Default.Add,
contentDescription = stringResource(id = R.string.debug_filter_add)
)
Icon(imageVector = Icons.Default.Add, contentDescription = stringResource(id = R.string.debug_filter_add))
}
}
}
@ -113,27 +106,26 @@ internal fun DebugPresetFilters(
filterTexts: List<String>,
logs: List<UiMeshLog>,
onFilterTextsChange: (List<String>) -> Unit,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
) {
val availableFilters = presetFilters.filter { filter ->
logs.any { log ->
log.logMessage.contains(filter, ignoreCase = true) ||
log.messageType.contains(filter, ignoreCase = true) ||
log.formattedReceivedDate.contains(filter, ignoreCase = true)
val availableFilters =
presetFilters.filter { filter ->
logs.any { log ->
log.logMessage.contains(filter, ignoreCase = true) ||
log.messageType.contains(filter, ignoreCase = true) ||
log.formattedReceivedDate.contains(filter, ignoreCase = true)
}
}
}
Column(modifier = modifier) {
Text(
text = "Preset Filters",
style = TextStyle(fontWeight = FontWeight.Bold),
modifier = Modifier.padding(vertical = 4.dp)
modifier = Modifier.padding(vertical = 4.dp),
)
FlowRow(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 0.dp),
modifier = Modifier.fillMaxWidth().padding(bottom = 0.dp),
horizontalArrangement = Arrangement.spacedBy(2.dp),
verticalArrangement = Arrangement.spacedBy(0.dp)
verticalArrangement = Arrangement.spacedBy(0.dp),
) {
for (filter in availableFilters) {
FilterChip(
@ -144,17 +136,18 @@ internal fun DebugPresetFilters(
filterTexts - filter
} else {
filterTexts + filter
}
},
)
},
label = { Text(filter) },
leadingIcon = { if (filter in filterTexts) {
Icon(
imageVector = Icons.Filled.Done,
contentDescription = stringResource(id = R.string.debug_filter_included),
)
leadingIcon = {
if (filter in filterTexts) {
Icon(
imageVector = Icons.Filled.Done,
contentDescription = stringResource(id = R.string.debug_filter_included),
)
}
}
},
)
}
}
@ -169,56 +162,46 @@ internal fun DebugFilterBar(
onCustomFilterTextChange: (String) -> Unit,
presetFilters: List<String>,
logs: List<UiMeshLog>,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
) {
var showFilterMenu by remember { mutableStateOf(false) }
Row(
modifier = modifier,
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically
verticalAlignment = Alignment.CenterVertically,
) {
Box {
TextButton(
onClick = { showFilterMenu = !showFilterMenu }
) {
Row(
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = stringResource(R.string.debug_filters),
style = TextStyle(fontWeight = FontWeight.Bold)
)
TextButton(onClick = { showFilterMenu = !showFilterMenu }) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(text = stringResource(R.string.debug_filters), style = TextStyle(fontWeight = FontWeight.Bold))
Icon(
imageVector = if (filterTexts.isNotEmpty()) {
imageVector =
if (filterTexts.isNotEmpty()) {
Icons.TwoTone.FilterAlt
} else {
Icons.TwoTone.FilterAltOff
},
contentDescription = stringResource(id = R.string.debug_filters)
contentDescription = stringResource(id = R.string.debug_filters),
)
}
}
DropdownMenu(
expanded = showFilterMenu,
onDismissRequest = { showFilterMenu = false },
offset = DpOffset(0.dp, 8.dp)
offset = DpOffset(0.dp, 8.dp),
) {
Column(
modifier = Modifier
.padding(8.dp)
.width(300.dp)
) {
Column(modifier = Modifier.padding(8.dp).width(300.dp)) {
DebugCustomFilterInput(
customFilterText = customFilterText,
onCustomFilterTextChange = onCustomFilterTextChange,
filterTexts = filterTexts,
onFilterTextsChange = onFilterTextsChange
onFilterTextsChange = onFilterTextsChange,
)
DebugPresetFilters(
presetFilters = presetFilters,
filterTexts = filterTexts,
logs = logs,
onFilterTextsChange = onFilterTextsChange
onFilterTextsChange = onFilterTextsChange,
)
}
}
@ -233,73 +216,62 @@ internal fun DebugActiveFilters(
onFilterTextsChange: (List<String>) -> Unit,
filterMode: FilterMode,
onFilterModeChange: (FilterMode) -> Unit,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
) {
val colorScheme = MaterialTheme.colorScheme
if (filterTexts.isNotEmpty()) {
Column(modifier = modifier) {
Row(
modifier = Modifier
.fillMaxWidth()
modifier =
Modifier.fillMaxWidth()
.padding(vertical = 2.dp)
.background(colorScheme.background.copy(alpha = 1.0f)),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = stringResource(R.string.debug_active_filters),
style = TextStyle(fontWeight = FontWeight.Bold)
style = TextStyle(fontWeight = FontWeight.Bold),
)
TextButton(
onClick = {
onFilterModeChange(
if (filterMode == FilterMode.OR) FilterMode.AND else FilterMode.OR
)
}
) {
Text(if (filterMode == FilterMode.OR) {
stringResource(R.string.match_any)
if (filterMode == FilterMode.OR) {
FilterMode.AND
} else {
stringResource(R.string.match_all)
}
FilterMode.OR
},
)
}
IconButton(
onClick = { onFilterTextsChange(emptyList()) }
},
) {
Text(
if (filterMode == FilterMode.OR) {
stringResource(R.string.match_any)
} else {
stringResource(R.string.match_all)
},
)
}
IconButton(onClick = { onFilterTextsChange(emptyList()) }) {
Icon(
imageVector = Icons.Default.Clear,
contentDescription = stringResource(id = R.string.debug_filter_clear)
contentDescription = stringResource(id = R.string.debug_filter_clear),
)
}
}
FlowRow(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 0.dp),
modifier = Modifier.fillMaxWidth().padding(bottom = 0.dp),
horizontalArrangement = Arrangement.spacedBy(2.dp),
verticalArrangement = Arrangement.spacedBy(0.dp)
verticalArrangement = Arrangement.spacedBy(0.dp),
) {
for (filter in filterTexts) {
FilterChip(
selected = true,
onClick = {
onFilterTextsChange(filterTexts - filter)
},
onClick = { onFilterTextsChange(filterTexts - filter) },
label = { Text(filter) },
leadingIcon = {
Icon(
imageVector = Icons.TwoTone.FilterAlt,
contentDescription = null
)
},
trailingIcon = {
Icon(
imageVector = Icons.Filled.Clear,
contentDescription = null
)
}
leadingIcon = { Icon(imageVector = Icons.TwoTone.FilterAlt, contentDescription = null) },
trailingIcon = { Icon(imageVector = Icons.Filled.Clear, contentDescription = null) },
)
}
}
@ -307,4 +279,7 @@ internal fun DebugActiveFilters(
}
}
enum class FilterMode { OR, AND }
enum class FilterMode {
OR,
AND,
}

Wyświetl plik

@ -53,12 +53,12 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import com.geeksville.mesh.R
import com.geeksville.mesh.model.DebugViewModel
import com.geeksville.mesh.model.DebugViewModel.UiMeshLog
import com.geeksville.mesh.model.LogSearchManager.SearchMatch
import com.geeksville.mesh.model.LogSearchManager.SearchState
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.strings.R
@Composable
internal fun DebugSearchNavigation(
@ -189,7 +189,7 @@ internal fun DebugSearchState(
IconButton(onClick = onExport, modifier = Modifier) {
Icon(
imageVector = Icons.Outlined.FileDownload,
contentDescription = stringResource(id = com.geeksville.mesh.R.string.debug_logs_export),
contentDescription = stringResource(id = R.string.debug_logs_export),
modifier = Modifier.size(24.dp),
)
}

Wyświetl plik

@ -34,7 +34,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import org.meshtastic.core.strings.R
/**
* Screen for explaining and guiding the user to configure critical alert settings. This screen is part of the app

Wyświetl plik

@ -26,7 +26,7 @@ import androidx.compose.material.icons.outlined.Router
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import com.geeksville.mesh.R
import org.meshtastic.core.strings.R
/**
* Screen for configuring location permissions during the app introduction. It explains why location permissions are

Wyświetl plik

@ -37,7 +37,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import org.meshtastic.core.strings.R
/**
* Screen for configuring notification permissions during the app introduction. It explains why notification permissions

Wyświetl plik

@ -43,6 +43,7 @@ import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import org.meshtastic.core.strings.R
/**
* A generic layout for screens within the app introduction flow. It typically presents a headline, a descriptive text
@ -92,7 +93,7 @@ internal fun PermissionScreenLayout(
onSkip = onSkip,
onConfigure = onConfigure,
configureButtonText = stringResource(id = configureButtonTextRes),
skipButtonText = stringResource(id = com.geeksville.mesh.R.string.skip),
skipButtonText = stringResource(id = R.string.skip),
)
},
) { innerPadding ->

Wyświetl plik

@ -39,7 +39,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import org.meshtastic.core.strings.R
/**
* The initial welcome screen for the app introduction flow. It displays a brief overview of the app's key features.

Wyświetl plik

@ -26,10 +26,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.R
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.ui.common.components.MainAppBar
import com.geeksville.mesh.ui.node.components.NodeMenuAction
import org.meshtastic.core.strings.R
@Composable
fun MapScreen(

Wyświetl plik

@ -96,7 +96,6 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.AppOnlyProtos
import com.geeksville.mesh.DataPacket
import com.geeksville.mesh.R
import com.geeksville.mesh.database.entity.QuickChatAction
import com.geeksville.mesh.model.Message
import com.geeksville.mesh.model.Node
@ -109,6 +108,7 @@ import com.geeksville.mesh.ui.node.components.NodeMenuAction
import com.geeksville.mesh.ui.sharing.SharedContactDialog
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.meshtastic.core.strings.R
import java.nio.charset.StandardCharsets
private const val MESSAGE_CHARACTER_LIMIT_BYTES = 200

Wyświetl plik

@ -48,7 +48,6 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.MessageStatus
import com.geeksville.mesh.R
import com.geeksville.mesh.database.entity.Reaction
import com.geeksville.mesh.model.Message
import com.geeksville.mesh.model.UIViewModel
@ -59,6 +58,7 @@ import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.launch
import org.meshtastic.core.strings.R
@Composable
fun DeliveryInfo(

Wyświetl plik

@ -70,13 +70,13 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.R
import com.geeksville.mesh.database.entity.QuickChatAction
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.ui.common.components.dragContainer
import com.geeksville.mesh.ui.common.components.dragDropItemsIndexed
import com.geeksville.mesh.ui.common.components.rememberDragDropState
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.strings.R
@Composable
internal fun QuickChatScreen(modifier: Modifier = Modifier, viewModel: UIViewModel = hiltViewModel()) {

Wyświetl plik

@ -40,13 +40,11 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.geeksville.mesh.MessageStatus
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.common.components.EmojiPickerDialog
import org.meshtastic.core.strings.R
@Composable
fun ReactionButton(
onSendReaction: (String) -> Unit = {},
) {
fun ReactionButton(onSendReaction: (String) -> Unit = {}) {
var showEmojiPickerDialog by remember { mutableStateOf(false) }
if (showEmojiPickerDialog) {
EmojiPickerDialog(
@ -54,54 +52,40 @@ fun ReactionButton(
showEmojiPickerDialog = false
onSendReaction(selectedEmoji)
},
onDismiss = { showEmojiPickerDialog = false }
onDismiss = { showEmojiPickerDialog = false },
)
}
IconButton(
onClick = { showEmojiPickerDialog = true },
) {
Icon(
imageVector = Icons.Default.EmojiEmotions,
contentDescription = stringResource(R.string.react),
)
IconButton(onClick = { showEmojiPickerDialog = true }) {
Icon(imageVector = Icons.Default.EmojiEmotions, contentDescription = stringResource(R.string.react))
}
}
@Composable
fun ReplyButton(
onClick: () -> Unit = {},
) = IconButton(
fun ReplyButton(onClick: () -> Unit = {}) = IconButton(
onClick = onClick,
content = {
Icon(
imageVector = Icons.AutoMirrored.Filled.Reply,
contentDescription = stringResource(R.string.reply),
)
}
Icon(imageVector = Icons.AutoMirrored.Filled.Reply, contentDescription = stringResource(R.string.reply))
},
)
@Composable
fun MessageStatusButton(
onStatusClick: () -> Unit = {},
status: MessageStatus,
fromLocal: Boolean,
) = AnimatedVisibility(visible = fromLocal) {
IconButton(
onClick = onStatusClick
) {
Icon(
imageVector = when (status) {
MessageStatus.RECEIVED -> Icons.TwoTone.HowToReg
MessageStatus.QUEUED -> Icons.TwoTone.CloudUpload
MessageStatus.DELIVERED -> Icons.TwoTone.CloudDone
MessageStatus.ENROUTE -> Icons.TwoTone.Cloud
MessageStatus.ERROR -> Icons.TwoTone.CloudOff
else -> Icons.TwoTone.Warning
},
contentDescription = stringResource(R.string.message_delivery_status),
)
fun MessageStatusButton(onStatusClick: () -> Unit = {}, status: MessageStatus, fromLocal: Boolean) =
AnimatedVisibility(visible = fromLocal) {
IconButton(onClick = onStatusClick) {
Icon(
imageVector =
when (status) {
MessageStatus.RECEIVED -> Icons.TwoTone.HowToReg
MessageStatus.QUEUED -> Icons.TwoTone.CloudUpload
MessageStatus.DELIVERED -> Icons.TwoTone.CloudDone
MessageStatus.ENROUTE -> Icons.TwoTone.Cloud
MessageStatus.ERROR -> Icons.TwoTone.CloudOff
else -> Icons.TwoTone.Warning
},
contentDescription = stringResource(R.string.message_delivery_status),
)
}
}
}
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
@ -113,16 +97,13 @@ fun MessageActions(
onSendReply: () -> Unit = {},
onStatusClick: () -> Unit = {},
) {
Row(
modifier = modifier.wrapContentSize(),
) {
Row(modifier = modifier.wrapContentSize()) {
ReactionButton { onSendReaction(it) }
ReplyButton { onSendReply() }
MessageStatusButton(
onStatusClick = onStatusClick,
status = status ?: MessageStatus.UNKNOWN,
fromLocal = isLocal
fromLocal = isLocal,
)
}
}

Wyświetl plik

@ -50,7 +50,6 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.MessageStatus
import com.geeksville.mesh.R
import com.geeksville.mesh.database.entity.Reaction
import com.geeksville.mesh.model.Message
import com.geeksville.mesh.model.Node
@ -62,6 +61,7 @@ import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.common.theme.MessageItemColors
import com.geeksville.mesh.ui.node.components.NodeChip
import com.geeksville.mesh.ui.node.components.NodeMenuAction
import org.meshtastic.core.strings.R
@Suppress("LongMethod", "CyclomaticComplexMethod")
@Composable

Wyświetl plik

@ -56,11 +56,11 @@ import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.geeksville.mesh.R
import com.geeksville.mesh.model.Environment
import com.geeksville.mesh.ui.metrics.CommonCharts.DATE_TIME_MINUTE_FORMAT
import com.geeksville.mesh.ui.metrics.CommonCharts.MAX_PERCENT_VALUE
import com.geeksville.mesh.ui.metrics.CommonCharts.MS_PER_SEC
import org.meshtastic.core.strings.R
import java.text.DateFormat
object CommonCharts {

Wyświetl plik

@ -59,7 +59,6 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.R
import com.geeksville.mesh.TelemetryProtos
import com.geeksville.mesh.TelemetryProtos.Telemetry
import com.geeksville.mesh.model.MetricsViewModel
@ -78,6 +77,7 @@ import com.geeksville.mesh.ui.metrics.CommonCharts.MS_PER_SEC
import com.geeksville.mesh.util.GraphUtil
import com.geeksville.mesh.util.GraphUtil.createPath
import com.geeksville.mesh.util.GraphUtil.plotPoint
import org.meshtastic.core.strings.R
private const val CHART_WEIGHT = 1f
private const val Y_AXIS_WEIGHT = 0.1f

Wyświetl plik

@ -40,13 +40,13 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalWindowInfo
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.TelemetryProtos.Telemetry
import com.geeksville.mesh.model.Environment
import com.geeksville.mesh.model.EnvironmentGraphingData
import com.geeksville.mesh.model.TimeFrame
import com.geeksville.mesh.util.GraphUtil.createPath
import com.geeksville.mesh.util.GraphUtil.drawPathWithGradient
import org.meshtastic.core.strings.R
private const val CHART_WEIGHT = 1f
private const val Y_AXIS_WEIGHT = 0.1f

Wyświetl plik

@ -49,7 +49,6 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.EnvironmentMetrics
import com.geeksville.mesh.R
import com.geeksville.mesh.TelemetryProtos
import com.geeksville.mesh.TelemetryProtos.Telemetry
import com.geeksville.mesh.copy
@ -62,6 +61,7 @@ import com.geeksville.mesh.ui.common.components.SlidingSelector
import com.geeksville.mesh.ui.metrics.CommonCharts.DATE_TIME_FORMAT
import com.geeksville.mesh.ui.metrics.CommonCharts.MS_PER_SEC
import com.geeksville.mesh.util.UnitConversions.celsiusToFahrenheit
import org.meshtastic.core.strings.R
@Composable
fun EnvironmentMetricsScreen(viewModel: MetricsViewModel = hiltViewModel()) {

Wyświetl plik

@ -53,12 +53,12 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.R
import com.geeksville.mesh.TelemetryProtos
import com.geeksville.mesh.model.MetricsViewModel
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.metrics.CommonCharts.DATE_TIME_FORMAT
import com.geeksville.mesh.util.formatUptime
import org.meshtastic.core.strings.R
import java.text.DecimalFormat
@OptIn(ExperimentalFoundationApi::class)

Wyświetl plik

@ -55,13 +55,13 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.PaxcountProtos
import com.geeksville.mesh.Portnums.PortNum
import com.geeksville.mesh.R
import com.geeksville.mesh.database.entity.MeshLog
import com.geeksville.mesh.model.MetricsViewModel
import com.geeksville.mesh.model.TimeFrame
import com.geeksville.mesh.ui.common.components.OptionLabel
import com.geeksville.mesh.ui.common.components.SlidingSelector
import com.geeksville.mesh.util.formatUptime
import org.meshtastic.core.strings.R
import java.text.DateFormat
import java.util.Date

Wyświetl plik

@ -63,11 +63,11 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.ConfigProtos.Config.DisplayConfig.DisplayUnits
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.R
import com.geeksville.mesh.model.MetricsViewModel
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.util.metersIn
import com.geeksville.mesh.util.toString
import org.meshtastic.core.strings.R
import java.text.DateFormat
import kotlin.time.Duration.Companion.days

Wyświetl plik

@ -59,7 +59,6 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.R
import com.geeksville.mesh.TelemetryProtos.Telemetry
import com.geeksville.mesh.model.MetricsViewModel
import com.geeksville.mesh.model.TimeFrame
@ -71,6 +70,7 @@ import com.geeksville.mesh.ui.metrics.CommonCharts.DATE_TIME_FORMAT
import com.geeksville.mesh.ui.metrics.CommonCharts.MS_PER_SEC
import com.geeksville.mesh.util.GraphUtil
import com.geeksville.mesh.util.GraphUtil.createPath
import org.meshtastic.core.strings.R
import kotlin.math.ceil
import kotlin.math.floor

Wyświetl plik

@ -57,7 +57,6 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.MeshProtos.MeshPacket
import com.geeksville.mesh.R
import com.geeksville.mesh.model.MetricsViewModel
import com.geeksville.mesh.model.TimeFrame
import com.geeksville.mesh.ui.common.components.LoraSignalIndicator
@ -67,6 +66,7 @@ import com.geeksville.mesh.ui.common.components.SnrAndRssi
import com.geeksville.mesh.ui.metrics.CommonCharts.DATE_TIME_FORMAT
import com.geeksville.mesh.ui.metrics.CommonCharts.MS_PER_SEC
import com.geeksville.mesh.util.GraphUtil.plotPoint
import org.meshtastic.core.strings.R
@Suppress("MagicNumber")
private enum class Metric(val color: Color, val min: Float, val max: Float) {

Wyświetl plik

@ -57,13 +57,13 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.R
import com.geeksville.mesh.model.MetricsViewModel
import com.geeksville.mesh.ui.common.components.SimpleAlertDialog
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.metrics.CommonCharts.MS_PER_SEC
import org.meshtastic.core.model.fullRouteDiscovery
import org.meshtastic.core.model.getTracerouteResponse
import org.meshtastic.core.strings.R
import java.text.DateFormat
@OptIn(ExperimentalFoundationApi::class)

Wyświetl plik

@ -124,7 +124,6 @@ import coil3.request.ImageRequest
import com.geeksville.mesh.ConfigProtos
import com.geeksville.mesh.DataPacket
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.R
import com.geeksville.mesh.database.entity.FirmwareRelease
import com.geeksville.mesh.database.entity.asDeviceVersion
import com.geeksville.mesh.model.DeviceVersion
@ -162,6 +161,7 @@ import org.meshtastic.core.model.DeviceHardware
import org.meshtastic.core.navigation.NodeDetailRoutes
import org.meshtastic.core.navigation.Route
import org.meshtastic.core.navigation.SettingsRoutes
import org.meshtastic.core.strings.R
private data class VectorMetricInfo(
@StringRes val label: Int,
@ -717,7 +717,12 @@ private fun ColumnScope.DeviceDetailsContent(state: MetricsState) {
} else {
stringResource(R.string.supported_by_community)
},
icon = if (isSupported) Icons.TwoTone.Verified else ImageVector.vectorResource(R.drawable.unverified),
icon =
if (isSupported) {
Icons.TwoTone.Verified
} else {
ImageVector.vectorResource(com.geeksville.mesh.R.drawable.unverified)
},
trailingText = "",
iconTint = if (isSupported) colorScheme.StatusGreen else colorScheme.StatusRed,
)
@ -731,9 +736,9 @@ fun DeviceHardwareImage(deviceHardware: DeviceHardware, modifier: Modifier = Mod
model = ImageRequest.Builder(LocalContext.current).data(imageUrl).build(),
contentScale = ContentScale.Inside,
contentDescription = deviceHardware.displayName,
placeholder = painterResource(R.drawable.hw_unknown),
error = painterResource(R.drawable.hw_unknown),
fallback = painterResource(R.drawable.hw_unknown),
placeholder = painterResource(com.geeksville.mesh.R.drawable.hw_unknown),
error = painterResource(com.geeksville.mesh.R.drawable.hw_unknown),
fallback = painterResource(com.geeksville.mesh.R.drawable.hw_unknown),
modifier = modifier.padding(16.dp),
)
}
@ -982,7 +987,7 @@ private fun EnvironmentMetrics(
DrawableMetricInfo(
R.string.dew_point,
dewPoint.toTempString(isFahrenheit),
R.drawable.ic_outlined_dew_point_24,
com.geeksville.mesh.R.drawable.ic_outlined_dew_point_24,
),
)
}
@ -991,7 +996,7 @@ private fun EnvironmentMetrics(
DrawableMetricInfo(
R.string.soil_temperature,
soilTemperature.toTempString(isFahrenheit),
R.drawable.soil_temperature,
com.geeksville.mesh.R.drawable.soil_temperature,
),
)
}
@ -1000,7 +1005,7 @@ private fun EnvironmentMetrics(
DrawableMetricInfo(
R.string.soil_moisture,
"%d%%".format(soilMoisture),
R.drawable.soil_moisture,
com.geeksville.mesh.R.drawable.soil_moisture,
),
)
}
@ -1009,7 +1014,7 @@ private fun EnvironmentMetrics(
DrawableMetricInfo(
R.string.radiation,
"%.1f µR/h".format(radiation),
R.drawable.ic_filled_radioactive_24,
com.geeksville.mesh.R.drawable.ic_filled_radioactive_24,
),
)
}

Wyświetl plik

@ -47,7 +47,6 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.DataPacket
import com.geeksville.mesh.R
import com.geeksville.mesh.model.DeviceVersion
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.UIViewModel
@ -60,6 +59,7 @@ import com.geeksville.mesh.ui.node.components.NodeMenuAction
import com.geeksville.mesh.ui.sharing.AddContactFAB
import com.geeksville.mesh.ui.sharing.SharedContactDialog
import com.geeksville.mesh.ui.sharing.supportsQrCodeSharing
import org.meshtastic.core.strings.R
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3ExpressiveApi::class)
@Suppress("LongMethod", "CyclomaticComplexMethod")

Wyświetl plik

@ -35,26 +35,18 @@ import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.util.formatAgo
@Composable
fun LastHeardInfo(
modifier: Modifier = Modifier,
lastHeard: Int,
currentTimeMillis: Long,
) {
fun LastHeardInfo(modifier: Modifier = Modifier, lastHeard: Int, currentTimeMillis: Long) {
Row(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(2.dp)
horizontalArrangement = Arrangement.spacedBy(2.dp),
) {
Icon(
modifier = Modifier.height(18.dp),
imageVector = ImageVector.vectorResource(id = R.drawable.ic_antenna_24),
contentDescription = null,
)
Text(
text = formatAgo(lastHeard, currentTimeMillis),
fontSize = MaterialTheme.typography.labelLarge.fontSize
)
Text(text = formatAgo(lastHeard, currentTimeMillis), fontSize = MaterialTheme.typography.labelLarge.fontSize)
}
}
@ -64,7 +56,7 @@ fun LastHeardInfoPreview() {
AppTheme {
LastHeardInfo(
lastHeard = (System.currentTimeMillis() / 1000).toInt() - 8600,
currentTimeMillis = System.currentTimeMillis()
currentTimeMillis = System.currentTimeMillis(),
)
}
}

Wyświetl plik

@ -56,10 +56,10 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.model.NodeSortOption
import com.geeksville.mesh.ui.common.preview.LargeFontPreview
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.strings.R
@Suppress("LongParameterList")
@Composable

Wyświetl plik

@ -51,7 +51,6 @@ import androidx.compose.ui.unit.dp
import com.geeksville.mesh.ConfigProtos.Config.DeviceConfig
import com.geeksville.mesh.ConfigProtos.Config.DisplayConfig
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.R
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.isUnmessageableRole
import com.geeksville.mesh.ui.common.components.BatteryInfo
@ -59,6 +58,7 @@ import com.geeksville.mesh.ui.common.components.SignalInfo
import com.geeksville.mesh.ui.common.preview.NodePreviewParameterProvider
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.util.toDistanceString
import org.meshtastic.core.strings.R
@Suppress("LongMethod", "CyclomaticComplexMethod")
@Composable

Wyświetl plik

@ -54,7 +54,6 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.common.components.CopyIconButton
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusGreen
@ -62,6 +61,7 @@ import com.geeksville.mesh.ui.common.theme.StatusColors.StatusRed
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusYellow
import com.google.protobuf.ByteString
import org.meshtastic.core.model.Channel
import org.meshtastic.core.strings.R
@Composable
private fun KeyStatusDialog(@StringRes title: Int, @StringRes text: Int, key: ByteString?, onDismiss: () -> Unit = {}) =
@ -129,7 +129,9 @@ fun NodeKeyStatusIcon(
when {
mismatchKey -> Icons.Default.KeyOff to colorScheme.StatusRed
hasPKC -> Icons.Default.Lock to colorScheme.StatusGreen
else -> ImageVector.vectorResource(R.drawable.ic_lock_open_right_24) to colorScheme.StatusYellow
else ->
ImageVector.vectorResource(com.geeksville.mesh.R.drawable.ic_lock_open_right_24) to
colorScheme.StatusYellow
}
IconButton(onClick = { showEncryptionDialog = true }, modifier = modifier) {

Wyświetl plik

@ -38,10 +38,10 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.isUnmessageableRole
import com.geeksville.mesh.ui.common.components.SimpleAlertDialog
import org.meshtastic.core.strings.R
@Suppress("LongMethod")
@Composable
@ -52,12 +52,13 @@ fun NodeMenu(
onDismissMenuRequest: () -> Unit,
onAction: (NodeMenuAction) -> Unit,
) {
val isUnmessageable = if (node.user.hasIsUnmessagable()) {
node.user.isUnmessagable
} else {
// for older firmwares
node.user.role?.isUnmessageableRole() == true
}
val isUnmessageable =
if (node.user.hasIsUnmessagable()) {
node.user.isUnmessagable
} else {
// for older firmwares
node.user.role?.isUnmessageableRole() == true
}
var displayFavoriteDialog by remember { mutableStateOf(false) }
var displayIgnoreDialog by remember { mutableStateOf(false) }
@ -79,14 +80,13 @@ fun NodeMenu(
displayIgnoreDialog = displayIgnoreDialog,
displayRemoveDialog = displayRemoveDialog,
onDismissMenuRequest = dialogDismissRequest,
onAction = onMenuAction
onAction = onMenuAction,
)
DropdownMenu(
modifier = Modifier.background(MaterialTheme.colorScheme.background.copy(alpha = 1f)),
expanded = expanded,
onDismissRequest = onDismissMenuRequest,
) {
if (showFullMenu) {
if (!isUnmessageable) {
DropdownMenuItem(
@ -94,7 +94,7 @@ fun NodeMenu(
dialogDismissRequest()
onMenuAction(NodeMenuAction.DirectMessage(node))
},
text = { Text(stringResource(R.string.direct_message)) }
text = { Text(stringResource(R.string.direct_message)) },
)
}
DropdownMenuItem(
@ -102,21 +102,21 @@ fun NodeMenu(
dialogDismissRequest()
onMenuAction(NodeMenuAction.RequestUserInfo(node))
},
text = { Text(stringResource(R.string.exchange_userinfo)) }
text = { Text(stringResource(R.string.exchange_userinfo)) },
)
DropdownMenuItem(
onClick = {
dialogDismissRequest()
onMenuAction(NodeMenuAction.RequestPosition(node))
},
text = { Text(stringResource(R.string.exchange_position)) }
text = { Text(stringResource(R.string.exchange_position)) },
)
DropdownMenuItem(
onClick = {
dialogDismissRequest()
onMenuAction(NodeMenuAction.TraceRoute(node))
},
text = { Text(stringResource(R.string.traceroute)) }
text = { Text(stringResource(R.string.traceroute)) },
)
DropdownMenuItem(
onClick = {
@ -124,24 +124,20 @@ fun NodeMenu(
displayFavoriteDialog = true
},
enabled = !node.isIgnored,
text = {
Text(stringResource(R.string.favorite))
},
text = { Text(stringResource(R.string.favorite)) },
trailingIcon = {
Icon(
imageVector = if (node.isFavorite) Icons.Filled.Star else Icons.TwoTone.StarBorder,
contentDescription = stringResource(R.string.favorite),
)
}
},
)
DropdownMenuItem(
onClick = {
dialogDismissRequest()
displayIgnoreDialog = true
},
text = {
Text(stringResource(R.string.ignore))
},
text = { Text(stringResource(R.string.ignore)) },
trailingIcon = {
Checkbox(
checked = node.isIgnored,
@ -151,7 +147,7 @@ fun NodeMenu(
},
modifier = Modifier.size(24.dp),
)
}
},
)
DropdownMenuItem(
onClick = {
@ -159,7 +155,7 @@ fun NodeMenu(
displayRemoveDialog = true
},
enabled = !node.isIgnored,
text = { Text(stringResource(R.string.remove)) }
text = { Text(stringResource(R.string.remove)) },
)
HorizontalDivider(Modifier.padding(vertical = 8.dp))
}
@ -168,7 +164,7 @@ fun NodeMenu(
dialogDismissRequest()
onMenuAction(NodeMenuAction.Share(node))
},
text = { Text(stringResource(R.string.share_contact)) }
text = { Text(stringResource(R.string.share_contact)) },
)
DropdownMenuItem(
@ -176,7 +172,7 @@ fun NodeMenu(
dialogDismissRequest()
onMenuAction(NodeMenuAction.MoreDetails(node))
},
text = { Text(stringResource(R.string.more_details)) }
text = { Text(stringResource(R.string.more_details)) },
)
}
}
@ -188,34 +184,36 @@ fun NodeActionDialogs(
displayIgnoreDialog: Boolean,
displayRemoveDialog: Boolean,
onDismissMenuRequest: () -> Unit,
onAction: (NodeMenuAction) -> Unit
onAction: (NodeMenuAction) -> Unit,
) {
if (displayFavoriteDialog) {
SimpleAlertDialog(
title = R.string.favorite,
text = stringResource(
text =
stringResource(
id = if (node.isFavorite) R.string.favorite_remove else R.string.favorite_add,
node.user.longName
node.user.longName,
),
onConfirm = {
onDismissMenuRequest()
onAction(NodeMenuAction.Favorite(node))
},
onDismiss = onDismissMenuRequest
onDismiss = onDismissMenuRequest,
)
}
if (displayIgnoreDialog) {
SimpleAlertDialog(
title = R.string.ignore,
text = stringResource(
text =
stringResource(
id = if (node.isIgnored) R.string.ignore_remove else R.string.ignore_add,
node.user.longName
node.user.longName,
),
onConfirm = {
onDismissMenuRequest()
onAction(NodeMenuAction.Ignore(node))
},
onDismiss = onDismissMenuRequest
onDismiss = onDismissMenuRequest,
)
}
if (displayRemoveDialog) {
@ -226,19 +224,27 @@ fun NodeActionDialogs(
onDismissMenuRequest()
onAction(NodeMenuAction.Remove(node))
},
onDismiss = onDismissMenuRequest
onDismiss = onDismissMenuRequest,
)
}
}
sealed class NodeMenuAction {
data class Remove(val node: Node) : NodeMenuAction()
data class Ignore(val node: Node) : NodeMenuAction()
data class Favorite(val node: Node) : NodeMenuAction()
data class DirectMessage(val node: Node) : NodeMenuAction()
data class RequestUserInfo(val node: Node) : NodeMenuAction()
data class RequestPosition(val node: Node) : NodeMenuAction()
data class TraceRoute(val node: Node) : NodeMenuAction()
data class MoreDetails(val node: Node) : NodeMenuAction()
data class Share(val node: Node) : NodeMenuAction()
}

Wyświetl plik

@ -39,10 +39,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusGreen
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusRed
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusYellow
import org.meshtastic.core.strings.R
@Suppress("LongMethod")
@OptIn(ExperimentalMaterial3Api::class)

Wyświetl plik

@ -34,9 +34,9 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.settings.components.SettingsItem
import org.meshtastic.core.strings.R
private const val COOL_DOWN_TIME_MS = 30000L

Wyświetl plik

@ -57,7 +57,6 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.BuildConfig
import com.geeksville.mesh.ClientOnlyProtos.DeviceProfile
import com.geeksville.mesh.R
import com.geeksville.mesh.android.gpsDisabled
import com.geeksville.mesh.navigation.getNavRouteFrom
import com.geeksville.mesh.ui.common.components.MainAppBar
@ -78,6 +77,7 @@ import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.rememberMultiplePermissionsState
import kotlinx.coroutines.delay
import org.meshtastic.core.navigation.Route
import org.meshtastic.core.strings.R
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

Wyświetl plik

@ -46,9 +46,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import com.geeksville.mesh.R
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.ui.node.components.NodeChip
import org.meshtastic.core.strings.R
/**
* Composable screen for cleaning the node database. Allows users to specify criteria for deleting nodes. The list of

Wyświetl plik

@ -42,7 +42,6 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.navigation.ConfigRoute
import com.geeksville.mesh.navigation.ModuleRoute
import com.geeksville.mesh.ui.common.components.TitledCard
@ -52,6 +51,7 @@ import com.geeksville.mesh.ui.settings.components.SettingsItem
import com.geeksville.mesh.ui.settings.radio.components.WarningDialog
import org.meshtastic.core.navigation.Route
import org.meshtastic.core.navigation.SettingsRoutes
import org.meshtastic.core.strings.R
@Suppress("LongMethod", "CyclomaticComplexMethod")
@Composable

Wyświetl plik

@ -42,7 +42,6 @@ import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.ModuleConfigProtos
import com.geeksville.mesh.Portnums
import com.geeksville.mesh.Position
import com.geeksville.mesh.R
import com.geeksville.mesh.android.GeeksvilleApplication
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.android.isAnalyticsAvailable
@ -78,6 +77,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONObject
import org.meshtastic.core.navigation.SettingsRoutes
import org.meshtastic.core.strings.R
import java.io.FileOutputStream
import javax.inject.Inject

Wyświetl plik

@ -33,7 +33,6 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.ModuleConfigProtos
import com.geeksville.mesh.R
import com.geeksville.mesh.copy
import com.geeksville.mesh.moduleConfig
import com.geeksville.mesh.ui.common.components.EditTextPreference
@ -41,6 +40,7 @@ import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.PreferenceFooter
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
@Composable
fun AmbientLightingConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) {

Wyświetl plik

@ -34,7 +34,6 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig.AudioConfig
import com.geeksville.mesh.R
import com.geeksville.mesh.copy
import com.geeksville.mesh.moduleConfig
import com.geeksville.mesh.ui.common.components.DropDownPreference
@ -43,6 +42,7 @@ import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.PreferenceFooter
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
@Composable
fun AudioConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) {

Wyświetl plik

@ -33,7 +33,6 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.ConfigProtos.Config.BluetoothConfig
import com.geeksville.mesh.R
import com.geeksville.mesh.config
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.common.components.DropDownPreference
@ -42,6 +41,7 @@ import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.PreferenceFooter
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
@Composable
fun BluetoothConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) {

Wyświetl plik

@ -36,7 +36,6 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig.CannedMessageConfig
import com.geeksville.mesh.R
import com.geeksville.mesh.copy
import com.geeksville.mesh.moduleConfig
import com.geeksville.mesh.ui.common.components.DropDownPreference
@ -45,6 +44,7 @@ import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.PreferenceFooter
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
@Composable
fun CannedMessageConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) {

Some files were not shown because too many files have changed in this diff Show More