Modularize database classes (#3192)

This commit is contained in:
Phil Oliver 2025-09-24 16:23:05 -04:00 committed by GitHub
parent 989a6bc820
commit 613714cdb4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
94 changed files with 384 additions and 431 deletions

View file

@ -28,7 +28,6 @@ plugins {
alias(libs.plugins.meshtastic.android.application.compose)
alias(libs.plugins.meshtastic.android.application.firebase)
alias(libs.plugins.meshtastic.hilt)
alias(libs.plugins.meshtastic.android.room)
alias(libs.plugins.kotlin.parcelize)
alias(libs.plugins.meshtastic.kotlinx.serialization)
alias(libs.plugins.devtools.ksp)
@ -146,10 +145,6 @@ android {
}
bundle { language { enableSplit = false } }
buildFeatures { aidl = true }
sourceSets {
// Adds exported schema location as test app assets.
named("androidTest") { assets.srcDirs(files("$projectDir/schemas")) }
}
}
secrets {
@ -181,6 +176,7 @@ project.afterEvaluate { logger.lifecycle("Version code is set to: ${android.defa
dependencies {
implementation(projects.core.data)
implementation(projects.core.database)
implementation(projects.core.datastore)
implementation(projects.core.di)
implementation(projects.core.model)

View file

@ -21,12 +21,12 @@ import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.geeksville.mesh.model.Message
import com.geeksville.mesh.ui.common.preview.NodePreviewParameterProvider
import com.geeksville.mesh.ui.message.components.MessageItem
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.meshtastic.core.database.model.Message
import org.meshtastic.core.model.MessageStatus
@RunWith(AndroidJUnit4::class)

View file

@ -67,8 +67,6 @@ import com.geeksville.mesh.android.BuildUtils.debug
import com.geeksville.mesh.android.gpsDisabled
import com.geeksville.mesh.android.hasGps
import com.geeksville.mesh.copy
import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.ui.map.components.CacheLayout
import com.geeksville.mesh.ui.map.components.DownloadButton
@ -82,6 +80,8 @@ import com.geeksville.mesh.waypoint
import com.google.accompanist.permissions.ExperimentalPermissionsApi // Added for Accompanist
import com.google.accompanist.permissions.rememberMultiplePermissionsState // Added for Accompanist
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.meshtastic.core.database.entity.Packet
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.model.DataPacket
import org.meshtastic.core.model.util.formatAgo
import org.meshtastic.core.strings.R

View file

@ -71,7 +71,6 @@ import com.geeksville.mesh.MeshProtos.Waypoint
import com.geeksville.mesh.android.BuildUtils.debug
import com.geeksville.mesh.android.BuildUtils.warn
import com.geeksville.mesh.copy
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.ui.map.components.ClusterItemsListDialog
import com.geeksville.mesh.ui.map.components.CustomMapLayersSheet
@ -84,8 +83,6 @@ import com.geeksville.mesh.ui.metrics.HEADING_DEG
import com.geeksville.mesh.ui.metrics.formatPositionTime
import com.geeksville.mesh.ui.node.DEG_D
import com.geeksville.mesh.ui.node.components.NodeChip
import com.geeksville.mesh.util.metersIn
import com.geeksville.mesh.util.toString
import com.geeksville.mesh.waypoint
import com.google.android.gms.location.LocationCallback
import com.google.android.gms.location.LocationRequest
@ -117,9 +114,12 @@ import com.google.maps.android.compose.rememberUpdatedMarkerState
import com.google.maps.android.compose.widgets.ScaleBar
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.model.util.formatAgo
import org.meshtastic.core.model.util.metersIn
import org.meshtastic.core.model.util.mpsToKmph
import org.meshtastic.core.model.util.mpsToMph
import org.meshtastic.core.model.util.toString
import org.meshtastic.core.strings.R
import timber.log.Timber
import java.text.DateFormat

View file

@ -22,14 +22,14 @@ import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.MeshProtos.MeshPacket
import com.geeksville.mesh.Portnums
import com.geeksville.mesh.TelemetryProtos.Telemetry
import com.geeksville.mesh.database.dao.MeshLogDao
import com.geeksville.mesh.database.entity.MeshLog
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.withContext
import org.meshtastic.core.database.dao.MeshLogDao
import org.meshtastic.core.database.entity.MeshLog
import javax.inject.Inject
@Suppress("TooManyFunctions")

View file

@ -21,12 +21,6 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.coroutineScope
import com.geeksville.mesh.CoroutineDispatchers
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.database.dao.NodeInfoDao
import com.geeksville.mesh.database.entity.MetadataEntity
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.NodeSortOption
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
@ -38,6 +32,12 @@ import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
import org.meshtastic.core.database.dao.NodeInfoDao
import org.meshtastic.core.database.entity.MetadataEntity
import org.meshtastic.core.database.entity.MyNodeEntity
import org.meshtastic.core.database.entity.NodeEntity
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.database.model.NodeSortOption
import org.meshtastic.core.model.DataPacket
import org.meshtastic.core.model.util.onlineTimeThreshold
import javax.inject.Inject

View file

@ -18,15 +18,15 @@
package com.geeksville.mesh.database
import com.geeksville.mesh.Portnums.PortNum
import com.geeksville.mesh.database.dao.PacketDao
import com.geeksville.mesh.database.entity.ContactSettings
import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.database.entity.ReactionEntity
import com.geeksville.mesh.model.Node
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.withContext
import org.meshtastic.core.database.dao.PacketDao
import org.meshtastic.core.database.entity.ContactSettings
import org.meshtastic.core.database.entity.Packet
import org.meshtastic.core.database.entity.ReactionEntity
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.model.DataPacket
import org.meshtastic.core.model.MessageStatus
import javax.inject.Inject

View file

@ -18,35 +18,28 @@
package com.geeksville.mesh.database
import com.geeksville.mesh.CoroutineDispatchers
import com.geeksville.mesh.database.dao.QuickChatActionDao
import com.geeksville.mesh.database.entity.QuickChatAction
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.withContext
import org.meshtastic.core.database.dao.QuickChatActionDao
import org.meshtastic.core.database.entity.QuickChatAction
import javax.inject.Inject
class QuickChatActionRepository @Inject constructor(
class QuickChatActionRepository
@Inject
constructor(
private val quickChatDaoLazy: dagger.Lazy<QuickChatActionDao>,
private val dispatchers: CoroutineDispatchers,
) {
private val quickChatActionDao by lazy {
quickChatDaoLazy.get()
}
private val quickChatActionDao by lazy { quickChatDaoLazy.get() }
fun getAllActions() = quickChatActionDao.getAll().flowOn(dispatchers.io)
suspend fun upsert(action: QuickChatAction) = withContext(dispatchers.io) {
quickChatActionDao.upsert(action)
}
suspend fun upsert(action: QuickChatAction) = withContext(dispatchers.io) { quickChatActionDao.upsert(action) }
suspend fun deleteAll() = withContext(dispatchers.io) {
quickChatActionDao.deleteAll()
}
suspend fun deleteAll() = withContext(dispatchers.io) { quickChatActionDao.deleteAll() }
suspend fun delete(action: QuickChatAction) = withContext(dispatchers.io) {
quickChatActionDao.delete(action)
}
suspend fun delete(action: QuickChatAction) = withContext(dispatchers.io) { quickChatActionDao.delete(action) }
suspend fun setItemPosition(uuid: Long, newPos: Int) = withContext(dispatchers.io) {
quickChatActionDao.updateActionPosition(uuid, newPos)
}
}
suspend fun setItemPosition(uuid: Long, newPos: Int) =
withContext(dispatchers.io) { quickChatActionDao.updateActionPosition(uuid, newPos) }
}

View file

@ -28,7 +28,6 @@ import com.geeksville.mesh.StoreAndForwardProtos
import com.geeksville.mesh.TelemetryProtos
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.database.MeshLogRepository
import com.geeksville.mesh.database.entity.MeshLog
import com.geeksville.mesh.repository.datastore.RadioConfigRepository
import com.geeksville.mesh.ui.debug.FilterMode
import com.google.protobuf.InvalidProtocolBufferException
@ -45,6 +44,7 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import org.meshtastic.core.database.entity.MeshLog
import java.text.DateFormat
import java.util.Date
import java.util.Locale

View file

@ -36,8 +36,6 @@ import com.geeksville.mesh.Portnums.PortNum
import com.geeksville.mesh.TelemetryProtos.Telemetry
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.database.MeshLogRepository
import com.geeksville.mesh.database.entity.FirmwareRelease
import com.geeksville.mesh.database.entity.MeshLog
import com.geeksville.mesh.repository.api.DeviceHardwareRepository
import com.geeksville.mesh.repository.api.FirmwareReleaseRepository
import com.geeksville.mesh.repository.datastore.RadioConfigRepository
@ -58,6 +56,9 @@ import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.meshtastic.core.database.entity.FirmwareRelease
import org.meshtastic.core.database.entity.MeshLog
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.model.DataPacket
import org.meshtastic.core.model.DeviceHardware
import org.meshtastic.core.navigation.NodesRoutes

View file

@ -46,10 +46,6 @@ import com.geeksville.mesh.database.MeshLogRepository
import com.geeksville.mesh.database.NodeRepository
import com.geeksville.mesh.database.PacketRepository
import com.geeksville.mesh.database.QuickChatActionRepository
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.database.entity.QuickChatAction
import com.geeksville.mesh.database.entity.asDeviceVersion
import com.geeksville.mesh.repository.api.DeviceHardwareRepository
import com.geeksville.mesh.repository.api.FirmwareReleaseRepository
import com.geeksville.mesh.repository.datastore.RadioConfigRepository
@ -78,6 +74,13 @@ import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.meshtastic.core.database.entity.MyNodeEntity
import org.meshtastic.core.database.entity.Packet
import org.meshtastic.core.database.entity.QuickChatAction
import org.meshtastic.core.database.entity.asDeviceVersion
import org.meshtastic.core.database.model.Message
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.database.model.NodeSortOption
import org.meshtastic.core.datastore.UiPreferencesDataSource
import org.meshtastic.core.model.DataPacket
import org.meshtastic.core.model.DeviceHardware

View file

@ -17,11 +17,11 @@
package com.geeksville.mesh.repository.api
import com.geeksville.mesh.database.dao.DeviceHardwareDao
import com.geeksville.mesh.database.entity.DeviceHardwareEntity
import com.geeksville.mesh.database.entity.asEntity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.meshtastic.core.database.dao.DeviceHardwareDao
import org.meshtastic.core.database.entity.DeviceHardwareEntity
import org.meshtastic.core.database.entity.asEntity
import org.meshtastic.core.model.NetworkDeviceHardware
import javax.inject.Inject

View file

@ -19,10 +19,10 @@ package com.geeksville.mesh.repository.api
import com.geeksville.mesh.android.BuildUtils.debug
import com.geeksville.mesh.android.BuildUtils.warn
import com.geeksville.mesh.database.entity.DeviceHardwareEntity
import com.geeksville.mesh.database.entity.asExternalModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.meshtastic.core.database.entity.DeviceHardwareEntity
import org.meshtastic.core.database.entity.asExternalModel
import org.meshtastic.core.model.DeviceHardware
import org.meshtastic.core.network.DeviceHardwareRemoteDataSource
import java.util.concurrent.TimeUnit

View file

@ -17,14 +17,14 @@
package com.geeksville.mesh.repository.api
import com.geeksville.mesh.database.dao.FirmwareReleaseDao
import com.geeksville.mesh.database.entity.FirmwareReleaseEntity
import com.geeksville.mesh.database.entity.FirmwareReleaseType
import com.geeksville.mesh.database.entity.asDeviceVersion
import com.geeksville.mesh.database.entity.asEntity
import dagger.Lazy
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.meshtastic.core.database.dao.FirmwareReleaseDao
import org.meshtastic.core.database.entity.FirmwareReleaseEntity
import org.meshtastic.core.database.entity.FirmwareReleaseType
import org.meshtastic.core.database.entity.asDeviceVersion
import org.meshtastic.core.database.entity.asEntity
import org.meshtastic.core.model.NetworkFirmwareRelease
import javax.inject.Inject

View file

@ -19,12 +19,12 @@ package com.geeksville.mesh.repository.api
import com.geeksville.mesh.android.BuildUtils.debug
import com.geeksville.mesh.android.BuildUtils.warn
import com.geeksville.mesh.database.entity.FirmwareRelease
import com.geeksville.mesh.database.entity.FirmwareReleaseEntity
import com.geeksville.mesh.database.entity.FirmwareReleaseType
import com.geeksville.mesh.database.entity.asExternalModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import org.meshtastic.core.database.entity.FirmwareRelease
import org.meshtastic.core.database.entity.FirmwareReleaseEntity
import org.meshtastic.core.database.entity.FirmwareReleaseType
import org.meshtastic.core.database.entity.asExternalModel
import org.meshtastic.core.network.FirmwareReleaseRemoteDataSource
import java.util.concurrent.TimeUnit
import javax.inject.Inject

View file

@ -30,11 +30,7 @@ import com.geeksville.mesh.MeshProtos.DeviceMetadata
import com.geeksville.mesh.MeshProtos.MeshPacket
import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig
import com.geeksville.mesh.database.NodeRepository
import com.geeksville.mesh.database.entity.MetadataEntity
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.deviceProfile
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.getChannelUrl
import com.geeksville.mesh.service.ConnectionState
import com.geeksville.mesh.service.ServiceAction
@ -45,6 +41,10 @@ import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.first
import org.meshtastic.core.database.entity.MetadataEntity
import org.meshtastic.core.database.entity.MyNodeEntity
import org.meshtastic.core.database.entity.NodeEntity
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.datastore.ChannelSetDataSource
import org.meshtastic.core.datastore.LocalConfigDataSource
import org.meshtastic.core.datastore.ModuleConfigDataSource

View file

@ -56,14 +56,8 @@ import com.geeksville.mesh.concurrent.handledLaunch
import com.geeksville.mesh.copy
import com.geeksville.mesh.database.MeshLogRepository
import com.geeksville.mesh.database.PacketRepository
import com.geeksville.mesh.database.entity.MeshLog
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.database.entity.ReactionEntity
import com.geeksville.mesh.fromRadio
import com.geeksville.mesh.model.NO_DEVICE_SELECTED
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.position
import com.geeksville.mesh.repository.datastore.RadioConfigRepository
import com.geeksville.mesh.repository.location.LocationRepository
@ -90,6 +84,12 @@ import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.meshtastic.core.database.entity.MeshLog
import org.meshtastic.core.database.entity.MyNodeEntity
import org.meshtastic.core.database.entity.NodeEntity
import org.meshtastic.core.database.entity.Packet
import org.meshtastic.core.database.entity.ReactionEntity
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.model.DataPacket
import org.meshtastic.core.model.DeviceVersion
import org.meshtastic.core.model.MeshUser

View file

@ -38,8 +38,8 @@ import com.geeksville.mesh.MainActivity
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.R.raw
import com.geeksville.mesh.TelemetryProtos.LocalStats
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.service.ReplyReceiver.Companion.KEY_TEXT_REPLY
import org.meshtastic.core.database.entity.NodeEntity
import org.meshtastic.core.model.util.formatUptime
import org.meshtastic.core.navigation.DEEP_LINK_BASE_URI
import org.meshtastic.core.strings.R

View file

@ -26,7 +26,6 @@ import com.geeksville.mesh.android.BuildUtils.info
import com.geeksville.mesh.concurrent.handledLaunch
import com.geeksville.mesh.database.MeshLogRepository
import com.geeksville.mesh.database.PacketRepository
import com.geeksville.mesh.database.entity.MeshLog
import com.geeksville.mesh.fromRadio
import com.geeksville.mesh.repository.radio.RadioInterfaceService
import dagger.Lazy
@ -36,6 +35,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.withTimeoutOrNull
import org.meshtastic.core.database.entity.MeshLog
import org.meshtastic.core.model.DataPacket
import org.meshtastic.core.model.MessageStatus
import org.meshtastic.core.model.util.toOneLineString

View file

@ -80,7 +80,6 @@ import com.geeksville.mesh.android.AddNavigationTracking
import com.geeksville.mesh.android.BuildUtils.debug
import com.geeksville.mesh.android.setAttributes
import com.geeksville.mesh.model.BTScanModel
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.navigation.channelsGraph
import com.geeksville.mesh.navigation.connectionsGraph
@ -111,6 +110,7 @@ import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.model.DeviceVersion
import org.meshtastic.core.navigation.ConnectionsRoutes
import org.meshtastic.core.navigation.ContactsRoutes

View file

@ -46,7 +46,6 @@ import androidx.navigation.NavDestination
import androidx.navigation.NavDestination.Companion.hasRoute
import androidx.navigation.NavHostController
import androidx.navigation.compose.currentBackStackEntryAsState
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.navigation.isConfigRoute
import com.geeksville.mesh.navigation.isNodeDetailRoute
@ -55,6 +54,7 @@ import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.debug.DebugMenuActions
import com.geeksville.mesh.ui.node.components.NodeChip
import com.geeksville.mesh.ui.node.components.NodeMenuAction
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.navigation.ContactsRoutes
import org.meshtastic.core.navigation.NodesRoutes
import org.meshtastic.core.navigation.SettingsRoutes

View file

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

View file

@ -23,7 +23,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.PaxcountProtos
import com.geeksville.mesh.TelemetryProtos
import com.geeksville.mesh.model.Node
import org.meshtastic.core.database.model.Node
/** Simple [PreviewParameterProvider] that provides true and false values. */
class BooleanProvider : PreviewParameterProvider<Boolean> {

View file

@ -26,9 +26,9 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.tooling.preview.PreviewParameter
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.ui.common.preview.NodePreviewParameterProvider
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.strings.R
const val MAX_VALID_SNR = 100F

View file

@ -22,11 +22,11 @@ import com.geeksville.mesh.ConfigProtos
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.deviceMetrics
import com.geeksville.mesh.environmentMetrics
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.paxcount
import com.geeksville.mesh.position
import com.geeksville.mesh.user
import com.google.protobuf.ByteString
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.model.DeviceMetrics.Companion.currentTime
import kotlin.random.Random

View file

@ -62,7 +62,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.ConfigProtos
import com.geeksville.mesh.model.BTScanModel
import com.geeksville.mesh.model.DeviceListEntry
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.navigation.ConfigRoute
import com.geeksville.mesh.navigation.getNavRouteFrom
import com.geeksville.mesh.service.ConnectionState
@ -80,6 +79,7 @@ import com.geeksville.mesh.ui.settings.radio.components.PacketResponseStateDialo
import com.geeksville.mesh.ui.sharing.SharedContactDialog
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import kotlinx.coroutines.delay
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.navigation.Route
import org.meshtastic.core.navigation.SettingsRoutes
import org.meshtastic.core.strings.R

View file

@ -21,8 +21,6 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.geeksville.mesh.LocalOnlyProtos.LocalConfig
import com.geeksville.mesh.database.NodeRepository
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.repository.bluetooth.BluetoothRepository
import com.geeksville.mesh.repository.datastore.RadioConfigRepository
import dagger.hilt.android.lifecycle.HiltViewModel
@ -31,6 +29,8 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.stateIn
import org.meshtastic.core.database.entity.MyNodeEntity
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.prefs.ui.UiPrefs
import javax.inject.Inject

View file

@ -43,12 +43,12 @@ import androidx.compose.ui.unit.dp
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.PaxcountProtos
import com.geeksville.mesh.TelemetryProtos
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.ui.common.components.MaterialBatteryInfo
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusRed
import com.geeksville.mesh.ui.node.components.NodeChip
import com.geeksville.mesh.ui.node.components.NodeMenuAction
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.strings.R
@Composable

View file

@ -21,8 +21,6 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.geeksville.mesh.database.NodeRepository
import com.geeksville.mesh.database.PacketRepository
import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.repository.datastore.RadioConfigRepository
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
@ -31,6 +29,8 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.stateIn
import org.meshtastic.core.database.entity.Packet
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.prefs.map.MapPrefs
@Suppress("TooManyFunctions")

View file

@ -95,9 +95,6 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.AppOnlyProtos
import com.geeksville.mesh.database.entity.QuickChatAction
import com.geeksville.mesh.model.Message
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.model.getChannel
import com.geeksville.mesh.ui.common.components.SecurityIcon
@ -107,6 +104,9 @@ import com.geeksville.mesh.ui.node.components.NodeMenuAction
import com.geeksville.mesh.ui.sharing.SharedContactDialog
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.meshtastic.core.database.entity.QuickChatAction
import org.meshtastic.core.database.model.Message
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.model.DataPacket
import org.meshtastic.core.strings.R
import java.nio.charset.StandardCharsets

View file

@ -47,8 +47,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.database.entity.Reaction
import com.geeksville.mesh.model.Message
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.ui.message.components.MessageItem
import com.geeksville.mesh.ui.message.components.ReactionDialog
@ -57,6 +55,8 @@ import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.launch
import org.meshtastic.core.database.entity.Reaction
import org.meshtastic.core.database.model.Message
import org.meshtastic.core.model.MessageStatus
import org.meshtastic.core.strings.R

View file

@ -70,12 +70,12 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.database.entity.QuickChatAction
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.ui.common.components.dragContainer
import com.geeksville.mesh.ui.common.components.dragDropItemsIndexed
import com.geeksville.mesh.ui.common.components.rememberDragDropState
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.database.entity.QuickChatAction
import org.meshtastic.core.strings.R
@Composable

View file

@ -49,9 +49,6 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.database.entity.Reaction
import com.geeksville.mesh.model.Message
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.ui.common.components.MDText
import com.geeksville.mesh.ui.common.components.Rssi
import com.geeksville.mesh.ui.common.components.Snr
@ -60,6 +57,9 @@ import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.common.theme.MessageItemColors
import com.geeksville.mesh.ui.node.components.NodeChip
import com.geeksville.mesh.ui.node.components.NodeMenuAction
import org.meshtastic.core.database.entity.Reaction
import org.meshtastic.core.database.model.Message
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.model.MessageStatus
import org.meshtastic.core.strings.R

View file

@ -52,44 +52,25 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.database.entity.Reaction
import com.geeksville.mesh.ui.common.components.BottomSheetDialog
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.database.entity.Reaction
@Composable
private fun ReactionItem(
emoji: String,
emojiCount: Int = 1,
onClick: () -> Unit = {},
onLongClick: () -> Unit = {},
) {
private fun ReactionItem(emoji: String, emojiCount: Int = 1, onClick: () -> Unit = {}, onLongClick: () -> Unit = {}) {
BadgedBox(
badge = {
if (emojiCount > 1) {
Badge {
Text(
fontWeight = FontWeight.Bold,
text = emojiCount.toString()
)
}
Badge { Text(fontWeight = FontWeight.Bold, text = emojiCount.toString()) }
}
}
},
) {
Surface(
modifier = Modifier
.combinedClickable(
onClick = onClick,
onLongClick = onLongClick
),
modifier = Modifier.combinedClickable(onClick = onClick, onLongClick = onLongClick),
color = MaterialTheme.colorScheme.primaryContainer,
shape = CircleShape,
) {
Text(
text = emoji,
modifier = Modifier
.padding(4.dp)
.clip(CircleShape),
)
Text(text = emoji, modifier = Modifier.padding(4.dp).clip(CircleShape))
}
}
}
@ -102,10 +83,7 @@ fun ReactionRow(
onSendReaction: (String) -> Unit = {},
onShowReactions: () -> Unit = {},
) {
val emojiList =
reduceEmojis(
reactions.reversed().map { it.emoji }
).entries
val emojiList = reduceEmojis(reactions.reversed().map { it.emoji }).entries
AnimatedVisibility(emojiList.isNotEmpty()) {
LazyRow(
@ -113,16 +91,12 @@ fun ReactionRow(
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically,
) {
items(
emojiList.size
) { index ->
items(emojiList.size) { index ->
val entry = emojiList.elementAt(index)
ReactionItem(
emoji = entry.key,
emojiCount = entry.value,
onClick = {
onSendReaction(entry.key)
},
onClick = { onSendReaction(entry.key) },
onLongClick = onShowReactions,
)
}
@ -133,68 +107,47 @@ fun ReactionRow(
fun reduceEmojis(emojis: List<String>): Map<String, Int> = emojis.groupingBy { it }.eachCount()
@Composable
fun ReactionDialog(
reactions: List<Reaction>,
onDismiss: () -> Unit = {}
) = BottomSheetDialog(
onDismiss = onDismiss,
modifier = Modifier.fillMaxHeight(fraction = .3f),
) {
val groupedEmojis = reactions.groupBy { it.emoji }
var selectedEmoji by remember { mutableStateOf<String?>(null) }
val filteredReactions = selectedEmoji?.let { groupedEmojis[it] ?: emptyList() } ?: reactions
fun ReactionDialog(reactions: List<Reaction>, onDismiss: () -> Unit = {}) =
BottomSheetDialog(onDismiss = onDismiss, modifier = Modifier.fillMaxHeight(fraction = .3f)) {
val groupedEmojis = reactions.groupBy { it.emoji }
var selectedEmoji by remember { mutableStateOf<String?>(null) }
val filteredReactions = selectedEmoji?.let { groupedEmojis[it] ?: emptyList() } ?: reactions
LazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.fillMaxWidth()
) {
items(groupedEmojis.entries.toList()) { (emoji, reactions) ->
Text(
text = "$emoji${reactions.size}",
modifier = Modifier
.clip(CircleShape)
.background(if (selectedEmoji == emoji) Color.Gray else Color.Transparent)
.padding(8.dp)
.clickable {
selectedEmoji = if (selectedEmoji == emoji) null else emoji
},
style = MaterialTheme.typography.bodyMedium
)
}
}
HorizontalDivider(Modifier.padding(vertical = 8.dp))
LazyColumn(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
items(filteredReactions) { reaction ->
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
LazyRow(horizontalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.fillMaxWidth()) {
items(groupedEmojis.entries.toList()) { (emoji, reactions) ->
Text(
text = reaction.user.longName,
style = MaterialTheme.typography.titleMedium
)
Text(
text = reaction.emoji,
style = MaterialTheme.typography.titleLarge
text = "$emoji${reactions.size}",
modifier =
Modifier.clip(CircleShape)
.background(if (selectedEmoji == emoji) Color.Gray else Color.Transparent)
.padding(8.dp)
.clickable { selectedEmoji = if (selectedEmoji == emoji) null else emoji },
style = MaterialTheme.typography.bodyMedium,
)
}
}
HorizontalDivider(Modifier.padding(vertical = 8.dp))
LazyColumn(modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(12.dp)) {
items(filteredReactions) { reaction ->
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Text(text = reaction.user.longName, style = MaterialTheme.typography.titleMedium)
Text(text = reaction.emoji, style = MaterialTheme.typography.titleLarge)
}
}
}
}
}
@PreviewLightDark
@Composable
fun ReactionItemPreview() {
AppTheme {
Column(
modifier = Modifier.background(MaterialTheme.colorScheme.background)
) {
Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {
ReactionItem(emoji = "\uD83D\uDE42")
ReactionItem(emoji = "\uD83D\uDE42", emojiCount = 2)
ReactionButton()
@ -207,20 +160,21 @@ fun ReactionItemPreview() {
fun ReactionRowPreview() {
AppTheme {
ReactionRow(
reactions = listOf(
reactions =
listOf(
Reaction(
replyId = 1,
user = MeshProtos.User.getDefaultInstance(),
emoji = "\uD83D\uDE42",
timestamp = 1L
timestamp = 1L,
),
Reaction(
replyId = 1,
user = MeshProtos.User.getDefaultInstance(),
emoji = "\uD83D\uDE42",
timestamp = 1L
timestamp = 1L,
),
)
),
)
}
}

View file

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

View file

@ -65,8 +65,8 @@ import com.geeksville.mesh.ConfigProtos.Config.DisplayConfig.DisplayUnits
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.model.MetricsViewModel
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.util.metersIn
import com.geeksville.mesh.util.toString
import org.meshtastic.core.model.util.metersIn
import org.meshtastic.core.model.util.toString
import org.meshtastic.core.strings.R
import java.text.DateFormat
import kotlin.time.Duration.Companion.days

View file

@ -123,13 +123,9 @@ import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import com.geeksville.mesh.ConfigProtos
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.database.entity.FirmwareRelease
import com.geeksville.mesh.database.entity.asDeviceVersion
import com.geeksville.mesh.model.MetricsState
import com.geeksville.mesh.model.MetricsViewModel
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.model.isUnmessageableRole
import com.geeksville.mesh.service.ServiceAction
import com.geeksville.mesh.ui.common.components.MainAppBar
import com.geeksville.mesh.ui.common.components.TitledCard
@ -147,10 +143,11 @@ import com.geeksville.mesh.ui.settings.components.SettingsItemDetail
import com.geeksville.mesh.ui.settings.components.SettingsItemSwitch
import com.geeksville.mesh.ui.sharing.SharedContactDialog
import com.geeksville.mesh.util.thenIf
import com.geeksville.mesh.util.toDistanceString
import com.geeksville.mesh.util.toSmallDistanceString
import com.geeksville.mesh.util.toSpeedString
import com.mikepenz.markdown.m3.Markdown
import org.meshtastic.core.database.entity.FirmwareRelease
import org.meshtastic.core.database.entity.asDeviceVersion
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.database.model.isUnmessageableRole
import org.meshtastic.core.model.DataPacket
import org.meshtastic.core.model.DeviceHardware
import org.meshtastic.core.model.DeviceVersion
@ -158,6 +155,9 @@ import org.meshtastic.core.model.util.UnitConversions
import org.meshtastic.core.model.util.UnitConversions.toTempString
import org.meshtastic.core.model.util.formatAgo
import org.meshtastic.core.model.util.formatUptime
import org.meshtastic.core.model.util.toDistanceString
import org.meshtastic.core.model.util.toSmallDistanceString
import org.meshtastic.core.model.util.toSpeedString
import org.meshtastic.core.navigation.NodeDetailRoutes
import org.meshtastic.core.navigation.Route
import org.meshtastic.core.navigation.SettingsRoutes

View file

@ -46,7 +46,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.service.ConnectionState
import com.geeksville.mesh.ui.common.components.MainAppBar
@ -57,6 +56,7 @@ import com.geeksville.mesh.ui.node.components.NodeMenuAction
import com.geeksville.mesh.ui.sharing.AddContactFAB
import com.geeksville.mesh.ui.sharing.SharedContactDialog
import com.geeksville.mesh.ui.sharing.supportsQrCodeSharing
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.model.DataPacket
import org.meshtastic.core.model.DeviceVersion
import org.meshtastic.core.strings.R

View file

@ -25,40 +25,21 @@ import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.ConfigProtos.Config.DisplayConfig.DisplayUnits
import com.geeksville.mesh.util.metersIn
import com.geeksville.mesh.util.toString
import org.meshtastic.core.model.util.metersIn
import org.meshtastic.core.model.util.toString
@Composable
fun ElevationInfo(
modifier: Modifier = Modifier,
altitude: Int,
system: DisplayUnits,
suffix: String
) {
fun ElevationInfo(modifier: Modifier = Modifier, altitude: Int, system: DisplayUnits, suffix: String) {
val annotatedString = buildAnnotatedString {
append(altitude.metersIn(system).toString(system))
MaterialTheme.typography.labelSmall.toSpanStyle().let { style ->
withStyle(style) {
append(" $suffix")
}
}
MaterialTheme.typography.labelSmall.toSpanStyle().let { style -> withStyle(style) { append(" $suffix") } }
}
Text(
modifier = modifier,
fontSize = MaterialTheme.typography.labelLarge.fontSize,
text = annotatedString,
)
Text(modifier = modifier, fontSize = MaterialTheme.typography.labelLarge.fontSize, text = annotatedString)
}
@Composable
@Preview
fun ElevationInfoPreview() {
MaterialTheme {
ElevationInfo(
altitude = 100,
system = DisplayUnits.METRIC,
suffix = "ASL"
)
}
MaterialTheme { ElevationInfo(altitude = 100, system = DisplayUnits.METRIC, suffix = "ASL") }
}

View file

@ -44,7 +44,7 @@ import androidx.compose.ui.unit.dp
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.PaxcountProtos
import com.geeksville.mesh.TelemetryProtos
import com.geeksville.mesh.model.Node
import org.meshtastic.core.database.model.Node
@Composable
fun NodeChip(

View file

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

View file

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

View file

@ -38,9 +38,9 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.isUnmessageableRole
import com.geeksville.mesh.ui.common.components.SimpleAlertDialog
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.database.model.isUnmessageableRole
import org.meshtastic.core.strings.R
@Suppress("LongMethod")

View file

@ -28,8 +28,6 @@ import com.geeksville.mesh.Portnums
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.database.MeshLogRepository
import com.geeksville.mesh.database.NodeRepository
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.repository.datastore.RadioConfigRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
@ -45,6 +43,8 @@ import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.meshtastic.core.database.entity.MyNodeEntity
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.datastore.UiPreferencesDataSource
import org.meshtastic.core.model.Position
import org.meshtastic.core.model.util.positionToMeter

View file

@ -46,8 +46,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.ui.node.components.NodeChip
import org.meshtastic.core.database.entity.NodeEntity
import org.meshtastic.core.strings.R
/**

View file

@ -20,12 +20,12 @@ package com.geeksville.mesh.ui.settings.radio
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.geeksville.mesh.database.NodeRepository
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.repository.datastore.RadioConfigRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import org.meshtastic.core.database.entity.NodeEntity
import javax.inject.Inject
import kotlin.time.Duration.Companion.days
import kotlin.time.Duration.Companion.milliseconds

View file

@ -45,11 +45,8 @@ import com.geeksville.mesh.android.GeeksvilleApplication
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.android.isAnalyticsAvailable
import com.geeksville.mesh.config
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.deviceProfile
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.getChannelList
import com.geeksville.mesh.model.getStringResFrom
import com.geeksville.mesh.model.toChannelSet
import com.geeksville.mesh.moduleConfig
import com.geeksville.mesh.navigation.ConfigRoute
@ -73,6 +70,9 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONObject
import org.meshtastic.core.database.entity.MyNodeEntity
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.database.model.getStringResFrom
import org.meshtastic.core.model.Position
import org.meshtastic.core.navigation.SettingsRoutes
import org.meshtastic.core.prefs.analytics.AnalyticsPrefs

View file

@ -43,8 +43,8 @@ import androidx.compose.ui.unit.dp
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.common.components.precisionBitsToMeters
import com.geeksville.mesh.util.DistanceUnit
import com.geeksville.mesh.util.toDistanceString
import org.meshtastic.core.model.util.DistanceUnit
import org.meshtastic.core.model.util.toDistanceString
import org.meshtastic.core.strings.R
import kotlin.math.roundToInt

View file

@ -30,12 +30,12 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavController
import com.geeksville.mesh.copy
import com.geeksville.mesh.model.isUnmessageableRole
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.RegularPreference
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.database.model.isUnmessageableRole
import org.meshtastic.core.model.DeviceVersion
import org.meshtastic.core.strings.R

View file

@ -54,7 +54,6 @@ import com.geeksville.mesh.AdminProtos
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.android.BuildUtils.debug
import com.geeksville.mesh.android.BuildUtils.errormsg
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.ui.common.components.CopyIconButton
import com.geeksville.mesh.ui.common.components.SimpleAlertDialog
@ -69,6 +68,7 @@ import com.google.zxing.WriterException
import com.journeyapps.barcodescanner.BarcodeEncoder
import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanOptions
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.model.DeviceVersion
import org.meshtastic.core.strings.R
import timber.log.Timber

View file

@ -50,6 +50,7 @@ class AndroidLibraryConventionPlugin : Plugin<Project> {
}
dependencies {
"androidTestImplementation"(libs.findLibrary("kotlin.test").get())
"androidTestImplementation"(libs.findBundle("testing.android").get())
"testImplementation"(libs.findLibrary("kotlin.test").get())
}

View file

@ -0,0 +1,39 @@
/*
* 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/>.
*/
plugins {
alias(libs.plugins.meshtastic.android.library)
alias(libs.plugins.meshtastic.android.room)
alias(libs.plugins.meshtastic.hilt)
alias(libs.plugins.meshtastic.kotlinx.serialization)
}
android {
namespace = "org.meshtastic.core.database"
sourceSets {
// Adds exported schema location as test app assets.
named("androidTest") { assets.srcDirs(files("$projectDir/schemas")) }
}
}
dependencies {
implementation(projects.core.model)
implementation(projects.core.proto)
implementation(projects.core.strings)
implementation(libs.kotlinx.serialization.json)
implementation(libs.timber)
}

View file

@ -15,13 +15,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh
package org.meshtastic.core.database
import androidx.room.Room
import androidx.room.testing.MigrationTestHelper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.geeksville.mesh.database.MeshtasticDatabase
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@ -35,27 +34,23 @@ class MeshtasticDatabaseTest {
}
@get:Rule
val helper: MigrationTestHelper = MigrationTestHelper(
InstrumentationRegistry.getInstrumentation(),
MeshtasticDatabase::class.java,
)
val helper: MigrationTestHelper =
MigrationTestHelper(InstrumentationRegistry.getInstrumentation(), MeshtasticDatabase::class.java)
@Test
@Throws(IOException::class)
fun migrateAll() {
// Create earliest version of the database.
helper.createDatabase(TEST_DB, 3).apply {
close()
}
helper.createDatabase(TEST_DB, 3).apply { close() }
// Open latest version of the database. Room validates the schema
// once all migrations execute.
Room.databaseBuilder(
InstrumentationRegistry.getInstrumentation().targetContext,
MeshtasticDatabase::class.java,
TEST_DB
).build().apply {
openHelper.writableDatabase.close()
}
TEST_DB,
)
.build()
.apply { openHelper.writableDatabase.close() }
}
}

View file

@ -15,17 +15,14 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh
package org.meshtastic.core.database.dao
import androidx.room.Room
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.geeksville.mesh.database.MeshtasticDatabase
import com.geeksville.mesh.database.dao.NodeInfoDao
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.NodeSortOption
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.copy
import com.geeksville.mesh.user
import com.google.protobuf.ByteString
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
@ -37,6 +34,11 @@ import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.meshtastic.core.database.MeshtasticDatabase
import org.meshtastic.core.database.entity.MyNodeEntity
import org.meshtastic.core.database.entity.NodeEntity
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.database.model.NodeSortOption
import org.meshtastic.core.model.util.onlineTimeThreshold
@RunWith(AndroidJUnit4::class)

View file

@ -15,16 +15,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh
package org.meshtastic.core.database.dao
import androidx.room.Room
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.geeksville.mesh.database.MeshtasticDatabase
import com.geeksville.mesh.database.dao.NodeInfoDao
import com.geeksville.mesh.database.dao.PacketDao
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.Portnums
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
@ -33,6 +29,9 @@ import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.meshtastic.core.database.MeshtasticDatabase
import org.meshtastic.core.database.entity.MyNodeEntity
import org.meshtastic.core.database.entity.Packet
import org.meshtastic.core.model.DataPacket
@RunWith(AndroidJUnit4::class)

View file

@ -15,20 +15,20 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.database
package org.meshtastic.core.database
import androidx.room.TypeConverter
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.PaxcountProtos
import com.geeksville.mesh.TelemetryProtos
import com.geeksville.mesh.android.Logging
import com.google.protobuf.ByteString
import com.google.protobuf.InvalidProtocolBufferException
import kotlinx.serialization.json.Json
import org.meshtastic.core.model.DataPacket
import timber.log.Timber
@Suppress("TooManyFunctions")
class Converters : Logging {
class Converters {
@TypeConverter
fun dataFromString(value: String): DataPacket {
val json = Json { isLenient = true }
@ -45,7 +45,7 @@ class Converters : Logging {
fun bytesToFromRadio(bytes: ByteArray): MeshProtos.FromRadio = try {
MeshProtos.FromRadio.parseFrom(bytes)
} catch (ex: InvalidProtocolBufferException) {
errormsg("bytesToFromRadio TypeConverter error:", ex)
Timber.e(ex, "bytesToFromRadio TypeConverter error")
MeshProtos.FromRadio.getDefaultInstance()
}
@ -55,7 +55,7 @@ class Converters : Logging {
fun bytesToUser(bytes: ByteArray): MeshProtos.User = try {
MeshProtos.User.parseFrom(bytes)
} catch (ex: InvalidProtocolBufferException) {
errormsg("bytesToUser TypeConverter error:", ex)
Timber.e(ex, "bytesToUser TypeConverter error")
MeshProtos.User.getDefaultInstance()
}
@ -65,7 +65,7 @@ class Converters : Logging {
fun bytesToPosition(bytes: ByteArray): MeshProtos.Position = try {
MeshProtos.Position.parseFrom(bytes)
} catch (ex: InvalidProtocolBufferException) {
errormsg("bytesToPosition TypeConverter error:", ex)
Timber.e(ex, "bytesToPosition TypeConverter error")
MeshProtos.Position.getDefaultInstance()
}
@ -75,7 +75,7 @@ class Converters : Logging {
fun bytesToTelemetry(bytes: ByteArray): TelemetryProtos.Telemetry = try {
TelemetryProtos.Telemetry.parseFrom(bytes)
} catch (ex: InvalidProtocolBufferException) {
errormsg("bytesToTelemetry TypeConverter error:", ex)
Timber.e(ex, "bytesToTelemetry TypeConverter error")
TelemetryProtos.Telemetry.newBuilder().build() // Return an empty Telemetry object
}
@ -85,7 +85,7 @@ class Converters : Logging {
fun bytesToPaxcounter(bytes: ByteArray): PaxcountProtos.Paxcount = try {
PaxcountProtos.Paxcount.parseFrom(bytes)
} catch (ex: InvalidProtocolBufferException) {
errormsg("bytesToPaxcounter TypeConverter error:", ex)
Timber.e(ex, "bytesToPaxcounter TypeConverter error")
PaxcountProtos.Paxcount.getDefaultInstance()
}
@ -95,7 +95,7 @@ class Converters : Logging {
fun bytesToMetadata(bytes: ByteArray): MeshProtos.DeviceMetadata = try {
MeshProtos.DeviceMetadata.parseFrom(bytes)
} catch (ex: InvalidProtocolBufferException) {
errormsg("bytesToMetadata TypeConverter error:", ex)
Timber.e(ex, "bytesToMetadata TypeConverter error")
MeshProtos.DeviceMetadata.getDefaultInstance()
}

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.database
package org.meshtastic.core.database
import android.content.Context
import androidx.room.AutoMigration
@ -25,22 +25,22 @@ import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import androidx.room.migration.AutoMigrationSpec
import com.geeksville.mesh.database.dao.DeviceHardwareDao
import com.geeksville.mesh.database.dao.FirmwareReleaseDao
import com.geeksville.mesh.database.dao.MeshLogDao
import com.geeksville.mesh.database.dao.NodeInfoDao
import com.geeksville.mesh.database.dao.PacketDao
import com.geeksville.mesh.database.dao.QuickChatActionDao
import com.geeksville.mesh.database.entity.ContactSettings
import com.geeksville.mesh.database.entity.DeviceHardwareEntity
import com.geeksville.mesh.database.entity.FirmwareReleaseEntity
import com.geeksville.mesh.database.entity.MeshLog
import com.geeksville.mesh.database.entity.MetadataEntity
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.database.entity.QuickChatAction
import com.geeksville.mesh.database.entity.ReactionEntity
import org.meshtastic.core.database.dao.DeviceHardwareDao
import org.meshtastic.core.database.dao.FirmwareReleaseDao
import org.meshtastic.core.database.dao.MeshLogDao
import org.meshtastic.core.database.dao.NodeInfoDao
import org.meshtastic.core.database.dao.PacketDao
import org.meshtastic.core.database.dao.QuickChatActionDao
import org.meshtastic.core.database.entity.ContactSettings
import org.meshtastic.core.database.entity.DeviceHardwareEntity
import org.meshtastic.core.database.entity.FirmwareReleaseEntity
import org.meshtastic.core.database.entity.MeshLog
import org.meshtastic.core.database.entity.MetadataEntity
import org.meshtastic.core.database.entity.MyNodeEntity
import org.meshtastic.core.database.entity.NodeEntity
import org.meshtastic.core.database.entity.Packet
import org.meshtastic.core.database.entity.QuickChatAction
import org.meshtastic.core.database.entity.ReactionEntity
@Database(
entities =

View file

@ -15,13 +15,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.database.dao
package org.meshtastic.core.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.geeksville.mesh.database.entity.DeviceHardwareEntity
import org.meshtastic.core.database.entity.DeviceHardwareEntity
@Dao
interface DeviceHardwareDao {

View file

@ -15,14 +15,14 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.database.dao
package org.meshtastic.core.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.geeksville.mesh.database.entity.FirmwareReleaseEntity
import com.geeksville.mesh.database.entity.FirmwareReleaseType
import org.meshtastic.core.database.entity.FirmwareReleaseEntity
import org.meshtastic.core.database.entity.FirmwareReleaseType
@Dao
interface FirmwareReleaseDao {

View file

@ -15,13 +15,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.database.dao
package org.meshtastic.core.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import com.geeksville.mesh.database.entity.MeshLog
import kotlinx.coroutines.flow.Flow
import org.meshtastic.core.database.entity.MeshLog
@Dao
interface MeshLogDao {
@ -42,12 +42,11 @@ interface MeshLogDao {
SELECT * FROM log
WHERE from_num = :fromNum AND (:portNum = 0 AND port_num != 0 OR port_num = :portNum)
ORDER BY received_date DESC LIMIT 0,:maxItem
"""
""",
)
fun getLogsFrom(fromNum: Int, portNum: Int, maxItem: Int): Flow<List<MeshLog>>
@Insert
fun insert(log: MeshLog)
@Insert fun insert(log: MeshLog)
@Query("DELETE FROM log")
fun deleteAll()

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.database.dao
package org.meshtastic.core.database.dao
import androidx.room.Dao
import androidx.room.Insert
@ -24,12 +24,12 @@ import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Upsert
import com.geeksville.mesh.database.entity.MetadataEntity
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.database.entity.NodeWithRelations
import com.google.protobuf.ByteString
import kotlinx.coroutines.flow.Flow
import org.meshtastic.core.database.entity.MetadataEntity
import org.meshtastic.core.database.entity.MyNodeEntity
import org.meshtastic.core.database.entity.NodeEntity
import org.meshtastic.core.database.entity.NodeWithRelations
@Suppress("TooManyFunctions")
@Dao

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.database.dao
package org.meshtastic.core.database.dao
import androidx.room.Dao
import androidx.room.MapColumn
@ -23,14 +23,15 @@ import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
import androidx.room.Upsert
import com.geeksville.mesh.database.entity.ContactSettings
import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.database.entity.PacketEntity
import com.geeksville.mesh.database.entity.ReactionEntity
import kotlinx.coroutines.flow.Flow
import org.meshtastic.core.database.entity.ContactSettings
import org.meshtastic.core.database.entity.Packet
import org.meshtastic.core.database.entity.PacketEntity
import org.meshtastic.core.database.entity.ReactionEntity
import org.meshtastic.core.model.DataPacket
import org.meshtastic.core.model.MessageStatus
@Suppress("TooManyFunctions")
@Dao
interface PacketDao {

View file

@ -15,14 +15,14 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.database.dao
package org.meshtastic.core.database.dao
import androidx.room.Dao
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Upsert
import com.geeksville.mesh.database.entity.QuickChatAction
import kotlinx.coroutines.flow.Flow
import org.meshtastic.core.database.entity.QuickChatAction
@Dao
interface QuickChatActionDao {
@ -30,18 +30,17 @@ interface QuickChatActionDao {
@Query("Select * from quick_chat order by position asc")
fun getAll(): Flow<List<QuickChatAction>>
@Upsert
fun upsert(action: QuickChatAction)
@Upsert fun upsert(action: QuickChatAction)
@Query("Delete from quick_chat")
fun deleteAll()
@Query("Delete from quick_chat where uuid=:uuid")
fun _delete(uuid: Long)
fun delete(uuid: Long)
@Transaction
fun delete(action: QuickChatAction) {
_delete(action.uuid)
delete(action.uuid)
decrementPositionsAfter(action.position)
}

View file

@ -15,56 +15,40 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.database
package org.meshtastic.core.database.di
import android.app.Application
import com.geeksville.mesh.database.dao.DeviceHardwareDao
import com.geeksville.mesh.database.dao.FirmwareReleaseDao
import com.geeksville.mesh.database.dao.MeshLogDao
import com.geeksville.mesh.database.dao.NodeInfoDao
import com.geeksville.mesh.database.dao.PacketDao
import com.geeksville.mesh.database.dao.QuickChatActionDao
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import org.meshtastic.core.database.MeshtasticDatabase
import org.meshtastic.core.database.dao.DeviceHardwareDao
import org.meshtastic.core.database.dao.FirmwareReleaseDao
import org.meshtastic.core.database.dao.MeshLogDao
import org.meshtastic.core.database.dao.NodeInfoDao
import org.meshtastic.core.database.dao.PacketDao
import org.meshtastic.core.database.dao.QuickChatActionDao
import javax.inject.Singleton
@InstallIn(SingletonComponent::class)
@Module
class DatabaseModule {
@Provides
@Singleton
fun provideDatabase(app: Application): MeshtasticDatabase =
MeshtasticDatabase.getDatabase(app)
@Provides @Singleton
fun provideDatabase(app: Application): MeshtasticDatabase = MeshtasticDatabase.getDatabase(app)
@Provides fun provideNodeInfoDao(database: MeshtasticDatabase): NodeInfoDao = database.nodeInfoDao()
@Provides fun providePacketDao(database: MeshtasticDatabase): PacketDao = database.packetDao()
@Provides fun provideMeshLogDao(database: MeshtasticDatabase): MeshLogDao = database.meshLogDao()
@Provides
fun provideNodeInfoDao(database: MeshtasticDatabase): NodeInfoDao {
return database.nodeInfoDao()
}
fun provideQuickChatActionDao(database: MeshtasticDatabase): QuickChatActionDao = database.quickChatActionDao()
@Provides
fun providePacketDao(database: MeshtasticDatabase): PacketDao {
return database.packetDao()
}
fun provideDeviceHardwareDao(database: MeshtasticDatabase): DeviceHardwareDao = database.deviceHardwareDao()
@Provides
fun provideMeshLogDao(database: MeshtasticDatabase): MeshLogDao {
return database.meshLogDao()
}
@Provides
fun provideQuickChatActionDao(database: MeshtasticDatabase): QuickChatActionDao {
return database.quickChatActionDao()
}
@Provides
fun provideDeviceHardwareDao(database: MeshtasticDatabase): DeviceHardwareDao {
return database.deviceHardwareDao()
}
@Provides
fun provideFirmwareReleaseDao(database: MeshtasticDatabase): FirmwareReleaseDao {
return database.firmwareReleaseDao()
}
fun provideFirmwareReleaseDao(database: MeshtasticDatabase): FirmwareReleaseDao = database.firmwareReleaseDao()
}

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.database.entity
package org.meshtastic.core.database.entity
import androidx.room.ColumnInfo
import androidx.room.Entity

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.database.entity
package org.meshtastic.core.database.entity
import androidx.room.ColumnInfo
import androidx.room.Entity

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.database.entity
package org.meshtastic.core.database.entity
import androidx.room.ColumnInfo
import androidx.room.Entity
@ -27,13 +27,8 @@ import com.geeksville.mesh.Portnums
import com.google.protobuf.TextFormat
import java.io.IOException
@Entity(
tableName = "log",
indices = [
Index(value = ["from_num"]),
Index(value = ["port_num"]),
],
)
@Suppress("EmptyCatchBlock", "SwallowedException", "ConstructorParameterNaming")
@Entity(tableName = "log", indices = [Index(value = ["from_num"]), Index(value = ["port_num"])])
data class MeshLog(
@PrimaryKey val uuid: String,
@ColumnInfo(name = "type") val message_type: String,
@ -52,8 +47,7 @@ data class MeshLog(
try {
TextFormat.getParser().merge(raw_message, builder)
return builder.build()
} catch (e: IOException) {
}
} catch (e: IOException) {}
}
return null
}
@ -65,8 +59,7 @@ data class MeshLog(
try {
TextFormat.getParser().merge(raw_message, builder)
return builder.build()
} catch (e: IOException) {
}
} catch (e: IOException) {}
}
return null
}
@ -78,8 +71,7 @@ data class MeshLog(
try {
TextFormat.getParser().merge(raw_message, builder)
return builder.build()
} catch (e: IOException) {
}
} catch (e: IOException) {}
}
return null
}

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.database.entity
package org.meshtastic.core.database.entity
import androidx.room.Entity
import androidx.room.PrimaryKey

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.database.entity
package org.meshtastic.core.database.entity
import androidx.room.ColumnInfo
import androidx.room.Embedded
@ -27,9 +27,9 @@ import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.PaxcountProtos
import com.geeksville.mesh.TelemetryProtos
import com.geeksville.mesh.copy
import com.geeksville.mesh.model.Node
import com.google.protobuf.ByteString
import com.google.protobuf.kotlin.isNotEmpty
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.model.DeviceMetrics
import org.meshtastic.core.model.EnvironmentMetrics
import org.meshtastic.core.model.MeshUser

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.database.entity
package org.meshtastic.core.database.entity
import androidx.room.ColumnInfo
import androidx.room.Embedded
@ -24,8 +24,8 @@ import androidx.room.Index
import androidx.room.PrimaryKey
import androidx.room.Relation
import com.geeksville.mesh.MeshProtos.User
import com.geeksville.mesh.model.Message
import com.geeksville.mesh.model.Node
import org.meshtastic.core.database.model.Message
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.model.DataPacket
import org.meshtastic.core.model.util.getShortDateTime
@ -57,6 +57,7 @@ data class PacketEntity(
}
}
@Suppress("ConstructorParameterNaming")
@Entity(
tableName = "packet",
indices = [Index(value = ["myNodeNum"]), Index(value = ["port_num"]), Index(value = ["contact_key"])],
@ -77,6 +78,7 @@ data class Packet(
@ColumnInfo(name = "hopsAway", defaultValue = "-1") val hopsAway: Int = -1,
)
@Suppress("ConstructorParameterNaming")
@Entity(tableName = "contact_settings")
data class ContactSettings(@PrimaryKey val contact_key: String, val muteUntil: Long = 0L) {
val isMuted

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.database.entity
package org.meshtastic.core.database.entity
import androidx.room.ColumnInfo
import androidx.room.Entity
@ -27,7 +27,7 @@ data class QuickChatAction(
@ColumnInfo(name = "name") val name: String = "",
@ColumnInfo(name = "message") val message: String = "",
@ColumnInfo(name = "mode") val mode: Mode = Mode.Instant,
@ColumnInfo(name = "position") val position: Int
@ColumnInfo(name = "position") val position: Int,
) {
enum class Mode {
Append,

View file

@ -15,11 +15,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.model
package org.meshtastic.core.database.model
import androidx.annotation.StringRes
import com.geeksville.mesh.MeshProtos.Routing
import com.geeksville.mesh.database.entity.Reaction
import org.meshtastic.core.database.entity.Reaction
import org.meshtastic.core.model.MessageStatus
import org.meshtastic.core.strings.R

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.model
package org.meshtastic.core.database.model
import android.graphics.Color
import com.geeksville.mesh.ConfigProtos
@ -25,13 +25,13 @@ import com.geeksville.mesh.PaxcountProtos
import com.geeksville.mesh.TelemetryProtos.DeviceMetrics
import com.geeksville.mesh.TelemetryProtos.EnvironmentMetrics
import com.geeksville.mesh.TelemetryProtos.PowerMetrics
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.util.toDistanceString
import com.google.protobuf.ByteString
import com.google.protobuf.kotlin.isNotEmpty
import org.meshtastic.core.database.entity.NodeEntity
import org.meshtastic.core.model.util.GPSFormat
import org.meshtastic.core.model.util.UnitConversions.celsiusToFahrenheit
import org.meshtastic.core.model.util.latLongToMeter
import org.meshtastic.core.model.util.toDistanceString
@Suppress("MagicNumber")
data class Node(

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.model
package org.meshtastic.core.database.model
import androidx.annotation.StringRes
import org.meshtastic.core.strings.R

View file

@ -15,18 +15,16 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.util
@file:Suppress("MatchingDeclarationName")
package org.meshtastic.core.model.util
import android.icu.util.LocaleData
import android.icu.util.ULocale
import com.geeksville.mesh.ConfigProtos.Config.DisplayConfig.DisplayUnits
import java.util.Locale
enum class DistanceUnit(
val symbol: String,
val multiplier: Float,
val system: Int
) {
enum class DistanceUnit(val symbol: String, val multiplier: Float, val system: Int) {
METER("m", multiplier = 1F, DisplayUnits.METRIC_VALUE),
KILOMETER("km", multiplier = 0.001F, DisplayUnits.METRIC_VALUE),
FOOT("ft", multiplier = 3.28084F, DisplayUnits.IMPERIAL_VALUE),
@ -34,75 +32,76 @@ enum class DistanceUnit(
;
companion object {
fun getFromLocale(locale: Locale = Locale.getDefault()): DisplayUnits {
return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
fun getFromLocale(locale: Locale = Locale.getDefault()): DisplayUnits =
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
when (LocaleData.getMeasurementSystem(ULocale.forLocale(locale))) {
LocaleData.MeasurementSystem.SI -> DisplayUnits.METRIC
else -> DisplayUnits.IMPERIAL
}
} else {
when (locale.country.uppercase(locale)) {
"US", "LR", "MM", "GB" -> DisplayUnits.IMPERIAL
"US",
"LR",
"MM",
"GB",
-> DisplayUnits.IMPERIAL
else -> DisplayUnits.METRIC
}
}
}
}
}
fun Int.metersIn(unit: DistanceUnit): Float {
return this * unit.multiplier
}
fun Int.metersIn(unit: DistanceUnit): Float = this * unit.multiplier
fun Int.metersIn(system: DisplayUnits): Float {
val unit = when (system.number) {
DisplayUnits.IMPERIAL_VALUE -> DistanceUnit.FOOT
else -> DistanceUnit.METER
}
val unit =
when (system.number) {
DisplayUnits.IMPERIAL_VALUE -> DistanceUnit.FOOT
else -> DistanceUnit.METER
}
return this.metersIn(unit)
}
fun Float.toString(unit: DistanceUnit): String {
return if (unit in setOf(DistanceUnit.METER, DistanceUnit.FOOT)) {
"%.0f %s"
} else {
"%.1f %s"
}.format(this, unit.symbol)
fun Float.toString(unit: DistanceUnit): String = if (unit in setOf(DistanceUnit.METER, DistanceUnit.FOOT)) {
"%.0f %s"
} else {
"%.1f %s"
}
.format(this, unit.symbol)
fun Float.toString(system: DisplayUnits): String {
val unit = when (system.number) {
DisplayUnits.IMPERIAL_VALUE -> DistanceUnit.FOOT
else -> DistanceUnit.METER
}
val unit =
when (system.number) {
DisplayUnits.IMPERIAL_VALUE -> DistanceUnit.FOOT
else -> DistanceUnit.METER
}
return this.toString(unit)
}
private const val KILOMETER_THRESHOLD = 1000
private const val MILE_THRESHOLD = 1609
fun Int.toDistanceString(system: DisplayUnits): String {
val unit = if (system.number == DisplayUnits.METRIC_VALUE) {
if (this < KILOMETER_THRESHOLD) DistanceUnit.METER else DistanceUnit.KILOMETER
} else {
if (this < MILE_THRESHOLD) DistanceUnit.FOOT else DistanceUnit.MILE
}
val unit =
if (system.number == DisplayUnits.METRIC_VALUE) {
if (this < KILOMETER_THRESHOLD) DistanceUnit.METER else DistanceUnit.KILOMETER
} else {
if (this < MILE_THRESHOLD) DistanceUnit.FOOT else DistanceUnit.MILE
}
val valueInUnit = this * unit.multiplier
return valueInUnit.toString(unit)
}
@Suppress("MagicNumber")
fun Float.toSpeedString(system: DisplayUnits): String =
if (system == DisplayUnits.METRIC) {
"%.0f km/h".format(this * 3.6)
} else {
"%.0f mph".format(this * 2.23694f)
}
fun Float.toSpeedString(system: DisplayUnits): String = if (system == DisplayUnits.METRIC) {
"%.0f km/h".format(this * 3.6)
} else {
"%.0f mph".format(this * 2.23694f)
}
@Suppress("MagicNumber")
fun Float.toSmallDistanceString(system: DisplayUnits): String {
return if (system == DisplayUnits.IMPERIAL) {
"%.2f in".format(this / 25.4f)
} else {
"%.0f mm".format(this)
}
fun Float.toSmallDistanceString(system: DisplayUnits): String = if (system == DisplayUnits.IMPERIAL) {
"%.2f in".format(this / 25.4f)
} else {
"%.0f mm".format(this)
}

View file

@ -17,8 +17,21 @@ import org.gradle.kotlin.dsl.maven
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
include(":app", ":core:data", ":core:datastore", ":core:di", ":core:model", ":core:navigation", ":core:network", ":core:prefs", ":core:proto",
":core:strings", ":feature:map", ":mesh_service_example")
include(
":app",
":core:data",
":core:database",
":core:datastore",
":core:di",
":core:model",
":core:navigation",
":core:network",
":core:prefs",
":core:proto",
":core:strings",
":feature:map",
":mesh_service_example",
)
rootProject.name = "MeshtasticAndroid"
// https://docs.gradle.org/current/userguide/declaring_dependencies.html#sec:type-safe-project-accessors