mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
refactor(ui): Icon audit and node list item refactor (#4313)
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
parent
5db2c9d69c
commit
a28aa4d52e
91 changed files with 2178 additions and 702 deletions
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.ui.component
|
||||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.strings.Res
|
||||
import org.meshtastic.core.strings.channel
|
||||
import org.meshtastic.core.ui.icon.Channel
|
||||
import org.meshtastic.core.ui.icon.Counter0
|
||||
import org.meshtastic.core.ui.icon.Counter1
|
||||
import org.meshtastic.core.ui.icon.Counter2
|
||||
import org.meshtastic.core.ui.icon.Counter3
|
||||
import org.meshtastic.core.ui.icon.Counter4
|
||||
import org.meshtastic.core.ui.icon.Counter5
|
||||
import org.meshtastic.core.ui.icon.Counter6
|
||||
import org.meshtastic.core.ui.icon.Counter7
|
||||
import org.meshtastic.core.ui.icon.Counter8
|
||||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.core.ui.theme.AppTheme
|
||||
|
||||
@Composable
|
||||
@Suppress("MagicNumber")
|
||||
fun ChannelInfo(
|
||||
channel: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
contentColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
val icon =
|
||||
when (channel) {
|
||||
0 -> MeshtasticIcons.Counter0
|
||||
1 -> MeshtasticIcons.Counter1
|
||||
2 -> MeshtasticIcons.Counter2
|
||||
3 -> MeshtasticIcons.Counter3
|
||||
4 -> MeshtasticIcons.Counter4
|
||||
5 -> MeshtasticIcons.Counter5
|
||||
6 -> MeshtasticIcons.Counter6
|
||||
7 -> MeshtasticIcons.Counter7
|
||||
8 -> MeshtasticIcons.Counter8
|
||||
else -> MeshtasticIcons.Channel
|
||||
}
|
||||
|
||||
IconInfo(
|
||||
modifier = modifier,
|
||||
icon = icon,
|
||||
contentDescription = stringResource(Res.string.channel),
|
||||
text = stringResource(Res.string.channel),
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun ChannelInfoPreview() {
|
||||
AppTheme { ChannelInfo(channel = 2) }
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.ui.component
|
||||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.strings.Res
|
||||
import org.meshtastic.core.strings.distance
|
||||
import org.meshtastic.core.ui.icon.Distance
|
||||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.core.ui.theme.AppTheme
|
||||
|
||||
@Composable
|
||||
fun DistanceInfo(
|
||||
distance: String,
|
||||
modifier: Modifier = Modifier,
|
||||
contentColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
IconInfo(
|
||||
modifier = modifier,
|
||||
icon = MeshtasticIcons.Distance,
|
||||
contentDescription = stringResource(Res.string.distance),
|
||||
text = distance,
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun DistanceInfoPreview() {
|
||||
AppTheme { DistanceInfo(distance = "423 mi.") }
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.ui.component
|
||||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.model.util.metersIn
|
||||
import org.meshtastic.core.model.util.toString
|
||||
import org.meshtastic.core.strings.Res
|
||||
import org.meshtastic.core.strings.altitude
|
||||
import org.meshtastic.core.strings.elevation_suffix
|
||||
import org.meshtastic.core.ui.icon.Elevation
|
||||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.proto.ConfigProtos.Config.DisplayConfig.DisplayUnits
|
||||
|
||||
@Composable
|
||||
fun ElevationInfo(
|
||||
modifier: Modifier = Modifier,
|
||||
altitude: Int,
|
||||
system: DisplayUnits,
|
||||
suffix: String = stringResource(Res.string.elevation_suffix),
|
||||
contentColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
IconInfo(
|
||||
modifier = modifier,
|
||||
icon = MeshtasticIcons.Elevation,
|
||||
contentDescription = stringResource(Res.string.altitude),
|
||||
text = altitude.metersIn(system).toString(system) + " " + suffix,
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
private fun ElevationInfoPreview() {
|
||||
MaterialTheme { ElevationInfo(altitude = 100, system = DisplayUnits.METRIC, suffix = "ASL") }
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.ui.component
|
||||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.strings.Res
|
||||
import org.meshtastic.core.strings.hops_away
|
||||
import org.meshtastic.core.ui.icon.Hops
|
||||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.core.ui.theme.AppTheme
|
||||
|
||||
@Composable
|
||||
fun HopsInfo(hops: Int, modifier: Modifier = Modifier, contentColor: Color = MaterialTheme.colorScheme.onSurface) {
|
||||
IconInfo(
|
||||
modifier = modifier,
|
||||
icon = MeshtasticIcons.Hops,
|
||||
contentDescription = stringResource(Res.string.hops_away),
|
||||
text = hops.toString(),
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun HopsInfoPreview() {
|
||||
AppTheme { HopsInfo(hops = 3) }
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.ui.component
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.meshtastic.core.ui.icon.Elevation
|
||||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
|
||||
private const val SIZE_ICON = 20
|
||||
|
||||
@Composable
|
||||
fun IconInfo(
|
||||
icon: ImageVector,
|
||||
contentDescription: String,
|
||||
modifier: Modifier = Modifier,
|
||||
text: String? = null,
|
||||
style: TextStyle = MaterialTheme.typography.labelMedium,
|
||||
contentColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
content: @Composable () -> Unit = {},
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(2.dp),
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(SIZE_ICON.dp),
|
||||
imageVector = icon,
|
||||
contentDescription = contentDescription,
|
||||
tint = contentColor,
|
||||
)
|
||||
text?.let { Text(text = it, style = style, color = contentColor) }
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
private fun IconInfoPreview() {
|
||||
MaterialTheme {
|
||||
IconInfo(icon = MeshtasticIcons.Elevation, contentDescription = "Elevation", content = { Text(text = "100") })
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Meshtastic LLC
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -14,7 +14,6 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.meshtastic.core.ui.component
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
|
|
@ -31,9 +30,6 @@ import androidx.compose.foundation.layout.size
|
|||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ThumbUp
|
||||
import androidx.compose.material.icons.filled.Warning
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Icon
|
||||
|
|
@ -61,6 +57,9 @@ import org.meshtastic.core.strings.Res
|
|||
import org.meshtastic.core.strings.air_quality_icon
|
||||
import org.meshtastic.core.strings.close
|
||||
import org.meshtastic.core.strings.indoor_air_quality_iaq
|
||||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.core.ui.icon.ThumbUp
|
||||
import org.meshtastic.core.ui.icon.Warning
|
||||
import org.meshtastic.core.ui.theme.IAQColors.IAQDangerouslyPolluted
|
||||
import org.meshtastic.core.ui.theme.IAQColors.IAQExcellent
|
||||
import org.meshtastic.core.ui.theme.IAQColors.IAQExtremelyPolluted
|
||||
|
|
@ -137,7 +136,7 @@ fun IndoorAirQuality(iaq: Int?, displayMode: IaqDisplayMode = IaqDisplayMode.Pil
|
|||
Text(text = "IAQ $iaq", color = Color.White, fontWeight = FontWeight.Bold)
|
||||
Icon(
|
||||
imageVector =
|
||||
if (iaqEnum.range.first < 100) Icons.Default.ThumbUp else Icons.Filled.Warning,
|
||||
if (iaqEnum.range.first < 100) MeshtasticIcons.ThumbUp else MeshtasticIcons.Warning,
|
||||
contentDescription = stringResource(Res.string.air_quality_icon),
|
||||
tint = Color.White,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.ui.component
|
||||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.strings.Res
|
||||
import org.meshtastic.core.strings.node_sort_last_heard
|
||||
import org.meshtastic.core.ui.R
|
||||
import org.meshtastic.core.ui.theme.AppTheme
|
||||
import org.meshtastic.core.ui.util.formatAgo
|
||||
|
||||
@Composable
|
||||
fun LastHeardInfo(
|
||||
modifier: Modifier = Modifier,
|
||||
lastHeard: Int,
|
||||
contentColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
IconInfo(
|
||||
modifier = modifier,
|
||||
icon = ImageVector.vectorResource(id = R.drawable.ic_antenna_24),
|
||||
contentDescription = stringResource(Res.string.node_sort_last_heard),
|
||||
text = formatAgo(lastHeard),
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun LastHeardInfoPreview() {
|
||||
AppTheme { LastHeardInfo(lastHeard = (System.currentTimeMillis() / 1000).toInt() - 8600) }
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Meshtastic LLC
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -14,7 +14,6 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
@file:Suppress("MagicNumber")
|
||||
|
||||
package org.meshtastic.core.ui.component
|
||||
|
|
@ -29,10 +28,10 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.SignalCellular4Bar
|
||||
import androidx.compose.material.icons.filled.SignalCellularAlt
|
||||
import androidx.compose.material.icons.filled.SignalCellularAlt1Bar
|
||||
import androidx.compose.material.icons.filled.SignalCellularAlt2Bar
|
||||
import androidx.compose.material.icons.rounded.SignalCellular4Bar
|
||||
import androidx.compose.material.icons.rounded.SignalCellularAlt
|
||||
import androidx.compose.material.icons.rounded.SignalCellularAlt1Bar
|
||||
import androidx.compose.material.icons.rounded.SignalCellularAlt2Bar
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.MaterialTheme.colorScheme
|
||||
|
|
@ -72,10 +71,10 @@ enum class Quality(
|
|||
@Stable val imageVector: ImageVector,
|
||||
@Stable val color: @Composable () -> Color,
|
||||
) {
|
||||
NONE(Res.string.none_quality, Icons.Default.SignalCellularAlt1Bar, { colorScheme.StatusRed }),
|
||||
BAD(Res.string.bad, Icons.Default.SignalCellularAlt2Bar, { colorScheme.StatusOrange }),
|
||||
FAIR(Res.string.fair, Icons.Default.SignalCellularAlt, { colorScheme.StatusYellow }),
|
||||
GOOD(Res.string.good, Icons.Default.SignalCellular4Bar, { colorScheme.StatusGreen }),
|
||||
NONE(Res.string.none_quality, Icons.Rounded.SignalCellularAlt1Bar, { colorScheme.StatusRed }),
|
||||
BAD(Res.string.bad, Icons.Rounded.SignalCellularAlt2Bar, { colorScheme.StatusOrange }),
|
||||
FAIR(Res.string.fair, Icons.Rounded.SignalCellularAlt, { colorScheme.StatusYellow }),
|
||||
GOOD(Res.string.good, Icons.Rounded.SignalCellular4Bar, { colorScheme.StatusGreen }),
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Meshtastic LLC
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -14,7 +14,6 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.meshtastic.core.ui.component
|
||||
|
||||
import android.util.Base64
|
||||
|
|
@ -28,10 +27,6 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.KeyOff
|
||||
import androidx.compose.material.icons.filled.Lock
|
||||
import androidx.compose.material.icons.filled.LockOpen
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
|
|
@ -52,7 +47,6 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
|
|
@ -61,7 +55,6 @@ import com.google.protobuf.ByteString
|
|||
import org.jetbrains.compose.resources.StringResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.model.Channel
|
||||
import org.meshtastic.core.strings.R
|
||||
import org.meshtastic.core.strings.Res
|
||||
import org.meshtastic.core.strings.config_security_public_key
|
||||
import org.meshtastic.core.strings.encryption_error
|
||||
|
|
@ -74,6 +67,10 @@ import org.meshtastic.core.strings.security_icon_help_dismiss
|
|||
import org.meshtastic.core.strings.security_icon_help_show_all
|
||||
import org.meshtastic.core.strings.security_icon_help_show_less
|
||||
import org.meshtastic.core.strings.show_all_key_title
|
||||
import org.meshtastic.core.ui.icon.KeyOff
|
||||
import org.meshtastic.core.ui.icon.Lock
|
||||
import org.meshtastic.core.ui.icon.LockOpen
|
||||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.core.ui.theme.AppTheme
|
||||
import org.meshtastic.core.ui.theme.StatusColors.StatusGreen
|
||||
import org.meshtastic.core.ui.theme.StatusColors.StatusRed
|
||||
|
|
@ -106,11 +103,9 @@ fun NodeKeyStatusIcon(
|
|||
|
||||
val (icon, tint) =
|
||||
when {
|
||||
mismatchKey -> Icons.Default.KeyOff to colorScheme.StatusRed
|
||||
hasPKC -> Icons.Default.Lock to colorScheme.StatusGreen
|
||||
else ->
|
||||
ImageVector.vectorResource(org.meshtastic.core.ui.R.drawable.ic_lock_open_right_24) to
|
||||
colorScheme.StatusYellow
|
||||
mismatchKey -> MeshtasticIcons.KeyOff to colorScheme.StatusRed
|
||||
hasPKC -> MeshtasticIcons.Lock to colorScheme.StatusGreen
|
||||
else -> MeshtasticIcons.LockOpen to colorScheme.StatusYellow
|
||||
}
|
||||
|
||||
IconButton(onClick = { showEncryptionDialog = true }, modifier = modifier) {
|
||||
|
|
@ -149,7 +144,7 @@ enum class NodeKeySecurityState(
|
|||
) {
|
||||
// State for public key mismatch
|
||||
PKM(
|
||||
icon = Icons.Default.KeyOff,
|
||||
icon = MeshtasticIcons.KeyOff,
|
||||
color = { colorScheme.StatusRed },
|
||||
descriptionResId = Res.string.encryption_error,
|
||||
helpTextResId = Res.string.encryption_error_text,
|
||||
|
|
@ -158,7 +153,7 @@ enum class NodeKeySecurityState(
|
|||
|
||||
// State for public key encryption
|
||||
PKC(
|
||||
icon = Icons.Default.Lock,
|
||||
icon = MeshtasticIcons.Lock,
|
||||
color = { colorScheme.StatusGreen },
|
||||
title = Res.string.encryption_pkc,
|
||||
helpTextResId = Res.string.encryption_pkc_text,
|
||||
|
|
@ -167,7 +162,7 @@ enum class NodeKeySecurityState(
|
|||
|
||||
// State for shared key encryption
|
||||
PSK(
|
||||
icon = Icons.Default.LockOpen,
|
||||
icon = MeshtasticIcons.LockOpen,
|
||||
color = { colorScheme.StatusYellow },
|
||||
title = Res.string.encryption_psk,
|
||||
helpTextResId = Res.string.encryption_psk_text,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.ui.component
|
||||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.strings.Res
|
||||
import org.meshtastic.core.strings.sats
|
||||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.core.ui.icon.Satellites
|
||||
import org.meshtastic.core.ui.theme.AppTheme
|
||||
|
||||
@Composable
|
||||
fun SatelliteCountInfo(
|
||||
modifier: Modifier = Modifier,
|
||||
satCount: Int,
|
||||
contentColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
IconInfo(
|
||||
modifier = modifier,
|
||||
icon = MeshtasticIcons.Satellites,
|
||||
contentDescription = stringResource(Res.string.sats),
|
||||
text = "$satCount",
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun SatelliteCountInfoPreview() {
|
||||
AppTheme { SatelliteCountInfo(satCount = 5) }
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Meshtastic LLC
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -14,7 +14,6 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
@file:Suppress("TooManyFunctions")
|
||||
|
||||
package org.meshtastic.core.ui.component
|
||||
|
|
@ -30,10 +29,6 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Lock
|
||||
import androidx.compose.material.icons.filled.LockOpen
|
||||
import androidx.compose.material.icons.filled.Warning
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Badge
|
||||
import androidx.compose.material3.BadgedBox
|
||||
|
|
@ -78,6 +73,10 @@ import org.meshtastic.core.strings.security_icon_insecure_no_precise
|
|||
import org.meshtastic.core.strings.security_icon_insecure_precise_only
|
||||
import org.meshtastic.core.strings.security_icon_secure
|
||||
import org.meshtastic.core.strings.security_icon_warning_precise_mqtt
|
||||
import org.meshtastic.core.ui.icon.Lock
|
||||
import org.meshtastic.core.ui.icon.LockOpen
|
||||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.core.ui.icon.Warning
|
||||
import org.meshtastic.core.ui.theme.StatusColors.StatusGreen
|
||||
import org.meshtastic.core.ui.theme.StatusColors.StatusRed
|
||||
import org.meshtastic.core.ui.theme.StatusColors.StatusYellow
|
||||
|
|
@ -109,7 +108,7 @@ enum class SecurityState(
|
|||
) {
|
||||
/** State for a secure channel (green lock). */
|
||||
SECURE(
|
||||
icon = Icons.Filled.Lock,
|
||||
icon = MeshtasticIcons.Lock,
|
||||
color = { colorScheme.StatusGreen },
|
||||
descriptionResId = Res.string.security_icon_secure,
|
||||
helpTextResId = Res.string.security_icon_help_green_lock,
|
||||
|
|
@ -120,7 +119,7 @@ enum class SecurityState(
|
|||
* warning. (yellow open lock)
|
||||
*/
|
||||
INSECURE_NO_PRECISE(
|
||||
icon = Icons.Filled.LockOpen,
|
||||
icon = MeshtasticIcons.LockOpen,
|
||||
color = { colorScheme.StatusYellow },
|
||||
descriptionResId = Res.string.security_icon_insecure_no_precise,
|
||||
helpTextResId = Res.string.security_icon_help_yellow_open_lock,
|
||||
|
|
@ -131,7 +130,7 @@ enum class SecurityState(
|
|||
* lock)
|
||||
*/
|
||||
INSECURE_PRECISE_ONLY(
|
||||
icon = Icons.Filled.LockOpen,
|
||||
icon = MeshtasticIcons.LockOpen,
|
||||
color = { colorScheme.StatusRed },
|
||||
descriptionResId = Res.string.security_icon_insecure_precise_only,
|
||||
helpTextResId = Res.string.security_icon_help_red_open_lock,
|
||||
|
|
@ -142,11 +141,11 @@ enum class SecurityState(
|
|||
* badge).
|
||||
*/
|
||||
INSECURE_PRECISE_MQTT_WARNING(
|
||||
icon = Icons.Filled.LockOpen,
|
||||
icon = MeshtasticIcons.LockOpen,
|
||||
color = { colorScheme.StatusRed },
|
||||
descriptionResId = Res.string.security_icon_warning_precise_mqtt,
|
||||
helpTextResId = Res.string.security_icon_help_warning_precise_mqtt,
|
||||
badgeIcon = Icons.Filled.Warning,
|
||||
badgeIcon = MeshtasticIcons.Warning,
|
||||
badgeIconColor = { colorScheme.StatusYellow },
|
||||
),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Meshtastic LLC
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -14,16 +14,12 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.meshtastic.core.ui.component
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -34,12 +30,16 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
|||
import androidx.compose.ui.unit.dp
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.database.model.Node
|
||||
import org.meshtastic.core.model.util.formatUptime
|
||||
import org.meshtastic.core.strings.Res
|
||||
import org.meshtastic.core.strings.channel_air_util
|
||||
import org.meshtastic.core.strings.hops_away
|
||||
import org.meshtastic.core.strings.air_utilization
|
||||
import org.meshtastic.core.strings.channel_utilization
|
||||
import org.meshtastic.core.strings.signal
|
||||
import org.meshtastic.core.strings.signal_quality
|
||||
import org.meshtastic.core.ui.component.preview.NodePreviewParameterProvider
|
||||
import org.meshtastic.core.ui.icon.AirUtilization
|
||||
import org.meshtastic.core.ui.icon.ChannelUtilization
|
||||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.core.ui.theme.AppTheme
|
||||
|
||||
const val MAX_VALID_SNR = 100F
|
||||
|
|
@ -53,67 +53,53 @@ fun SignalInfo(
|
|||
isThisNode: Boolean,
|
||||
contentColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
val text =
|
||||
if (isThisNode) {
|
||||
stringResource(Res.string.channel_air_util)
|
||||
.format(node.deviceMetrics.channelUtilization, node.deviceMetrics.airUtilTx)
|
||||
} else {
|
||||
buildList {
|
||||
val hopsString =
|
||||
"%s: %s"
|
||||
.format(
|
||||
stringResource(Res.string.hops_away),
|
||||
if (node.hopsAway == -1) {
|
||||
"?"
|
||||
} else {
|
||||
node.hopsAway.toString()
|
||||
},
|
||||
)
|
||||
if (node.channel > 0) {
|
||||
add("ch:${node.channel}")
|
||||
}
|
||||
if (node.hopsAway != 0) add(hopsString)
|
||||
}
|
||||
.joinToString(" ")
|
||||
}
|
||||
Row(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
if (text.isNotEmpty()) {
|
||||
Text(text = text, color = contentColor, style = MaterialTheme.typography.labelSmall)
|
||||
}
|
||||
/* We only know the Signal Quality from direct nodes aka 0 hop. */
|
||||
if (node.hopsAway <= 0) {
|
||||
if (node.snr < MAX_VALID_SNR && node.rssi < MAX_VALID_RSSI) {
|
||||
val quality = determineSignalQuality(node.snr, node.rssi)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
Snr(node.snr)
|
||||
Rssi(node.rssi)
|
||||
if (isThisNode) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
IconInfo(
|
||||
icon = MeshtasticIcons.ChannelUtilization,
|
||||
contentDescription = stringResource(Res.string.channel_utilization),
|
||||
text = "%.1f%%".format(node.deviceMetrics.channelUtilization),
|
||||
contentColor = contentColor,
|
||||
)
|
||||
IconInfo(
|
||||
icon = MeshtasticIcons.AirUtilization,
|
||||
contentDescription = stringResource(Res.string.air_utilization),
|
||||
text = "%.1f%%".format(node.deviceMetrics.airUtilTx),
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
if (node.channel > 0) {
|
||||
ChannelInfo(channel = node.channel, contentColor = contentColor)
|
||||
}
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(20.dp),
|
||||
imageVector = quality.imageVector,
|
||||
contentDescription = stringResource(Res.string.signal_quality),
|
||||
tint = quality.color.invoke(),
|
||||
)
|
||||
Text(
|
||||
text = "${stringResource(Res.string.signal)} ${stringResource(quality.nameRes)}",
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = contentColor,
|
||||
maxLines = 1,
|
||||
)
|
||||
if (node.hopsAway > 0) {
|
||||
HopsInfo(hops = node.hopsAway, contentColor = contentColor)
|
||||
} else {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
if (node.snr < MAX_VALID_SNR && node.rssi < MAX_VALID_RSSI) {
|
||||
val quality = determineSignalQuality(node.snr, node.rssi)
|
||||
Snr(node.snr)
|
||||
Rssi(node.rssi)
|
||||
IconInfo(
|
||||
icon = quality.imageVector,
|
||||
contentDescription = stringResource(Res.string.signal_quality),
|
||||
contentColor = quality.color.invoke(),
|
||||
text = "${stringResource(Res.string.signal)} ${stringResource(quality.nameRes)}",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node.deviceMetrics.uptimeSeconds > 0) {
|
||||
UptimeInfo(uptime = formatUptime(node.deviceMetrics.uptimeSeconds), contentColor = contentColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
@file:Suppress("TooManyFunctions")
|
||||
|
||||
package org.meshtastic.core.ui.component
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawWithContent
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.strings.Res
|
||||
import org.meshtastic.core.strings.env_metrics_log
|
||||
import org.meshtastic.core.strings.node_id
|
||||
import org.meshtastic.core.strings.pax_metrics_log
|
||||
import org.meshtastic.core.strings.role
|
||||
import org.meshtastic.core.strings.uptime
|
||||
import org.meshtastic.core.ui.icon.AirQuality
|
||||
import org.meshtastic.core.ui.icon.ArrowCircleUp
|
||||
import org.meshtastic.core.ui.icon.HardwareModel
|
||||
import org.meshtastic.core.ui.icon.Humidity
|
||||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.core.ui.icon.NodeId
|
||||
import org.meshtastic.core.ui.icon.Paxcount
|
||||
import org.meshtastic.core.ui.icon.Power
|
||||
import org.meshtastic.core.ui.icon.Pressure
|
||||
import org.meshtastic.core.ui.icon.Role
|
||||
import org.meshtastic.core.ui.icon.Soil
|
||||
import org.meshtastic.core.ui.icon.Temperature
|
||||
|
||||
private const val SIZE_ICON = 20
|
||||
|
||||
@Composable
|
||||
fun TemperatureInfo(
|
||||
temp: String,
|
||||
modifier: Modifier = Modifier,
|
||||
contentColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
IconInfo(
|
||||
modifier = modifier,
|
||||
icon = MeshtasticIcons.Temperature,
|
||||
contentDescription = stringResource(Res.string.env_metrics_log),
|
||||
text = temp,
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HumidityInfo(
|
||||
humidity: String,
|
||||
modifier: Modifier = Modifier,
|
||||
contentColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
IconInfo(
|
||||
modifier = modifier,
|
||||
icon = MeshtasticIcons.Humidity,
|
||||
contentDescription = stringResource(Res.string.env_metrics_log),
|
||||
text = humidity,
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PressureInfo(
|
||||
pressure: String,
|
||||
modifier: Modifier = Modifier,
|
||||
contentColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
IconInfo(
|
||||
modifier = modifier,
|
||||
icon = MeshtasticIcons.Pressure,
|
||||
contentDescription = stringResource(Res.string.env_metrics_log),
|
||||
text = pressure,
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SoilTemperatureInfo(
|
||||
temp: String,
|
||||
modifier: Modifier = Modifier,
|
||||
contentColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
OverlayIconInfo(
|
||||
modifier = modifier,
|
||||
icon = MeshtasticIcons.Soil,
|
||||
overlayIcon = MeshtasticIcons.Temperature,
|
||||
contentDescription = stringResource(Res.string.env_metrics_log),
|
||||
text = temp,
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SoilMoistureInfo(
|
||||
moisture: String,
|
||||
modifier: Modifier = Modifier,
|
||||
contentColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
OverlayIconInfo(
|
||||
modifier = modifier,
|
||||
icon = MeshtasticIcons.Soil,
|
||||
overlayIcon = MeshtasticIcons.Humidity,
|
||||
contentDescription = stringResource(Res.string.env_metrics_log),
|
||||
text = moisture,
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PaxcountInfo(
|
||||
pax: String,
|
||||
modifier: Modifier = Modifier,
|
||||
contentColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
IconInfo(
|
||||
modifier = modifier,
|
||||
icon = MeshtasticIcons.Paxcount,
|
||||
contentDescription = stringResource(Res.string.pax_metrics_log),
|
||||
text = pax,
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AirQualityInfo(
|
||||
iaq: String,
|
||||
modifier: Modifier = Modifier,
|
||||
contentColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
IconInfo(
|
||||
modifier = modifier,
|
||||
icon = MeshtasticIcons.AirQuality,
|
||||
contentDescription = stringResource(Res.string.env_metrics_log),
|
||||
text = iaq,
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PowerInfo(value: String, modifier: Modifier = Modifier, contentColor: Color = MaterialTheme.colorScheme.onSurface) {
|
||||
IconInfo(
|
||||
modifier = modifier,
|
||||
icon = MeshtasticIcons.Power,
|
||||
contentDescription = stringResource(Res.string.env_metrics_log),
|
||||
text = value,
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UptimeInfo(
|
||||
uptime: String,
|
||||
modifier: Modifier = Modifier,
|
||||
contentColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
IconInfo(
|
||||
modifier = modifier,
|
||||
icon = MeshtasticIcons.ArrowCircleUp,
|
||||
contentDescription = stringResource(Res.string.uptime),
|
||||
text = uptime,
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HardwareInfo(
|
||||
hwModel: String,
|
||||
modifier: Modifier = Modifier,
|
||||
contentColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
IconInfo(
|
||||
modifier = modifier,
|
||||
icon = MeshtasticIcons.HardwareModel,
|
||||
contentDescription = "Hardware Model",
|
||||
text = hwModel,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RoleInfo(role: String, modifier: Modifier = Modifier, contentColor: Color = MaterialTheme.colorScheme.onSurface) {
|
||||
IconInfo(
|
||||
modifier = modifier,
|
||||
icon = MeshtasticIcons.Role,
|
||||
contentDescription = stringResource(Res.string.role),
|
||||
text = role,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NodeIdInfo(id: String, modifier: Modifier = Modifier, contentColor: Color = MaterialTheme.colorScheme.onSurface) {
|
||||
IconInfo(
|
||||
modifier = modifier,
|
||||
icon = MeshtasticIcons.NodeId,
|
||||
contentDescription = stringResource(Res.string.node_id),
|
||||
text = id,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Suppress("MagicNumber")
|
||||
fun OverlayIconInfo(
|
||||
icon: ImageVector,
|
||||
overlayIcon: ImageVector,
|
||||
contentDescription: String,
|
||||
modifier: Modifier = Modifier,
|
||||
text: String? = null,
|
||||
style: TextStyle = MaterialTheme.typography.labelMedium,
|
||||
contentColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(2.dp),
|
||||
) {
|
||||
val foregroundPainter = rememberVectorPainter(overlayIcon)
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = contentDescription,
|
||||
tint = contentColor,
|
||||
modifier =
|
||||
Modifier.size(SIZE_ICON.dp).drawWithContent {
|
||||
drawContent()
|
||||
val badgeSize = size.width * .5f
|
||||
with(foregroundPainter) {
|
||||
draw(size = Size(badgeSize, badgeSize), colorFilter = ColorFilter.tint(contentColor))
|
||||
}
|
||||
},
|
||||
)
|
||||
text?.let { Text(text = it, style = style, color = contentColor) }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Meshtastic LLC
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -14,7 +14,6 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.meshtastic.core.ui.component.preview
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
|
|
@ -120,6 +119,9 @@ class NodePreviewParameterProvider : PreviewParameterProvider<Node> {
|
|||
voltage = 3.7F
|
||||
current = 0.0F
|
||||
iaq = 100
|
||||
barometricPressure = 1013.25F
|
||||
soilTemperature = 28.0F
|
||||
soilMoisture = 50
|
||||
},
|
||||
paxcounter =
|
||||
paxcount {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.ui.icon
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.Reply
|
||||
import androidx.compose.material.icons.automirrored.filled.Send
|
||||
import androidx.compose.material.icons.automirrored.filled.Sort
|
||||
import androidx.compose.material.icons.rounded.Add
|
||||
import androidx.compose.material.icons.rounded.AddReaction
|
||||
import androidx.compose.material.icons.rounded.Clear
|
||||
import androidx.compose.material.icons.rounded.Close
|
||||
import androidx.compose.material.icons.rounded.CloudDownload
|
||||
import androidx.compose.material.icons.rounded.ContentCopy
|
||||
import androidx.compose.material.icons.rounded.Delete
|
||||
import androidx.compose.material.icons.rounded.Edit
|
||||
import androidx.compose.material.icons.rounded.Folder
|
||||
import androidx.compose.material.icons.rounded.MoreVert
|
||||
import androidx.compose.material.icons.rounded.Refresh
|
||||
import androidx.compose.material.icons.rounded.Save
|
||||
import androidx.compose.material.icons.rounded.Search
|
||||
import androidx.compose.material.icons.rounded.SelectAll
|
||||
import androidx.compose.material.icons.rounded.Share
|
||||
import androidx.compose.material.icons.rounded.SystemUpdate
|
||||
import androidx.compose.material.icons.rounded.ThumbUp
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
|
||||
val MeshtasticIcons.Add: ImageVector
|
||||
get() = Icons.Rounded.Add
|
||||
val MeshtasticIcons.AddReaction: ImageVector
|
||||
get() = Icons.Rounded.AddReaction
|
||||
val MeshtasticIcons.Clear: ImageVector
|
||||
get() = Icons.Rounded.Clear
|
||||
val MeshtasticIcons.Close: ImageVector
|
||||
get() = Icons.Rounded.Close
|
||||
val MeshtasticIcons.Copy: ImageVector
|
||||
get() = Icons.Rounded.ContentCopy
|
||||
val MeshtasticIcons.Delete: ImageVector
|
||||
get() = Icons.Rounded.Delete
|
||||
val MeshtasticIcons.Edit: ImageVector
|
||||
get() = Icons.Rounded.Edit
|
||||
val MeshtasticIcons.More: ImageVector
|
||||
get() = Icons.Rounded.MoreVert
|
||||
val MeshtasticIcons.Refresh: ImageVector
|
||||
get() = Icons.Rounded.Refresh
|
||||
val MeshtasticIcons.Reply: ImageVector
|
||||
get() = Icons.AutoMirrored.Filled.Reply
|
||||
val MeshtasticIcons.Save: ImageVector
|
||||
get() = Icons.Rounded.Save
|
||||
val MeshtasticIcons.Search: ImageVector
|
||||
get() = Icons.Rounded.Search
|
||||
val MeshtasticIcons.Send: ImageVector
|
||||
get() = Icons.AutoMirrored.Filled.Send
|
||||
val MeshtasticIcons.Share: ImageVector
|
||||
get() = Icons.Rounded.Share
|
||||
val MeshtasticIcons.Sort: ImageVector
|
||||
get() = Icons.AutoMirrored.Filled.Sort
|
||||
val MeshtasticIcons.CloudDownload: ImageVector
|
||||
get() = Icons.Rounded.CloudDownload
|
||||
val MeshtasticIcons.Folder: ImageVector
|
||||
get() = Icons.Rounded.Folder
|
||||
val MeshtasticIcons.SystemUpdate: ImageVector
|
||||
get() = Icons.Rounded.SystemUpdate
|
||||
val MeshtasticIcons.SelectAll: ImageVector
|
||||
get() = Icons.Rounded.SelectAll
|
||||
val MeshtasticIcons.ThumbUp: ImageVector
|
||||
get() = Icons.Rounded.ThumbUp
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.ui.icon
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import org.meshtastic.core.ui.R
|
||||
|
||||
/** These are from Material Symbols drawables. */
|
||||
val MeshtasticIcons.Counter0: ImageVector
|
||||
@Composable get() = ImageVector.vectorResource(R.drawable.counter_0_24px)
|
||||
|
||||
val MeshtasticIcons.Counter1: ImageVector
|
||||
@Composable get() = ImageVector.vectorResource(R.drawable.counter_1_24px)
|
||||
|
||||
val MeshtasticIcons.Counter2: ImageVector
|
||||
@Composable get() = ImageVector.vectorResource(R.drawable.counter_2_24px)
|
||||
|
||||
val MeshtasticIcons.Counter3: ImageVector
|
||||
@Composable get() = ImageVector.vectorResource(R.drawable.counter_3_24px)
|
||||
|
||||
val MeshtasticIcons.Counter4: ImageVector
|
||||
@Composable get() = ImageVector.vectorResource(R.drawable.counter_4_24px)
|
||||
|
||||
val MeshtasticIcons.Counter5: ImageVector
|
||||
@Composable get() = ImageVector.vectorResource(R.drawable.counter_5_24px)
|
||||
|
||||
val MeshtasticIcons.Counter6: ImageVector
|
||||
@Composable get() = ImageVector.vectorResource(R.drawable.counter_6_24px)
|
||||
|
||||
val MeshtasticIcons.Counter7: ImageVector
|
||||
@Composable get() = ImageVector.vectorResource(R.drawable.counter_7_24px)
|
||||
|
||||
val MeshtasticIcons.Counter8: ImageVector
|
||||
@Composable get() = ImageVector.vectorResource(R.drawable.counter_8_24px)
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Meshtastic LLC
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -14,15 +14,25 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.meshtastic.core.ui.icon
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Fingerprint
|
||||
import androidx.compose.material.icons.rounded.Router
|
||||
import androidx.compose.material.icons.rounded.Work
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.path
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
val MeshtasticIcons.HardwareModel: ImageVector
|
||||
get() = Icons.Rounded.Router
|
||||
val MeshtasticIcons.Role: ImageVector
|
||||
get() = Icons.Rounded.Work
|
||||
val MeshtasticIcons.NodeId: ImageVector
|
||||
get() = Icons.Rounded.Fingerprint
|
||||
|
||||
/**
|
||||
* This is from Material Symbols.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.ui.icon
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Bluetooth
|
||||
import androidx.compose.material.icons.rounded.Usb
|
||||
import androidx.compose.material.icons.rounded.Wifi
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
|
||||
val MeshtasticIcons.Bluetooth: ImageVector
|
||||
get() = Icons.Rounded.Bluetooth
|
||||
val MeshtasticIcons.Usb: ImageVector
|
||||
get() = Icons.Rounded.Usb
|
||||
val MeshtasticIcons.Wifi: ImageVector
|
||||
get() = Icons.Rounded.Wifi
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.ui.icon
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.AccountCircle
|
||||
import androidx.compose.material.icons.rounded.Group
|
||||
import androidx.compose.material.icons.rounded.Groups
|
||||
import androidx.compose.material.icons.rounded.Person
|
||||
import androidx.compose.material.icons.rounded.PersonOff
|
||||
import androidx.compose.material.icons.rounded.PersonSearch
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
|
||||
val MeshtasticIcons.Person: ImageVector
|
||||
get() = Icons.Rounded.Person
|
||||
val MeshtasticIcons.PersonOff: ImageVector
|
||||
get() = Icons.Rounded.PersonOff
|
||||
val MeshtasticIcons.Groups: ImageVector
|
||||
get() = Icons.Rounded.Groups
|
||||
val MeshtasticIcons.Group: ImageVector
|
||||
get() = Icons.Rounded.Group
|
||||
val MeshtasticIcons.AccountCircle: ImageVector
|
||||
get() = Icons.Rounded.AccountCircle
|
||||
val MeshtasticIcons.PersonSearch: ImageVector
|
||||
get() = Icons.Rounded.PersonSearch
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.ui.icon
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Fingerprint
|
||||
import androidx.compose.material.icons.rounded.KeyOff
|
||||
import androidx.compose.material.icons.rounded.Lock
|
||||
import androidx.compose.material.icons.rounded.LockOpen
|
||||
import androidx.compose.material.icons.rounded.Verified
|
||||
import androidx.compose.material.icons.rounded.Warning
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
|
||||
val MeshtasticIcons.Lock: ImageVector
|
||||
get() = Icons.Rounded.Lock
|
||||
val MeshtasticIcons.LockOpen: ImageVector
|
||||
get() = Icons.Rounded.LockOpen
|
||||
val MeshtasticIcons.Warning: ImageVector
|
||||
get() = Icons.Rounded.Warning
|
||||
val MeshtasticIcons.KeyOff: ImageVector
|
||||
get() = Icons.Rounded.KeyOff
|
||||
val MeshtasticIcons.Verified: ImageVector
|
||||
get() = Icons.Rounded.Verified
|
||||
val MeshtasticIcons.Fingerprint: ImageVector
|
||||
get() = Icons.Rounded.Fingerprint
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Meshtastic LLC
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -14,15 +14,31 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.meshtastic.core.ui.icon
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.CrueltyFree
|
||||
import androidx.compose.material.icons.rounded.Route
|
||||
import androidx.compose.material.icons.rounded.SignalCellularAlt
|
||||
import androidx.compose.material.icons.rounded.SsidChart
|
||||
import androidx.compose.material.icons.rounded.WifiChannel
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.path
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
val MeshtasticIcons.Hops: ImageVector
|
||||
get() = Icons.Rounded.CrueltyFree
|
||||
val MeshtasticIcons.Route: ImageVector
|
||||
get() = Icons.Rounded.Route
|
||||
val MeshtasticIcons.Channel: ImageVector
|
||||
get() = Icons.Rounded.WifiChannel
|
||||
val MeshtasticIcons.ChannelUtilization: ImageVector
|
||||
get() = Icons.Rounded.SignalCellularAlt
|
||||
val MeshtasticIcons.AirUtilization: ImageVector
|
||||
get() = Icons.Rounded.SsidChart
|
||||
|
||||
val MeshtasticIcons.SignalCellular0Bar: ImageVector
|
||||
get() {
|
||||
if (signalCellular0Bar != null) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.ui.icon
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.SpeakerNotes
|
||||
import androidx.compose.material.icons.automirrored.filled.VolumeOff
|
||||
import androidx.compose.material.icons.automirrored.filled.VolumeUp
|
||||
import androidx.compose.material.icons.automirrored.twotone.VolumeMute
|
||||
import androidx.compose.material.icons.automirrored.twotone.VolumeUp
|
||||
import androidx.compose.material.icons.rounded.ArrowCircleUp
|
||||
import androidx.compose.material.icons.rounded.CheckCircleOutline
|
||||
import androidx.compose.material.icons.rounded.Cloud
|
||||
import androidx.compose.material.icons.rounded.CloudOff
|
||||
import androidx.compose.material.icons.rounded.Dangerous
|
||||
import androidx.compose.material.icons.rounded.History
|
||||
import androidx.compose.material.icons.rounded.NoCell
|
||||
import androidx.compose.material.icons.rounded.SpeakerNotesOff
|
||||
import androidx.compose.material.icons.rounded.Star
|
||||
import androidx.compose.material.icons.rounded.StarBorder
|
||||
import androidx.compose.material.icons.twotone.Cloud
|
||||
import androidx.compose.material.icons.twotone.CloudDone
|
||||
import androidx.compose.material.icons.twotone.CloudOff
|
||||
import androidx.compose.material.icons.twotone.CloudSync
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
|
||||
val MeshtasticIcons.Favorite: ImageVector
|
||||
get() = Icons.Rounded.Star
|
||||
val MeshtasticIcons.NotFavorite: ImageVector
|
||||
get() = Icons.Rounded.StarBorder
|
||||
val MeshtasticIcons.Muted: ImageVector
|
||||
get() = Icons.Rounded.SpeakerNotesOff
|
||||
val MeshtasticIcons.Unmuted: ImageVector
|
||||
get() = Icons.AutoMirrored.Filled.SpeakerNotes
|
||||
val MeshtasticIcons.VolumeOff: ImageVector
|
||||
get() = Icons.AutoMirrored.Filled.VolumeOff
|
||||
val MeshtasticIcons.VolumeUp: ImageVector
|
||||
get() = Icons.AutoMirrored.Filled.VolumeUp
|
||||
val MeshtasticIcons.History: ImageVector
|
||||
get() = Icons.Rounded.History
|
||||
val MeshtasticIcons.Cloud: ImageVector
|
||||
get() = Icons.Rounded.Cloud
|
||||
val MeshtasticIcons.CloudOff: ImageVector
|
||||
get() = Icons.Rounded.CloudOff
|
||||
val MeshtasticIcons.Unmessageable: ImageVector
|
||||
get() = Icons.Rounded.NoCell
|
||||
|
||||
val MeshtasticIcons.CloudDone: ImageVector
|
||||
get() = Icons.TwoTone.CloudDone
|
||||
val MeshtasticIcons.CloudSync: ImageVector
|
||||
get() = Icons.TwoTone.CloudSync
|
||||
val MeshtasticIcons.CloudOffTwoTone: ImageVector
|
||||
get() = Icons.TwoTone.CloudOff
|
||||
val MeshtasticIcons.CloudTwoTone: ImageVector
|
||||
get() = Icons.TwoTone.Cloud
|
||||
|
||||
val MeshtasticIcons.ArrowCircleUp: ImageVector
|
||||
get() = Icons.Rounded.ArrowCircleUp
|
||||
val MeshtasticIcons.Dangerous: ImageVector
|
||||
get() = Icons.Rounded.Dangerous
|
||||
|
||||
val MeshtasticIcons.VolumeUpTwoTone: ImageVector
|
||||
get() = Icons.AutoMirrored.TwoTone.VolumeUp
|
||||
val MeshtasticIcons.VolumeMuteTwoTone: ImageVector
|
||||
get() = Icons.AutoMirrored.TwoTone.VolumeMute
|
||||
|
||||
val MeshtasticIcons.CheckCircle: ImageVector
|
||||
get() = Icons.Rounded.CheckCircleOutline
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.ui.icon
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Air
|
||||
import androidx.compose.material.icons.rounded.DataArray
|
||||
import androidx.compose.material.icons.rounded.ElectricBolt
|
||||
import androidx.compose.material.icons.rounded.Grass
|
||||
import androidx.compose.material.icons.rounded.People
|
||||
import androidx.compose.material.icons.rounded.SocialDistance
|
||||
import androidx.compose.material.icons.rounded.Speed
|
||||
import androidx.compose.material.icons.rounded.StackedLineChart
|
||||
import androidx.compose.material.icons.rounded.Thermostat
|
||||
import androidx.compose.material.icons.rounded.WaterDrop
|
||||
import androidx.compose.material.icons.twotone.SatelliteAlt
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
|
||||
val MeshtasticIcons.Temperature: ImageVector
|
||||
get() = Icons.Rounded.Thermostat
|
||||
val MeshtasticIcons.Humidity: ImageVector
|
||||
get() = Icons.Rounded.WaterDrop
|
||||
val MeshtasticIcons.Pressure: ImageVector
|
||||
get() = Icons.Rounded.Speed
|
||||
val MeshtasticIcons.Soil: ImageVector
|
||||
get() = Icons.Rounded.Grass
|
||||
val MeshtasticIcons.Paxcount: ImageVector
|
||||
get() = Icons.Rounded.People
|
||||
val MeshtasticIcons.AirQuality: ImageVector
|
||||
get() = Icons.Rounded.Air
|
||||
val MeshtasticIcons.Power: ImageVector
|
||||
get() = Icons.Rounded.ElectricBolt
|
||||
val MeshtasticIcons.Distance: ImageVector
|
||||
get() = Icons.Rounded.SocialDistance
|
||||
val MeshtasticIcons.Satellites: ImageVector
|
||||
get() = Icons.TwoTone.SatelliteAlt
|
||||
val MeshtasticIcons.DataArray: ImageVector
|
||||
get() = Icons.Rounded.DataArray
|
||||
val MeshtasticIcons.Speed: ImageVector
|
||||
get() = Icons.Rounded.Speed
|
||||
val MeshtasticIcons.Chart: ImageVector
|
||||
get() = Icons.Rounded.StackedLineChart
|
||||
5
core/ui/src/main/res/drawable/counter_0_24px.xml
Normal file
5
core/ui/src/main/res/drawable/counter_0_24px.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,346 707,253Q614,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480ZM440,680L520,680Q553,680 576.5,656.5Q600,633 600,600L600,360Q600,327 576.5,303.5Q553,280 520,280L440,280Q407,280 383.5,303.5Q360,327 360,360L360,600Q360,633 383.5,656.5Q407,680 440,680ZM440,360L520,360Q520,360 520,360Q520,360 520,360L520,600Q520,600 520,600Q520,600 520,600L440,600Q440,600 440,600Q440,600 440,600L440,360Q440,360 440,360Q440,360 440,360Z"/>
|
||||
|
||||
</vector>
|
||||
5
core/ui/src/main/res/drawable/counter_1_24px.xml
Normal file
5
core/ui/src/main/res/drawable/counter_1_24px.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,346 707,253Q614,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480ZM460,360L460,640Q460,657 471.5,668.5Q483,680 500,680Q517,680 528.5,668.5Q540,657 540,640L540,320Q540,303 528.5,291.5Q517,280 500,280L420,280Q403,280 391.5,291.5Q380,303 380,320Q380,337 391.5,348.5Q403,360 420,360L460,360Z"/>
|
||||
|
||||
</vector>
|
||||
5
core/ui/src/main/res/drawable/counter_2_24px.xml
Normal file
5
core/ui/src/main/res/drawable/counter_2_24px.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,346 707,253Q614,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480ZM560,680Q577,680 588.5,668.5Q600,657 600,640Q600,623 588.5,611.5Q577,600 560,600L440,600L440,520Q440,520 440,520Q440,520 440,520L520,520Q553,520 576.5,496.5Q600,473 600,440L600,360Q600,327 576.5,303.5Q553,280 520,280L400,280Q383,280 371.5,291.5Q360,303 360,320Q360,337 371.5,348.5Q383,360 400,360L520,360Q520,360 520,360Q520,360 520,360L520,440Q520,440 520,440Q520,440 520,440L440,440Q407,440 383.5,463.5Q360,487 360,520L360,640Q360,657 371.5,668.5Q383,680 400,680L560,680Z"/>
|
||||
|
||||
</vector>
|
||||
5
core/ui/src/main/res/drawable/counter_3_24px.xml
Normal file
5
core/ui/src/main/res/drawable/counter_3_24px.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,346 707,253Q614,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480ZM400,680L520,680Q553,680 576.5,656.5Q600,633 600,600L600,540Q600,514 583,497Q566,480 540,480Q566,480 583,463Q600,446 600,420L600,360Q600,327 576.5,303.5Q553,280 520,280L400,280Q383,280 371.5,291.5Q360,303 360,320Q360,337 371.5,348.5Q383,360 400,360L520,360Q520,360 520,360Q520,360 520,360L520,440Q520,440 520,440Q520,440 520,440L480,440Q463,440 451.5,451.5Q440,463 440,480Q440,497 451.5,508.5Q463,520 480,520L520,520Q520,520 520,520Q520,520 520,520L520,600Q520,600 520,600Q520,600 520,600L400,600Q383,600 371.5,611.5Q360,623 360,640Q360,657 371.5,668.5Q383,680 400,680Z"/>
|
||||
|
||||
</vector>
|
||||
22
core/ui/src/main/res/drawable/counter_4_24px.xml
Normal file
22
core/ui/src/main/res/drawable/counter_4_24px.xml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<!--
|
||||
~ Copyright (c) 2025 Meshtastic LLC
|
||||
~
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,346 707,253Q614,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480ZM520,680L600,680L600,280L520,280L520,440L440,440L440,280L360,280L360,520L520,520L520,680Z"/>
|
||||
|
||||
</vector>
|
||||
5
core/ui/src/main/res/drawable/counter_5_24px.xml
Normal file
5
core/ui/src/main/res/drawable/counter_5_24px.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,346 707,253Q614,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480ZM400,680L520,680Q553,680 576.5,656.5Q600,633 600,600L600,520Q600,487 576.5,463.5Q553,440 520,440L440,440L440,360L560,360Q577,360 588.5,348.5Q600,337 600,320Q600,303 588.5,291.5Q577,280 560,280L400,280Q383,280 371.5,291.5Q360,303 360,320L360,480Q360,497 371.5,508.5Q383,520 400,520L520,520Q520,520 520,520Q520,520 520,520L520,600Q520,600 520,600Q520,600 520,600L400,600Q383,600 371.5,611.5Q360,623 360,640Q360,657 371.5,668.5Q383,680 400,680Z"/>
|
||||
|
||||
</vector>
|
||||
5
core/ui/src/main/res/drawable/counter_6_24px.xml
Normal file
5
core/ui/src/main/res/drawable/counter_6_24px.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,346 707,253Q614,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480ZM440,680L520,680Q553,680 576.5,656.5Q600,633 600,600L600,520Q600,487 576.5,463.5Q553,440 520,440L440,440L440,360Q440,360 440,360Q440,360 440,360L520,360Q537,360 548.5,348.5Q560,337 560,320Q560,303 548.5,291.5Q537,280 520,280L440,280Q407,280 383.5,303.5Q360,327 360,360L360,600Q360,633 383.5,656.5Q407,680 440,680ZM440,520L520,520Q520,520 520,520Q520,520 520,520L520,600Q520,600 520,600Q520,600 520,600L440,600Q440,600 440,600Q440,600 440,600L440,520Z"/>
|
||||
|
||||
</vector>
|
||||
5
core/ui/src/main/res/drawable/counter_7_24px.xml
Normal file
5
core/ui/src/main/res/drawable/counter_7_24px.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M520,360L452,632Q447,650 459,665Q471,680 490,680Q504,680 514,672Q524,664 527,651L598,370Q600,365 600,361Q600,357 600,352Q600,323 579.5,301.5Q559,280 530,280L400,280Q383,280 371.5,291.5Q360,303 360,320Q360,337 371.5,348.5Q383,360 400,360L520,360ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,346 707,253Q614,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Z"/>
|
||||
|
||||
</vector>
|
||||
5
core/ui/src/main/res/drawable/counter_8_24px.xml
Normal file
5
core/ui/src/main/res/drawable/counter_8_24px.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,346 707,253Q614,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480ZM440,680L520,680Q553,680 576.5,656.5Q600,633 600,600L600,540Q600,515 582.5,497.5Q565,480 540,480Q565,480 582.5,462.5Q600,445 600,420L600,360Q600,327 576.5,303.5Q553,280 520,280L440,280Q407,280 383.5,303.5Q360,327 360,360L360,420Q360,445 377.5,462.5Q395,480 420,480Q395,480 377.5,497.5Q360,515 360,540L360,600Q360,633 383.5,656.5Q407,680 440,680ZM440,360L520,360Q520,360 520,360Q520,360 520,360L520,440Q520,440 520,440Q520,440 520,440L440,440Q440,440 440,440Q440,440 440,440L440,360Q440,360 440,360Q440,360 440,360ZM440,600Q440,600 440,600Q440,600 440,600L440,520Q440,520 440,520Q440,520 440,520L520,520Q520,520 520,520Q520,520 520,520L520,600Q520,600 520,600Q520,600 520,600L440,600Z"/>
|
||||
|
||||
</vector>
|
||||
Loading…
Add table
Add a link
Reference in a new issue