mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
feat: settings rework part 2, domain and usecase abstraction, tests (#4680)
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
parent
5f31df96d8
commit
8c6bd8ab7a
121 changed files with 5245 additions and 1332 deletions
|
|
@ -208,6 +208,10 @@ constructor(
|
|||
onDisconnected(state)
|
||||
}
|
||||
}
|
||||
.catch { e ->
|
||||
Logger.w(e) { "[$address] bleConnection.connectionState flow crashed!" }
|
||||
service.onDisconnect(BleError.from(e))
|
||||
}
|
||||
.launchIn(connectionScope)
|
||||
|
||||
val p = retryBleOperation(tag = address) { findPeripheral() }
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import kotlinx.coroutines.flow.SharedFlow
|
|||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -47,9 +48,9 @@ import org.meshtastic.core.common.util.nowMillis
|
|||
import org.meshtastic.core.common.util.toRemoteExceptions
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
import org.meshtastic.core.di.ProcessLifecycle
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.model.util.anonymize
|
||||
import org.meshtastic.core.prefs.radio.RadioPrefs
|
||||
import org.meshtastic.core.service.ConnectionState
|
||||
import org.meshtastic.proto.Heartbeat
|
||||
import org.meshtastic.proto.ToRadio
|
||||
import javax.inject.Inject
|
||||
|
|
@ -127,6 +128,7 @@ constructor(
|
|||
stopInterface()
|
||||
}
|
||||
}
|
||||
.catch { Logger.e(it) { "bluetoothRepository.state flow crashed!" } }
|
||||
.launchIn(processLifecycle.coroutineScope)
|
||||
|
||||
networkRepository.networkAvailable
|
||||
|
|
@ -137,6 +139,7 @@ constructor(
|
|||
stopInterface()
|
||||
}
|
||||
}
|
||||
.catch { Logger.e(it) { "networkRepository.networkAvailable flow crashed!" } }
|
||||
.launchIn(processLifecycle.coroutineScope)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ package com.geeksville.mesh.service
|
|||
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import org.meshtastic.core.service.ConnectionState
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
|
|
|||
|
|
@ -30,12 +30,12 @@ import okio.ByteString.Companion.toByteString
|
|||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.common.util.nowSeconds
|
||||
import org.meshtastic.core.data.repository.RadioConfigRepository
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.core.model.MessageStatus
|
||||
import org.meshtastic.core.model.Position
|
||||
import org.meshtastic.core.model.TelemetryType
|
||||
import org.meshtastic.core.model.util.isWithinSizeLimit
|
||||
import org.meshtastic.core.service.ConnectionState
|
||||
import org.meshtastic.proto.AdminMessage
|
||||
import org.meshtastic.proto.ChannelSet
|
||||
import org.meshtastic.proto.Constants
|
||||
|
|
@ -47,7 +47,6 @@ import org.meshtastic.proto.NeighborInfo
|
|||
import org.meshtastic.proto.PortNum
|
||||
import org.meshtastic.proto.Telemetry
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import javax.inject.Inject
|
||||
|
|
@ -68,7 +67,6 @@ constructor(
|
|||
private var scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
private val currentPacketId = AtomicLong(java.util.Random(nowMillis).nextLong().absoluteValue)
|
||||
private val sessionPasskey = AtomicReference(ByteString.EMPTY)
|
||||
private val offlineSentPackets = CopyOnWriteArrayList<DataPacket>()
|
||||
val tracerouteStartTimes = ConcurrentHashMap<Int, Long>()
|
||||
val neighborInfoStartTimes = ConcurrentHashMap<Int, Long>()
|
||||
|
||||
|
|
@ -77,17 +75,6 @@ constructor(
|
|||
|
||||
@Volatile var lastNeighborInfo: NeighborInfo? = null
|
||||
|
||||
private val rememberDataType =
|
||||
setOf(
|
||||
PortNum.TEXT_MESSAGE_APP.value,
|
||||
PortNum.ALERT_APP.value,
|
||||
PortNum.WAYPOINT_APP.value,
|
||||
PortNum.ATAK_PLUGIN.value,
|
||||
PortNum.ATAK_FORWARDER.value,
|
||||
PortNum.DETECTION_SENSOR_APP.value,
|
||||
PortNum.PRIVATE_APP.value,
|
||||
)
|
||||
|
||||
fun start(scope: CoroutineScope) {
|
||||
this.scope = scope
|
||||
radioConfigRepository?.localConfigFlow?.onEach { localConfig.value = it }?.launchIn(scope)
|
||||
|
|
@ -154,14 +141,9 @@ constructor(
|
|||
}
|
||||
|
||||
if (connectionStateHolder?.connectionState?.value == ConnectionState.Connected) {
|
||||
try {
|
||||
sendNow(p)
|
||||
} catch (@Suppress("TooGenericExceptionCaught") ex: Exception) {
|
||||
Logger.e(ex) { "Error sending message, so enqueueing" }
|
||||
enqueueForSending(p)
|
||||
}
|
||||
sendNow(p)
|
||||
} else {
|
||||
enqueueForSending(p)
|
||||
error("Radio is not connected")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -185,25 +167,6 @@ constructor(
|
|||
packetHandler?.sendToRadio(meshPacket)
|
||||
}
|
||||
|
||||
private fun enqueueForSending(p: DataPacket) {
|
||||
if (p.dataType in rememberDataType) {
|
||||
offlineSentPackets.add(p)
|
||||
}
|
||||
}
|
||||
|
||||
fun processQueuedPackets() {
|
||||
val sentPackets = mutableListOf<DataPacket>()
|
||||
offlineSentPackets.forEach { p ->
|
||||
try {
|
||||
sendNow(p)
|
||||
sentPackets.add(p)
|
||||
} catch (@Suppress("TooGenericExceptionCaught") ex: Exception) {
|
||||
Logger.e(ex) { "Error sending queued message:" }
|
||||
}
|
||||
}
|
||||
offlineSentPackets.removeAll(sentPackets)
|
||||
}
|
||||
|
||||
fun sendAdmin(
|
||||
destNum: Int,
|
||||
requestId: Int = generatePacketId(),
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import org.meshtastic.core.data.repository.NodeRepository
|
|||
import org.meshtastic.core.data.repository.RadioConfigRepository
|
||||
import org.meshtastic.core.database.entity.MetadataEntity
|
||||
import org.meshtastic.core.database.entity.MyNodeEntity
|
||||
import org.meshtastic.core.service.ConnectionState
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.proto.DeviceMetadata
|
||||
import org.meshtastic.proto.HardwareModel
|
||||
import org.meshtastic.proto.Heartbeat
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ package com.geeksville.mesh.service
|
|||
import android.app.Notification
|
||||
import android.content.Context
|
||||
import androidx.glance.appwidget.updateAll
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.workDataOf
|
||||
import co.touchlab.kermit.Logger
|
||||
import com.geeksville.mesh.repository.radio.RadioInterfaceService
|
||||
import com.geeksville.mesh.widget.LocalStatsWidget
|
||||
|
|
@ -40,7 +44,9 @@ import org.meshtastic.core.common.util.handledLaunch
|
|||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.common.util.nowSeconds
|
||||
import org.meshtastic.core.data.repository.NodeRepository
|
||||
import org.meshtastic.core.data.repository.PacketRepository
|
||||
import org.meshtastic.core.data.repository.RadioConfigRepository
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.model.TelemetryType
|
||||
import org.meshtastic.core.prefs.ui.UiPrefs
|
||||
import org.meshtastic.core.resources.Res
|
||||
|
|
@ -50,8 +56,8 @@ import org.meshtastic.core.resources.device_sleeping
|
|||
import org.meshtastic.core.resources.disconnected
|
||||
import org.meshtastic.core.resources.getString
|
||||
import org.meshtastic.core.resources.meshtastic_app_name
|
||||
import org.meshtastic.core.service.ConnectionState
|
||||
import org.meshtastic.core.service.MeshServiceNotifications
|
||||
import org.meshtastic.feature.messaging.domain.worker.SendMessageWorker
|
||||
import org.meshtastic.proto.AdminMessage
|
||||
import org.meshtastic.proto.Config
|
||||
import org.meshtastic.proto.Telemetry
|
||||
|
|
@ -82,6 +88,8 @@ constructor(
|
|||
private val commandSender: MeshCommandSender,
|
||||
private val nodeManager: MeshNodeManager,
|
||||
private val analytics: PlatformAnalytics,
|
||||
private val packetRepository: PacketRepository,
|
||||
private val workManager: WorkManager,
|
||||
) {
|
||||
private var scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
private var sleepTimeout: Job? = null
|
||||
|
|
@ -255,7 +263,25 @@ constructor(
|
|||
}
|
||||
|
||||
fun onRadioConfigLoaded() {
|
||||
commandSender.processQueuedPackets()
|
||||
scope.handledLaunch {
|
||||
val queuedPackets = packetRepository.getQueuedPackets() ?: emptyList()
|
||||
queuedPackets.forEach { packet ->
|
||||
try {
|
||||
val workRequest =
|
||||
OneTimeWorkRequestBuilder<SendMessageWorker>()
|
||||
.setInputData(workDataOf(SendMessageWorker.KEY_PACKET_ID to packet.id))
|
||||
.build()
|
||||
|
||||
workManager.enqueueUniqueWork(
|
||||
"${SendMessageWorker.WORK_NAME_PREFIX}${packet.id}",
|
||||
ExistingWorkPolicy.REPLACE,
|
||||
workRequest,
|
||||
)
|
||||
} catch (@Suppress("TooGenericExceptionCaught") e: Exception) {
|
||||
Logger.e(e) { "Failed to enqueue queued packet worker" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val myNodeNum = nodeManager.myNodeNum ?: 0
|
||||
// Set time
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ constructor(
|
|||
private val logInsertJobByPacketId = ConcurrentHashMap<Int, Job>()
|
||||
|
||||
private val earlyReceivedPackets = ArrayDeque<MeshPacket>()
|
||||
private val maxEarlyPacketBuffer = 128
|
||||
private val maxEarlyPacketBuffer = 10240
|
||||
|
||||
fun clearEarlyPackets() {
|
||||
synchronized(earlyReceivedPackets) { earlyReceivedPackets.clear() }
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ constructor(
|
|||
|
||||
fun loadCachedNodeDB() {
|
||||
scope.handledLaunch {
|
||||
val nodes = nodeRepository?.getNodeDBbyNum()?.first() ?: emptyMap()
|
||||
val nodes = nodeRepository?.getNodeEntityDBbyNumFlow()?.first() ?: emptyMap()
|
||||
nodeDBbyNodeNum.putAll(nodes)
|
||||
nodes.values.forEach { nodeDBbyID[it.user.id] = it }
|
||||
myNodeNum = nodeRepository?.myNodeInfo?.value?.myNodeNum
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@ import android.content.Intent
|
|||
import android.os.Parcelable
|
||||
import co.touchlab.kermit.Logger
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.core.model.MessageStatus
|
||||
import org.meshtastic.core.model.NodeInfo
|
||||
import org.meshtastic.core.model.util.toPIIString
|
||||
import org.meshtastic.core.service.ConnectionState
|
||||
import org.meshtastic.core.service.ServiceRepository
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ constructor(
|
|||
if (myNodeNum != null) {
|
||||
// We use runBlocking here because this is called from MeshConnectionManager's synchronous methods,
|
||||
// and we only do this once if the cache is empty.
|
||||
val nodes = runBlocking { repo.getNodeDBbyNum().first() }
|
||||
val nodes = runBlocking { repo.getNodeEntityDBbyNumFlow().first() }
|
||||
nodes[myNodeNum]?.let { entity ->
|
||||
if (cachedDeviceMetrics == null) {
|
||||
cachedDeviceMetrics = entity.deviceTelemetry.device_metrics
|
||||
|
|
|
|||
|
|
@ -32,11 +32,11 @@ import org.meshtastic.core.common.util.nowMillis
|
|||
import org.meshtastic.core.data.repository.MeshLogRepository
|
||||
import org.meshtastic.core.data.repository.PacketRepository
|
||||
import org.meshtastic.core.database.entity.MeshLog
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.core.model.MessageStatus
|
||||
import org.meshtastic.core.model.util.toOneLineString
|
||||
import org.meshtastic.core.model.util.toPIIString
|
||||
import org.meshtastic.core.service.ConnectionState
|
||||
import org.meshtastic.proto.FromRadio
|
||||
import org.meshtastic.proto.MeshPacket
|
||||
import org.meshtastic.proto.QueueStatus
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ import no.nordicsemi.android.common.permissions.notification.RequestNotification
|
|||
import org.jetbrains.compose.resources.StringResource
|
||||
import org.jetbrains.compose.resources.getString
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.model.DeviceVersion
|
||||
import org.meshtastic.core.navigation.ConnectionsRoutes
|
||||
import org.meshtastic.core.navigation.ContactsRoutes
|
||||
|
|
@ -123,7 +124,6 @@ import org.meshtastic.core.resources.should_update
|
|||
import org.meshtastic.core.resources.should_update_firmware
|
||||
import org.meshtastic.core.resources.traceroute
|
||||
import org.meshtastic.core.resources.view_on_map
|
||||
import org.meshtastic.core.service.ConnectionState
|
||||
import org.meshtastic.core.ui.component.MeshtasticDialog
|
||||
import org.meshtastic.core.ui.component.ScrollToTopEvent
|
||||
import org.meshtastic.core.ui.icon.Conversations
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ import com.geeksville.mesh.ui.connections.components.UsbDevices
|
|||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import org.jetbrains.compose.resources.getString
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.navigation.Route
|
||||
import org.meshtastic.core.navigation.SettingsRoutes
|
||||
import org.meshtastic.core.resources.Res
|
||||
|
|
@ -71,7 +72,6 @@ import org.meshtastic.core.resources.must_set_region
|
|||
import org.meshtastic.core.resources.no_device_selected
|
||||
import org.meshtastic.core.resources.not_connected
|
||||
import org.meshtastic.core.resources.set_your_region
|
||||
import org.meshtastic.core.service.ConnectionState
|
||||
import org.meshtastic.core.ui.component.ListItem
|
||||
import org.meshtastic.core.ui.component.MainAppBar
|
||||
import org.meshtastic.core.ui.component.TitledCard
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@ import no.nordicsemi.android.common.scanner.view.ScannerView
|
|||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.ble.MeshtasticBleConstants.BLE_NAME_PATTERN
|
||||
import org.meshtastic.core.ble.MeshtasticBleConstants.SERVICE_UUID
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.bluetooth_available_devices
|
||||
import org.meshtastic.core.service.ConnectionState
|
||||
|
||||
/**
|
||||
* Composable that displays a list of Bluetooth Low Energy (BLE) devices and allows scanning. It handles Bluetooth
|
||||
|
|
|
|||
|
|
@ -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 com.geeksville.mesh.ui.connections.components
|
||||
|
||||
import androidx.compose.animation.Crossfade
|
||||
|
|
@ -39,7 +38,7 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import com.geeksville.mesh.ui.connections.DeviceType
|
||||
import org.meshtastic.core.service.ConnectionState
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.ui.icon.Device
|
||||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.core.ui.icon.NoDevice
|
||||
|
|
|
|||
|
|
@ -56,12 +56,12 @@ import com.geeksville.mesh.model.DeviceListEntry
|
|||
import kotlinx.coroutines.delay
|
||||
import no.nordicsemi.android.common.ui.view.RssiIcon
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.add
|
||||
import org.meshtastic.core.resources.bluetooth
|
||||
import org.meshtastic.core.resources.network
|
||||
import org.meshtastic.core.resources.serial
|
||||
import org.meshtastic.core.service.ConnectionState
|
||||
import org.meshtastic.core.ui.component.NodeChip
|
||||
|
||||
private const val RSSI_UPDATE_RATE_MS = 2000L
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.geeksville.mesh.model.DeviceListEntry
|
||||
import org.meshtastic.core.service.ConnectionState
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
|
||||
@Composable
|
||||
fun List<DeviceListEntry>.DeviceListSection(
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ import com.geeksville.mesh.ui.connections.ScannerViewModel
|
|||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.common.util.isValidAddress
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.add_network_device
|
||||
import org.meshtastic.core.resources.address
|
||||
|
|
@ -63,7 +64,6 @@ import org.meshtastic.core.resources.forget_connection
|
|||
import org.meshtastic.core.resources.ip_port
|
||||
import org.meshtastic.core.resources.no_network_devices
|
||||
import org.meshtastic.core.resources.recent_network_devices
|
||||
import org.meshtastic.core.service.ConnectionState
|
||||
import org.meshtastic.core.ui.component.MeshtasticResourceDialog
|
||||
import org.meshtastic.core.ui.theme.AppTheme
|
||||
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ import androidx.compose.ui.unit.dp
|
|||
import com.geeksville.mesh.model.DeviceListEntry
|
||||
import com.geeksville.mesh.ui.connections.ScannerViewModel
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.no_usb_devices
|
||||
import org.meshtastic.core.service.ConnectionState
|
||||
|
||||
@Composable
|
||||
fun UsbDevices(
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ import kotlinx.coroutines.launch
|
|||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.common.util.toPlatformUri
|
||||
import org.meshtastic.core.model.Channel
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.model.util.getChannelUrl
|
||||
import org.meshtastic.core.model.util.qrCode
|
||||
import org.meshtastic.core.navigation.Route
|
||||
|
|
@ -88,7 +89,6 @@ import org.meshtastic.core.resources.replace
|
|||
import org.meshtastic.core.resources.reset
|
||||
import org.meshtastic.core.resources.reset_to_defaults
|
||||
import org.meshtastic.core.resources.share_channels_qr
|
||||
import org.meshtastic.core.service.ConnectionState
|
||||
import org.meshtastic.core.ui.component.AdaptiveTwoPane
|
||||
import org.meshtastic.core.ui.component.ChannelSelection
|
||||
import org.meshtastic.core.ui.component.MainAppBar
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ import dagger.hilt.android.EntryPointAccessors
|
|||
import dagger.hilt.components.SingletonComponent
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.common.util.DateFormatter
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.model.util.formatUptime
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.air_utilization
|
||||
|
|
@ -92,7 +93,6 @@ import org.meshtastic.core.resources.powered
|
|||
import org.meshtastic.core.resources.refresh
|
||||
import org.meshtastic.core.resources.updated
|
||||
import org.meshtastic.core.resources.uptime
|
||||
import org.meshtastic.core.service.ConnectionState
|
||||
|
||||
class LocalStatsWidget : GlanceAppWidget() {
|
||||
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ import kotlinx.coroutines.flow.stateIn
|
|||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.data.repository.NodeRepository
|
||||
import org.meshtastic.core.database.model.Node
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.model.util.onlineTimeThreshold
|
||||
import org.meshtastic.core.service.ConnectionState
|
||||
import org.meshtastic.core.service.ServiceRepository
|
||||
import org.meshtastic.proto.LocalStats
|
||||
import javax.inject.Inject
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue