mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
refactor: migrate from Hilt to Koin and expand KMP common modules (#4746)
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
parent
a5390a80e7
commit
875cf1cff2
440 changed files with 3738 additions and 3508 deletions
|
|
@ -75,7 +75,7 @@ The module follows a clean architecture approach:
|
|||
|
||||
- **Repository Pattern:** `BluetoothRepository` mediates data access.
|
||||
- **Coroutines & Flow:** All asynchronous operations use Kotlin Coroutines and Flows.
|
||||
- **Dependency Injection:** Hilt is used for dependency injection.
|
||||
- **Dependency Injection:** Koin is used for dependency injection.
|
||||
|
||||
## Testing
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
plugins {
|
||||
alias(libs.plugins.meshtastic.kmp.library)
|
||||
alias(libs.plugins.devtools.ksp)
|
||||
id("meshtastic.koin")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
|
|
@ -35,11 +35,9 @@ kotlin {
|
|||
|
||||
implementation(libs.kermit)
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
api(libs.javax.inject)
|
||||
}
|
||||
|
||||
androidMain.dependencies {
|
||||
implementation(libs.hilt.android)
|
||||
api(libs.nordic.client.android)
|
||||
api(libs.nordic.ble.env.android)
|
||||
api(libs.nordic.ble.env.android.compose)
|
||||
|
|
@ -65,5 +63,3 @@ kotlin {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies { add("kspAndroid", libs.hilt.compiler) }
|
||||
|
|
|
|||
|
|
@ -18,13 +18,11 @@ package org.meshtastic.core.ble
|
|||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import no.nordicsemi.kotlin.ble.client.android.CentralManager
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import org.koin.core.annotation.Single
|
||||
|
||||
/** An Android implementation of [BleConnectionFactory]. */
|
||||
@Singleton
|
||||
class AndroidBleConnectionFactory @Inject constructor(private val centralManager: CentralManager) :
|
||||
BleConnectionFactory {
|
||||
@Single
|
||||
class AndroidBleConnectionFactory(private val centralManager: CentralManager) : BleConnectionFactory {
|
||||
override fun create(scope: CoroutineScope, tag: String): BleConnection =
|
||||
AndroidBleConnection(centralManager, scope, tag)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import kotlinx.coroutines.flow.Flow
|
|||
import kotlinx.coroutines.flow.map
|
||||
import no.nordicsemi.kotlin.ble.client.android.CentralManager
|
||||
import no.nordicsemi.kotlin.ble.client.distinctByPeripheral
|
||||
import javax.inject.Inject
|
||||
import org.koin.core.annotation.Single
|
||||
import kotlin.time.Duration
|
||||
|
||||
/**
|
||||
|
|
@ -28,7 +28,8 @@ import kotlin.time.Duration
|
|||
*
|
||||
* @param centralManager The Nordic [CentralManager] to use for scanning.
|
||||
*/
|
||||
class AndroidBleScanner @Inject constructor(private val centralManager: CentralManager) : BleScanner {
|
||||
@Single
|
||||
class AndroidBleScanner(private val centralManager: CentralManager) : BleScanner {
|
||||
|
||||
override fun scan(timeout: Duration): Flow<BleDevice> =
|
||||
centralManager.scan(timeout).distinctByPeripheral().map { AndroidBleDevice(it.peripheral) }
|
||||
|
|
|
|||
|
|
@ -29,20 +29,17 @@ import no.nordicsemi.kotlin.ble.client.RemoteServices
|
|||
import no.nordicsemi.kotlin.ble.client.android.CentralManager
|
||||
import no.nordicsemi.kotlin.ble.client.android.Peripheral
|
||||
import no.nordicsemi.kotlin.ble.core.android.AndroidEnvironment
|
||||
import org.koin.core.annotation.Named
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.ble.MeshtasticBleConstants.BLE_NAME_PATTERN
|
||||
import org.meshtastic.core.ble.MeshtasticBleConstants.SERVICE_UUID
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
import org.meshtastic.core.di.ProcessLifecycle
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/** Android implementation of [BluetoothRepository]. */
|
||||
@Singleton
|
||||
class AndroidBluetoothRepository
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class AndroidBluetoothRepository(
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
@ProcessLifecycle private val processLifecycle: Lifecycle,
|
||||
@Named("ProcessLifecycle") private val processLifecycle: Lifecycle,
|
||||
private val centralManager: CentralManager,
|
||||
private val androidEnvironment: AndroidEnvironment,
|
||||
) : BluetoothRepository {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.ble.di
|
||||
|
||||
import android.app.Application
|
||||
import android.location.LocationManager
|
||||
import androidx.core.content.ContextCompat
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import no.nordicsemi.kotlin.ble.client.android.CentralManager
|
||||
import no.nordicsemi.kotlin.ble.client.android.native
|
||||
import no.nordicsemi.kotlin.ble.core.android.AndroidEnvironment
|
||||
import no.nordicsemi.kotlin.ble.environment.android.NativeAndroidEnvironment
|
||||
import org.koin.core.annotation.ComponentScan
|
||||
import org.koin.core.annotation.Module
|
||||
import org.koin.core.annotation.Single
|
||||
|
||||
@Module
|
||||
@ComponentScan("org.meshtastic.core.ble")
|
||||
class CoreBleAndroidModule {
|
||||
@Single
|
||||
fun provideAndroidEnvironment(app: Application): AndroidEnvironment =
|
||||
NativeAndroidEnvironment.getInstance(app, isNeverForLocationFlagSet = true)
|
||||
|
||||
@Single
|
||||
fun provideCentralManager(environment: AndroidEnvironment): CentralManager = CentralManager.native(
|
||||
environment as NativeAndroidEnvironment,
|
||||
CoroutineScope(SupervisorJob() + Dispatchers.Default),
|
||||
)
|
||||
|
||||
@Single
|
||||
fun provideLocationManager(app: Application): LocationManager =
|
||||
ContextCompat.getSystemService(app, LocationManager::class.java)!!
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.ble.di
|
||||
|
||||
import org.koin.core.annotation.ComponentScan
|
||||
import org.koin.core.annotation.Module
|
||||
|
||||
@Module
|
||||
@ComponentScan("org.meshtastic.core.ble")
|
||||
class CoreBleModule
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
plugins {
|
||||
alias(libs.plugins.meshtastic.kmp.library)
|
||||
alias(libs.plugins.kotlin.parcelize)
|
||||
id("meshtastic.koin")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.common.di
|
||||
|
||||
import org.koin.core.annotation.ComponentScan
|
||||
import org.koin.core.annotation.Module
|
||||
|
||||
@Module
|
||||
@ComponentScan("org.meshtastic.core.common")
|
||||
class CoreCommonModule
|
||||
|
|
@ -21,15 +21,16 @@ import kotlinx.coroutines.CoroutineScope
|
|||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.TimeoutCancellationException
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import org.koin.core.annotation.Factory
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* A helper class that manages a single [Job]. When a new job is launched, any previous job is cancelled. This is useful
|
||||
* for ensuring that only the latest operation of a certain type is running at a time (e.g. for search or settings
|
||||
* updates).
|
||||
*/
|
||||
class SequentialJob @Inject constructor() {
|
||||
@Factory
|
||||
class SequentialJob {
|
||||
private val job = AtomicReference<Job?>()
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
plugins {
|
||||
alias(libs.plugins.meshtastic.kmp.library)
|
||||
alias(libs.plugins.meshtastic.kotlinx.serialization)
|
||||
alias(libs.plugins.devtools.ksp)
|
||||
id("meshtastic.koin")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
|
|
@ -41,7 +41,6 @@ kotlin {
|
|||
implementation(projects.core.prefs)
|
||||
implementation(projects.core.proto)
|
||||
|
||||
api(libs.javax.inject)
|
||||
implementation(libs.androidx.lifecycle.runtime)
|
||||
implementation(libs.androidx.paging.common)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
|
|
@ -51,7 +50,6 @@ kotlin {
|
|||
}
|
||||
|
||||
androidMain.dependencies {
|
||||
implementation(libs.hilt.android)
|
||||
implementation(libs.androidx.core.ktx)
|
||||
implementation(libs.androidx.core.location.altitude)
|
||||
|
||||
|
|
@ -68,5 +66,3 @@ kotlin {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies { add("kspAndroid", libs.hilt.compiler) }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<SmellBaseline>
|
||||
<ManuallySuppressedIssues/>
|
||||
<CurrentIssues>
|
||||
<ID>MaxLineLength:BootloaderOtaQuirksJsonDataSourceImpl.kt$BootloaderOtaQuirksJsonDataSourceImpl$class</ID>
|
||||
</CurrentIssues>
|
||||
<CurrentIssues/>
|
||||
</SmellBaseline>
|
||||
|
|
|
|||
|
|
@ -22,11 +22,11 @@ import kotlinx.serialization.ExperimentalSerializationApi
|
|||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.decodeFromStream
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.model.BootloaderOtaQuirk
|
||||
import javax.inject.Inject
|
||||
|
||||
class BootloaderOtaQuirksJsonDataSourceImpl @Inject constructor(private val application: Application) :
|
||||
BootloaderOtaQuirksJsonDataSource {
|
||||
@Single
|
||||
class BootloaderOtaQuirksJsonDataSourceImpl(private val application: Application) : BootloaderOtaQuirksJsonDataSource {
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
override fun loadBootloaderOtaQuirksFromJsonAsset(): List<BootloaderOtaQuirk> = runCatching {
|
||||
val inputStream = application.assets.open("device_bootloader_ota_quirks.json")
|
||||
|
|
|
|||
|
|
@ -20,11 +20,11 @@ import android.app.Application
|
|||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.decodeFromStream
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.model.NetworkDeviceHardware
|
||||
import javax.inject.Inject
|
||||
|
||||
class DeviceHardwareJsonDataSourceImpl @Inject constructor(private val application: Application) :
|
||||
DeviceHardwareJsonDataSource {
|
||||
@Single
|
||||
class DeviceHardwareJsonDataSourceImpl(private val application: Application) : DeviceHardwareJsonDataSource {
|
||||
|
||||
// Use a tolerant JSON parser so that additional fields in the bundled asset
|
||||
// (e.g., "key") do not break deserialization on older app versions.
|
||||
|
|
|
|||
|
|
@ -20,11 +20,11 @@ import android.app.Application
|
|||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.decodeFromStream
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.model.NetworkFirmwareReleases
|
||||
import javax.inject.Inject
|
||||
|
||||
class FirmwareReleaseJsonDataSourceImpl @Inject constructor(private val application: Application) :
|
||||
FirmwareReleaseJsonDataSource {
|
||||
@Single
|
||||
class FirmwareReleaseJsonDataSourceImpl(private val application: Application) : FirmwareReleaseJsonDataSource {
|
||||
|
||||
// Match the network client behavior: be tolerant of unknown fields so that
|
||||
// older app versions can read newer snapshots of firmware_releases.json.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.data.di
|
||||
|
||||
import org.koin.core.annotation.ComponentScan
|
||||
import org.koin.core.annotation.Module
|
||||
|
||||
@Module
|
||||
@ComponentScan("org.meshtastic.core.data")
|
||||
class CoreDataAndroidModule
|
||||
|
|
@ -34,19 +34,16 @@ import kotlinx.coroutines.flow.Flow
|
|||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
import org.meshtastic.core.repository.Location
|
||||
import org.meshtastic.core.repository.LocationRepository
|
||||
import org.meshtastic.core.repository.PlatformAnalytics
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class LocationRepositoryImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class LocationRepositoryImpl(
|
||||
private val context: Application,
|
||||
private val locationManager: dagger.Lazy<LocationManager>,
|
||||
private val locationManager: Lazy<LocationManager>,
|
||||
private val analytics: PlatformAnalytics,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
) : LocationRepository {
|
||||
|
|
@ -125,5 +122,5 @@ constructor(
|
|||
|
||||
/** Observable flow for location updates */
|
||||
@RequiresPermission(anyOf = [ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION])
|
||||
override fun getLocations(): Flow<Location> = locationManager.get().requestLocationUpdates()
|
||||
override fun getLocations(): Flow<Location> = locationManager.value.requestLocationUpdates()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,16 +17,15 @@
|
|||
package org.meshtastic.core.data.datasource
|
||||
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.database.DatabaseManager
|
||||
import org.meshtastic.core.database.entity.DeviceHardwareEntity
|
||||
import org.meshtastic.core.database.entity.asEntity
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
import org.meshtastic.core.model.NetworkDeviceHardware
|
||||
import javax.inject.Inject
|
||||
|
||||
class DeviceHardwareLocalDataSource
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class DeviceHardwareLocalDataSource(
|
||||
private val dbManager: DatabaseManager,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package org.meshtastic.core.data.datasource
|
||||
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.database.DatabaseManager
|
||||
import org.meshtastic.core.database.entity.FirmwareReleaseEntity
|
||||
import org.meshtastic.core.database.entity.FirmwareReleaseType
|
||||
|
|
@ -24,11 +25,9 @@ import org.meshtastic.core.database.entity.asDeviceVersion
|
|||
import org.meshtastic.core.database.entity.asEntity
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
import org.meshtastic.core.model.NetworkFirmwareRelease
|
||||
import javax.inject.Inject
|
||||
|
||||
class FirmwareReleaseLocalDataSource
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class FirmwareReleaseLocalDataSource(
|
||||
private val dbManager: DatabaseManager,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -18,16 +18,14 @@ package org.meshtastic.core.data.datasource
|
|||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.database.DatabaseManager
|
||||
import org.meshtastic.core.database.entity.MyNodeEntity
|
||||
import org.meshtastic.core.database.entity.NodeEntity
|
||||
import org.meshtastic.core.database.entity.NodeWithRelations
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class SwitchingNodeInfoReadDataSource @Inject constructor(private val dbManager: DatabaseManager) :
|
||||
NodeInfoReadDataSource {
|
||||
@Single
|
||||
class SwitchingNodeInfoReadDataSource(private val dbManager: DatabaseManager) : NodeInfoReadDataSource {
|
||||
|
||||
override fun myNodeInfoFlow(): Flow<MyNodeEntity?> =
|
||||
dbManager.currentDb.flatMapLatest { db -> db.nodeInfoDao().getMyNodeInfo() }
|
||||
|
|
|
|||
|
|
@ -17,18 +17,15 @@
|
|||
package org.meshtastic.core.data.datasource
|
||||
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.database.DatabaseManager
|
||||
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.di.CoroutineDispatchers
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class SwitchingNodeInfoWriteDataSource
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class SwitchingNodeInfoWriteDataSource(
|
||||
private val dbManager: DatabaseManager,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
) : NodeInfoWriteDataSource {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.data.di
|
||||
|
||||
import org.koin.core.annotation.ComponentScan
|
||||
import org.koin.core.annotation.Module
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.model.util.MeshDataMapper
|
||||
import org.meshtastic.core.model.util.NodeIdLookup
|
||||
|
||||
@Module
|
||||
@ComponentScan("org.meshtastic.core.data")
|
||||
class CoreDataModule {
|
||||
@Single fun provideMeshDataMapper(nodeIdLookup: NodeIdLookup): MeshDataMapper = MeshDataMapper(nodeIdLookup)
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ import kotlinx.coroutines.flow.launchIn
|
|||
import kotlinx.coroutines.flow.onEach
|
||||
import okio.ByteString
|
||||
import okio.ByteString.Companion.toByteString
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.core.model.MessageStatus
|
||||
|
|
@ -46,17 +47,13 @@ import org.meshtastic.proto.Neighbor
|
|||
import org.meshtastic.proto.NeighborInfo
|
||||
import org.meshtastic.proto.PortNum
|
||||
import org.meshtastic.proto.Telemetry
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.random.Random
|
||||
import kotlin.time.Duration.Companion.hours
|
||||
|
||||
@Suppress("TooManyFunctions", "CyclomaticComplexMethod")
|
||||
@Singleton
|
||||
class CommandSenderImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class CommandSenderImpl(
|
||||
private val packetHandler: PacketHandler,
|
||||
private val nodeManager: NodeManager,
|
||||
private val radioConfigRepository: RadioConfigRepository,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
package org.meshtastic.core.data.manager
|
||||
|
||||
import dagger.Lazy
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.repository.FromRadioPacketHandler
|
||||
import org.meshtastic.core.repository.MeshRouter
|
||||
import org.meshtastic.core.repository.MeshServiceNotifications
|
||||
|
|
@ -24,14 +24,10 @@ import org.meshtastic.core.repository.MqttManager
|
|||
import org.meshtastic.core.repository.PacketHandler
|
||||
import org.meshtastic.core.repository.ServiceRepository
|
||||
import org.meshtastic.proto.FromRadio
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/** Implementation of [FromRadioPacketHandler] that dispatches [FromRadio] variants to specialized handlers. */
|
||||
@Singleton
|
||||
class FromRadioPacketHandlerImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class FromRadioPacketHandlerImpl(
|
||||
private val serviceRepository: ServiceRepository,
|
||||
private val router: Lazy<MeshRouter>,
|
||||
private val mqttManager: MqttManager,
|
||||
|
|
@ -52,18 +48,18 @@ constructor(
|
|||
val clientNotification = proto.clientNotification
|
||||
|
||||
when {
|
||||
myInfo != null -> router.get().configFlowManager.handleMyInfo(myInfo)
|
||||
metadata != null -> router.get().configFlowManager.handleLocalMetadata(metadata)
|
||||
myInfo != null -> router.value.configFlowManager.handleMyInfo(myInfo)
|
||||
metadata != null -> router.value.configFlowManager.handleLocalMetadata(metadata)
|
||||
nodeInfo != null -> {
|
||||
router.get().configFlowManager.handleNodeInfo(nodeInfo)
|
||||
serviceRepository.setConnectionProgress("Nodes (${router.get().configFlowManager.newNodeCount})")
|
||||
router.value.configFlowManager.handleNodeInfo(nodeInfo)
|
||||
serviceRepository.setConnectionProgress("Nodes (${router.value.configFlowManager.newNodeCount})")
|
||||
}
|
||||
configCompleteId != null -> router.get().configFlowManager.handleConfigComplete(configCompleteId)
|
||||
configCompleteId != null -> router.value.configFlowManager.handleConfigComplete(configCompleteId)
|
||||
mqttProxyMessage != null -> mqttManager.handleMqttProxyMessage(mqttProxyMessage)
|
||||
queueStatus != null -> packetHandler.handleQueueStatus(queueStatus)
|
||||
config != null -> router.get().configHandler.handleDeviceConfig(config)
|
||||
moduleConfig != null -> router.get().configHandler.handleModuleConfig(moduleConfig)
|
||||
channel != null -> router.get().configHandler.handleChannel(channel)
|
||||
config != null -> router.value.configHandler.handleDeviceConfig(config)
|
||||
moduleConfig != null -> router.value.configHandler.handleModuleConfig(moduleConfig)
|
||||
channel != null -> router.value.configHandler.handleChannel(channel)
|
||||
clientNotification != null -> {
|
||||
serviceRepository.setClientNotification(clientNotification)
|
||||
serviceNotifications.showClientNotification(clientNotification)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package org.meshtastic.core.data.manager
|
|||
|
||||
import co.touchlab.kermit.Logger
|
||||
import okio.ByteString.Companion.toByteString
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.repository.HistoryManager
|
||||
import org.meshtastic.core.repository.MeshPrefs
|
||||
import org.meshtastic.core.repository.PacketHandler
|
||||
|
|
@ -26,16 +27,9 @@ import org.meshtastic.proto.MeshPacket
|
|||
import org.meshtastic.proto.ModuleConfig
|
||||
import org.meshtastic.proto.PortNum
|
||||
import org.meshtastic.proto.StoreAndForward
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class HistoryManagerImpl
|
||||
@Inject
|
||||
constructor(
|
||||
private val meshPrefs: MeshPrefs,
|
||||
private val packetHandler: PacketHandler,
|
||||
) : HistoryManager {
|
||||
@Single
|
||||
class HistoryManagerImpl(private val meshPrefs: MeshPrefs, private val packetHandler: PacketHandler) : HistoryManager {
|
||||
|
||||
companion object {
|
||||
private const val HISTORY_TAG = "HistoryReplay"
|
||||
|
|
|
|||
|
|
@ -16,11 +16,11 @@
|
|||
*/
|
||||
package org.meshtastic.core.data.manager
|
||||
|
||||
import dagger.Lazy
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import okio.ByteString.Companion.toByteString
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.database.DatabaseManager
|
||||
import org.meshtastic.core.common.util.handledLaunch
|
||||
import org.meshtastic.core.common.util.ignoreException
|
||||
|
|
@ -49,14 +49,10 @@ import org.meshtastic.proto.ModuleConfig
|
|||
import org.meshtastic.proto.OTAMode
|
||||
import org.meshtastic.proto.PortNum
|
||||
import org.meshtastic.proto.User
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Suppress("LongParameterList", "TooManyFunctions", "CyclomaticComplexMethod")
|
||||
@Singleton
|
||||
class MeshActionHandlerImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class MeshActionHandlerImpl(
|
||||
private val nodeManager: NodeManager,
|
||||
private val commandSender: CommandSender,
|
||||
private val packetRepository: Lazy<PacketRepository>,
|
||||
|
|
@ -123,7 +119,7 @@ constructor(
|
|||
}
|
||||
}
|
||||
nodeManager.updateNode(node.num) { it.copy(isIgnored = newIgnoredStatus) }
|
||||
scope.handledLaunch { packetRepository.get().updateFilteredBySender(node.user.id, newIgnoredStatus) }
|
||||
scope.handledLaunch { packetRepository.value.updateFilteredBySender(node.user.id, newIgnoredStatus) }
|
||||
}
|
||||
|
||||
private fun handleMute(action: ServiceAction.Mute, myNodeNum: Int) {
|
||||
|
|
@ -177,7 +173,7 @@ constructor(
|
|||
to = action.contactKey.substring(1),
|
||||
channel = action.contactKey[0].digitToInt(),
|
||||
)
|
||||
packetRepository.get().insertReaction(reaction, myNodeNum)
|
||||
packetRepository.value.insertReaction(reaction, myNodeNum)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -190,7 +186,7 @@ constructor(
|
|||
override fun handleSend(p: DataPacket, myNodeNum: Int) {
|
||||
commandSender.sendData(p)
|
||||
serviceBroadcasts.broadcastMessageStatus(p.id, p.status ?: MessageStatus.UNKNOWN)
|
||||
dataHandler.get().rememberDataPacket(p, myNodeNum, false)
|
||||
dataHandler.value.rememberDataPacket(p, myNodeNum, false)
|
||||
val bytes = p.bytes ?: okio.ByteString.EMPTY
|
||||
analytics.track("data_send", DataPair("num_bytes", bytes.size), DataPair("type", p.dataType))
|
||||
}
|
||||
|
|
@ -348,7 +344,7 @@ constructor(
|
|||
meshPrefs.setDeviceAddress(deviceAddr)
|
||||
scope.handledLaunch {
|
||||
nodeManager.clear()
|
||||
messageProcessor.get().clearEarlyPackets()
|
||||
messageProcessor.value.clearEarlyPackets()
|
||||
databaseManager.switchActiveDatabase(deviceAddr)
|
||||
serviceNotifications.clearNotifications()
|
||||
nodeManager.loadCachedNodeDB()
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@
|
|||
package org.meshtastic.core.data.manager
|
||||
|
||||
import co.touchlab.kermit.Logger
|
||||
import dagger.Lazy
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.delay
|
||||
import okio.IOException
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.util.handledLaunch
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.repository.CommandSender
|
||||
|
|
@ -40,16 +40,12 @@ import org.meshtastic.proto.HardwareModel
|
|||
import org.meshtastic.proto.Heartbeat
|
||||
import org.meshtastic.proto.NodeInfo
|
||||
import org.meshtastic.proto.ToRadio
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import org.meshtastic.core.model.MyNodeInfo as SharedMyNodeInfo
|
||||
import org.meshtastic.proto.MyNodeInfo as ProtoMyNodeInfo
|
||||
|
||||
@Suppress("LongParameterList", "TooManyFunctions")
|
||||
@Singleton
|
||||
class MeshConfigFlowManagerImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class MeshConfigFlowManagerImpl(
|
||||
private val nodeManager: NodeManager,
|
||||
private val connectionManager: Lazy<MeshConnectionManager>,
|
||||
private val nodeRepository: NodeRepository,
|
||||
|
|
@ -101,7 +97,7 @@ constructor(
|
|||
} else {
|
||||
myNodeInfo = finalizedInfo
|
||||
Logger.i { "myNodeInfo committed successfully (nodeNum=${finalizedInfo.myNodeNum})" }
|
||||
connectionManager.get().onRadioConfigLoaded()
|
||||
connectionManager.value.onRadioConfigLoaded()
|
||||
}
|
||||
|
||||
scope.handledLaunch {
|
||||
|
|
@ -109,7 +105,7 @@ constructor(
|
|||
sendHeartbeat()
|
||||
delay(wantConfigDelay)
|
||||
Logger.i { "Requesting NodeInfo (Stage 2)" }
|
||||
connectionManager.get().startNodeInfoOnly()
|
||||
connectionManager.value.startNodeInfoOnly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +136,7 @@ constructor(
|
|||
nodeManager.setAllowNodeDbWrites(true)
|
||||
serviceRepository.setConnectionState(ConnectionState.Connected)
|
||||
serviceBroadcasts.broadcastConnection()
|
||||
connectionManager.get().onNodeDbReady()
|
||||
connectionManager.value.onNodeDbReady()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -172,7 +168,7 @@ constructor(
|
|||
}
|
||||
|
||||
override fun triggerWantConfig() {
|
||||
connectionManager.get().startConfigOnly()
|
||||
connectionManager.value.startConfigOnly()
|
||||
}
|
||||
|
||||
private fun regenMyNodeInfo(metadata: DeviceMetadata? = null) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
|||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.util.handledLaunch
|
||||
import org.meshtastic.core.repository.MeshConfigHandler
|
||||
import org.meshtastic.core.repository.NodeManager
|
||||
|
|
@ -33,13 +34,9 @@ import org.meshtastic.proto.Config
|
|||
import org.meshtastic.proto.LocalConfig
|
||||
import org.meshtastic.proto.LocalModuleConfig
|
||||
import org.meshtastic.proto.ModuleConfig
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class MeshConfigHandlerImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class MeshConfigHandlerImpl(
|
||||
private val radioConfigRepository: RadioConfigRepository,
|
||||
private val serviceRepository: ServiceRepository,
|
||||
private val nodeManager: NodeManager,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import kotlinx.coroutines.flow.first
|
|||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.util.handledLaunch
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.common.util.nowSeconds
|
||||
|
|
@ -63,17 +64,13 @@ import org.meshtastic.proto.AdminMessage
|
|||
import org.meshtastic.proto.Config
|
||||
import org.meshtastic.proto.Telemetry
|
||||
import org.meshtastic.proto.ToRadio
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import kotlin.time.DurationUnit
|
||||
|
||||
@Suppress("LongParameterList", "TooManyFunctions")
|
||||
@Singleton
|
||||
class MeshConnectionManagerImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class MeshConnectionManagerImpl(
|
||||
private val radioInterfaceService: RadioInterfaceService,
|
||||
private val serviceRepository: ServiceRepository,
|
||||
private val serviceBroadcasts: ServiceBroadcasts,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ package org.meshtastic.core.data.manager
|
|||
|
||||
import co.touchlab.kermit.Logger
|
||||
import co.touchlab.kermit.Severity
|
||||
import dagger.Lazy
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
|
|
@ -29,6 +28,7 @@ import kotlinx.coroutines.sync.Mutex
|
|||
import kotlinx.coroutines.sync.withLock
|
||||
import okio.ByteString.Companion.toByteString
|
||||
import okio.IOException
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.util.handledLaunch
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.common.util.nowSeconds
|
||||
|
|
@ -76,8 +76,6 @@ import org.meshtastic.proto.StoreForwardPlusPlus
|
|||
import org.meshtastic.proto.Telemetry
|
||||
import org.meshtastic.proto.User
|
||||
import org.meshtastic.proto.Waypoint
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
/**
|
||||
|
|
@ -91,10 +89,8 @@ import kotlin.time.Duration.Companion.milliseconds
|
|||
* 5. Tracking received telemetry for node updates.
|
||||
*/
|
||||
@Suppress("LongParameterList", "TooManyFunctions", "LargeClass", "CyclomaticComplexMethod")
|
||||
@Singleton
|
||||
class MeshDataHandlerImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class MeshDataHandlerImpl(
|
||||
private val nodeManager: NodeManager,
|
||||
private val packetHandler: PacketHandler,
|
||||
private val serviceRepository: ServiceRepository,
|
||||
|
|
@ -291,17 +287,15 @@ constructor(
|
|||
"to=${sfpp.encapsulated_to} myNodeNum=${nodeManager.myNodeNum} status=$status"
|
||||
}
|
||||
scope.handledLaunch {
|
||||
packetRepository
|
||||
.get()
|
||||
.updateSFPPStatus(
|
||||
packetId = sfpp.encapsulated_id,
|
||||
from = sfpp.encapsulated_from,
|
||||
to = sfpp.encapsulated_to,
|
||||
hash = hash,
|
||||
status = status,
|
||||
rxTime = sfpp.encapsulated_rxtime.toLong() and 0xFFFFFFFFL,
|
||||
myNodeNum = nodeManager.myNodeNum ?: 0,
|
||||
)
|
||||
packetRepository.value.updateSFPPStatus(
|
||||
packetId = sfpp.encapsulated_id,
|
||||
from = sfpp.encapsulated_from,
|
||||
to = sfpp.encapsulated_to,
|
||||
hash = hash,
|
||||
status = status,
|
||||
rxTime = sfpp.encapsulated_rxtime.toLong() and 0xFFFFFFFFL,
|
||||
myNodeNum = nodeManager.myNodeNum ?: 0,
|
||||
)
|
||||
serviceBroadcasts.broadcastMessageStatus(sfpp.encapsulated_id, status)
|
||||
}
|
||||
}
|
||||
|
|
@ -309,13 +303,11 @@ constructor(
|
|||
StoreForwardPlusPlus.SFPP_message_type.CANON_ANNOUNCE -> {
|
||||
scope.handledLaunch {
|
||||
sfpp.message_hash.let {
|
||||
packetRepository
|
||||
.get()
|
||||
.updateSFPPStatusByHash(
|
||||
hash = it.toByteArray(),
|
||||
status = MessageStatus.SFPP_CONFIRMED,
|
||||
rxTime = sfpp.encapsulated_rxtime.toLong() and 0xFFFFFFFFL,
|
||||
)
|
||||
packetRepository.value.updateSFPPStatusByHash(
|
||||
hash = it.toByteArray(),
|
||||
status = MessageStatus.SFPP_CONFIRMED,
|
||||
rxTime = sfpp.encapsulated_rxtime.toLong() and 0xFFFFFFFFL,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -359,20 +351,20 @@ constructor(
|
|||
val fromNum = packet.from
|
||||
u.get_module_config_response?.let {
|
||||
if (fromNum == myNodeNum) {
|
||||
configHandler.get().handleModuleConfig(it)
|
||||
configHandler.value.handleModuleConfig(it)
|
||||
} else {
|
||||
it.statusmessage?.node_status?.let { nodeManager.updateNodeStatus(fromNum, it) }
|
||||
}
|
||||
}
|
||||
|
||||
if (fromNum == myNodeNum) {
|
||||
u.get_config_response?.let { configHandler.get().handleDeviceConfig(it) }
|
||||
u.get_channel_response?.let { configHandler.get().handleChannel(it) }
|
||||
u.get_config_response?.let { configHandler.value.handleDeviceConfig(it) }
|
||||
u.get_channel_response?.let { configHandler.value.handleChannel(it) }
|
||||
}
|
||||
|
||||
u.get_device_metadata_response?.let {
|
||||
if (fromNum == myNodeNum) {
|
||||
configFlowManager.get().handleLocalMetadata(it)
|
||||
configFlowManager.value.handleLocalMetadata(it)
|
||||
} else {
|
||||
nodeManager.insertMetadata(fromNum, it)
|
||||
}
|
||||
|
|
@ -414,7 +406,7 @@ constructor(
|
|||
val fromNum = packet.from
|
||||
val isRemote = (fromNum != myNodeNum)
|
||||
if (!isRemote) {
|
||||
connectionManager.get().updateTelemetry(t)
|
||||
connectionManager.value.updateTelemetry(t)
|
||||
}
|
||||
|
||||
nodeManager.updateNode(fromNum) { node: Node ->
|
||||
|
|
@ -508,8 +500,8 @@ constructor(
|
|||
private fun handleAckNak(requestId: Int, fromId: String, routingError: Int, relayNode: Int?) {
|
||||
scope.handledLaunch {
|
||||
val isAck = routingError == Routing.Error.NONE.value
|
||||
val p = packetRepository.get().getPacketByPacketId(requestId)
|
||||
val reaction = packetRepository.get().getReactionByPacketId(requestId)
|
||||
val p = packetRepository.value.getPacketByPacketId(requestId)
|
||||
val reaction = packetRepository.value.getReactionByPacketId(requestId)
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
Logger.d {
|
||||
|
|
@ -527,7 +519,7 @@ constructor(
|
|||
if (p != null && p.status != MessageStatus.RECEIVED) {
|
||||
val updatedPacket =
|
||||
p.copy(status = m, relays = if (isAck) p.relays + 1 else p.relays, relayNode = relayNode)
|
||||
packetRepository.get().update(updatedPacket)
|
||||
packetRepository.value.update(updatedPacket)
|
||||
}
|
||||
|
||||
reaction?.let { r ->
|
||||
|
|
@ -536,7 +528,7 @@ constructor(
|
|||
if (isAck) {
|
||||
updated = updated.copy(relays = updated.relays + 1)
|
||||
}
|
||||
packetRepository.get().updateReaction(updated)
|
||||
packetRepository.value.updateReaction(updated)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -601,7 +593,7 @@ constructor(
|
|||
val contactKey = "${dataPacket.channel}$contactId"
|
||||
|
||||
scope.handledLaunch {
|
||||
packetRepository.get().apply {
|
||||
packetRepository.value.apply {
|
||||
// Check for duplicates before inserting
|
||||
val existingPackets = findPacketsWithId(dataPacket.id)
|
||||
if (existingPackets.isNotEmpty()) {
|
||||
|
|
@ -646,7 +638,7 @@ constructor(
|
|||
contactKey: String,
|
||||
updateNotification: Boolean,
|
||||
) {
|
||||
val conversationMuted = packetRepository.get().getContactSettings(contactKey).isMuted
|
||||
val conversationMuted = packetRepository.value.getContactSettings(contactKey).isMuted
|
||||
val nodeMuted = nodeManager.nodeDBbyID[dataPacket.from]?.isMuted == true
|
||||
val isSilent = conversationMuted || nodeMuted
|
||||
if (dataPacket.dataType == PortNum.ALERT_APP.value && !isSilent) {
|
||||
|
|
@ -733,7 +725,7 @@ constructor(
|
|||
)
|
||||
|
||||
// Check for duplicates before inserting
|
||||
val existingReactions = packetRepository.get().findReactionsWithId(packet.id)
|
||||
val existingReactions = packetRepository.value.findReactionsWithId(packet.id)
|
||||
if (existingReactions.isNotEmpty()) {
|
||||
Logger.d {
|
||||
"Skipping duplicate reaction: packetId=${packet.id} replyId=${decoded.reply_id} " +
|
||||
|
|
@ -742,15 +734,15 @@ constructor(
|
|||
return@handledLaunch
|
||||
}
|
||||
|
||||
packetRepository.get().insertReaction(reaction, nodeManager.myNodeNum ?: 0)
|
||||
packetRepository.value.insertReaction(reaction, nodeManager.myNodeNum ?: 0)
|
||||
|
||||
// Find the original packet to get the contactKey
|
||||
packetRepository.get().getPacketByPacketId(decoded.reply_id)?.let { originalPacket ->
|
||||
packetRepository.value.getPacketByPacketId(decoded.reply_id)?.let { originalPacket ->
|
||||
// Skip notification if the original message was filtered
|
||||
val targetId =
|
||||
if (originalPacket.from == DataPacket.ID_LOCAL) originalPacket.to else originalPacket.from
|
||||
val contactKey = "${originalPacket.channel}$targetId"
|
||||
val conversationMuted = packetRepository.get().getContactSettings(contactKey).isMuted
|
||||
val conversationMuted = packetRepository.value.getContactSettings(contactKey).isMuted
|
||||
val nodeMuted = nodeManager.nodeDBbyID[fromId]?.isMuted == true
|
||||
val isSilent = conversationMuted || nodeMuted
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
package org.meshtastic.core.data.manager
|
||||
|
||||
import co.touchlab.kermit.Logger
|
||||
import dagger.Lazy
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
|
|
@ -27,6 +26,7 @@ import kotlinx.coroutines.flow.onEach
|
|||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.util.handledLaunch
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.common.util.nowSeconds
|
||||
|
|
@ -43,16 +43,12 @@ import org.meshtastic.proto.FromRadio
|
|||
import org.meshtastic.proto.LogRecord
|
||||
import org.meshtastic.proto.MeshPacket
|
||||
import org.meshtastic.proto.PortNum
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
/** Implementation of [MeshMessageProcessor] that handles raw radio messages and prepares mesh packets for routing. */
|
||||
@Suppress("TooManyFunctions")
|
||||
@Singleton
|
||||
class MeshMessageProcessorImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class MeshMessageProcessorImpl(
|
||||
private val nodeManager: NodeManager,
|
||||
private val serviceRepository: ServiceRepository,
|
||||
private val meshLogRepository: Lazy<MeshLogRepository>,
|
||||
|
|
@ -246,7 +242,7 @@ constructor(
|
|||
}
|
||||
|
||||
try {
|
||||
router.get().dataHandler.handleReceivedData(packet, myNum, log.uuid, logJob)
|
||||
router.value.dataHandler.handleReceivedData(packet, myNum, log.uuid, logJob)
|
||||
} finally {
|
||||
scope.launch {
|
||||
mapsMutex.withLock {
|
||||
|
|
@ -258,5 +254,5 @@ constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun insertMeshLog(log: MeshLog): Job = scope.handledLaunch { meshLogRepository.get().insert(log) }
|
||||
private fun insertMeshLog(log: MeshLog): Job = scope.handledLaunch { meshLogRepository.value.insert(log) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@
|
|||
*/
|
||||
package org.meshtastic.core.data.manager
|
||||
|
||||
import dagger.Lazy
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.repository.MeshActionHandler
|
||||
import org.meshtastic.core.repository.MeshConfigFlowManager
|
||||
import org.meshtastic.core.repository.MeshConfigHandler
|
||||
|
|
@ -26,15 +26,11 @@ import org.meshtastic.core.repository.MeshRouter
|
|||
import org.meshtastic.core.repository.MqttManager
|
||||
import org.meshtastic.core.repository.NeighborInfoHandler
|
||||
import org.meshtastic.core.repository.TracerouteHandler
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/** Implementation of [MeshRouter] that orchestrates specialized mesh packet handlers. */
|
||||
@Suppress("LongParameterList")
|
||||
@Singleton
|
||||
class MeshRouterImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class MeshRouterImpl(
|
||||
private val dataHandlerLazy: Lazy<MeshDataHandler>,
|
||||
private val configHandlerLazy: Lazy<MeshConfigHandler>,
|
||||
private val tracerouteHandlerLazy: Lazy<TracerouteHandler>,
|
||||
|
|
@ -44,25 +40,25 @@ constructor(
|
|||
private val actionHandlerLazy: Lazy<MeshActionHandler>,
|
||||
) : MeshRouter {
|
||||
override val dataHandler: MeshDataHandler
|
||||
get() = dataHandlerLazy.get()
|
||||
get() = dataHandlerLazy.value
|
||||
|
||||
override val configHandler: MeshConfigHandler
|
||||
get() = configHandlerLazy.get()
|
||||
get() = configHandlerLazy.value
|
||||
|
||||
override val tracerouteHandler: TracerouteHandler
|
||||
get() = tracerouteHandlerLazy.get()
|
||||
get() = tracerouteHandlerLazy.value
|
||||
|
||||
override val neighborInfoHandler: NeighborInfoHandler
|
||||
get() = neighborInfoHandlerLazy.get()
|
||||
get() = neighborInfoHandlerLazy.value
|
||||
|
||||
override val configFlowManager: MeshConfigFlowManager
|
||||
get() = configFlowManagerLazy.get()
|
||||
get() = configFlowManagerLazy.value
|
||||
|
||||
override val mqttManager: MqttManager
|
||||
get() = mqttManagerLazy.get()
|
||||
get() = mqttManagerLazy.value
|
||||
|
||||
override val actionHandler: MeshActionHandler
|
||||
get() = actionHandlerLazy.get()
|
||||
get() = actionHandlerLazy.value
|
||||
|
||||
override fun start(scope: CoroutineScope) {
|
||||
dataHandler.start(scope)
|
||||
|
|
|
|||
|
|
@ -17,14 +17,13 @@
|
|||
package org.meshtastic.core.data.manager
|
||||
|
||||
import co.touchlab.kermit.Logger
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.repository.FilterPrefs
|
||||
import org.meshtastic.core.repository.MessageFilter
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/** Implementation of [MessageFilter] that uses regex and plain text matching. */
|
||||
@Singleton
|
||||
class MessageFilterImpl @Inject constructor(private val filterPrefs: FilterPrefs) : MessageFilter {
|
||||
@Single
|
||||
class MessageFilterImpl(private val filterPrefs: FilterPrefs) : MessageFilter {
|
||||
private var compiledPatterns: List<Regex> = emptyList()
|
||||
|
||||
init {
|
||||
|
|
|
|||
|
|
@ -25,19 +25,16 @@ import kotlinx.coroutines.SupervisorJob
|
|||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.network.repository.MQTTRepository
|
||||
import org.meshtastic.core.repository.MqttManager
|
||||
import org.meshtastic.core.repository.PacketHandler
|
||||
import org.meshtastic.core.repository.ServiceRepository
|
||||
import org.meshtastic.proto.MqttClientProxyMessage
|
||||
import org.meshtastic.proto.ToRadio
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class MqttManagerImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class MqttManagerImpl(
|
||||
private val mqttRepository: MQTTRepository,
|
||||
private val packetHandler: PacketHandler,
|
||||
private val serviceRepository: ServiceRepository,
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import co.touchlab.kermit.Logger
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.repository.CommandSender
|
||||
import org.meshtastic.core.repository.NeighborInfoHandler
|
||||
|
|
@ -29,13 +30,9 @@ import org.meshtastic.core.repository.ServiceRepository
|
|||
import org.meshtastic.proto.MeshPacket
|
||||
import org.meshtastic.proto.NeighborInfo
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class NeighborInfoHandlerImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class NeighborInfoHandlerImpl(
|
||||
private val nodeManager: NodeManager,
|
||||
private val serviceRepository: ServiceRepository,
|
||||
private val commandSender: CommandSender,
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import kotlinx.coroutines.SupervisorJob
|
|||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import okio.ByteString
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.util.handledLaunch
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.core.model.DeviceMetrics
|
||||
|
|
@ -35,6 +36,7 @@ import org.meshtastic.core.model.MyNodeInfo
|
|||
import org.meshtastic.core.model.Node
|
||||
import org.meshtastic.core.model.NodeInfo
|
||||
import org.meshtastic.core.model.Position
|
||||
import org.meshtastic.core.model.util.NodeIdLookup
|
||||
import org.meshtastic.core.repository.MeshServiceNotifications
|
||||
import org.meshtastic.core.repository.NodeManager
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
|
|
@ -45,17 +47,13 @@ import org.meshtastic.proto.Paxcount
|
|||
import org.meshtastic.proto.StatusMessage
|
||||
import org.meshtastic.proto.Telemetry
|
||||
import org.meshtastic.proto.User
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import org.meshtastic.proto.NodeInfo as ProtoNodeInfo
|
||||
import org.meshtastic.proto.Position as ProtoPosition
|
||||
|
||||
/** Implementation of [NodeManager] that maintains an in-memory database of the mesh. */
|
||||
@Suppress("LongParameterList", "TooManyFunctions", "CyclomaticComplexMethod")
|
||||
@Singleton
|
||||
class NodeManagerImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@Single(binds = [NodeManager::class, NodeIdLookup::class])
|
||||
class NodeManagerImpl(
|
||||
private val nodeRepository: NodeRepository,
|
||||
private val serviceBroadcasts: ServiceBroadcasts,
|
||||
private val serviceNotifications: MeshServiceNotifications,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
package org.meshtastic.core.data.manager
|
||||
|
||||
import co.touchlab.kermit.Logger
|
||||
import dagger.Lazy
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -29,6 +28,7 @@ import kotlinx.coroutines.sync.Mutex
|
|||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.util.handledLaunch
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.database.entity.MeshLog
|
||||
|
|
@ -48,17 +48,13 @@ import org.meshtastic.proto.FromRadio
|
|||
import org.meshtastic.proto.MeshPacket
|
||||
import org.meshtastic.proto.QueueStatus
|
||||
import org.meshtastic.proto.ToRadio
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
@Singleton
|
||||
class PacketHandlerImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class PacketHandlerImpl(
|
||||
private val packetRepository: Lazy<PacketRepository>,
|
||||
private val serviceBroadcasts: ServiceBroadcasts,
|
||||
private val radioInterfaceService: RadioInterfaceService,
|
||||
|
|
@ -182,7 +178,7 @@ constructor(
|
|||
if (packetId != 0) {
|
||||
getDataPacketById(packetId)?.let { p ->
|
||||
if (p.status == m) return@handledLaunch
|
||||
packetRepository.get().updateMessageStatus(p, m)
|
||||
packetRepository.value.updateMessageStatus(p, m)
|
||||
serviceBroadcasts.broadcastMessageStatus(packetId, m)
|
||||
}
|
||||
}
|
||||
|
|
@ -191,7 +187,7 @@ constructor(
|
|||
private suspend fun getDataPacketById(packetId: Int): DataPacket? = withTimeoutOrNull(1.seconds) {
|
||||
var dataPacket: DataPacket? = null
|
||||
while (dataPacket == null) {
|
||||
dataPacket = packetRepository.get().getPacketById(packetId)
|
||||
dataPacket = packetRepository.value.getPacketById(packetId)
|
||||
if (dataPacket == null) delay(100.milliseconds)
|
||||
}
|
||||
dataPacket
|
||||
|
|
@ -222,7 +218,7 @@ constructor(
|
|||
"insert: ${packetToSave.message_type} = " +
|
||||
"${packetToSave.raw_message.toOneLineString()} from=${packetToSave.fromNum}"
|
||||
}
|
||||
meshLogRepository.get().insert(packetToSave)
|
||||
meshLogRepository.value.insert(packetToSave)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import co.touchlab.kermit.Logger
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.util.handledLaunch
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.data.repository.TracerouteSnapshotRepository
|
||||
|
|
@ -34,13 +35,9 @@ import org.meshtastic.core.repository.ServiceRepository
|
|||
import org.meshtastic.core.repository.TracerouteHandler
|
||||
import org.meshtastic.proto.MeshPacket
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class TracerouteHandlerImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class TracerouteHandlerImpl(
|
||||
private val nodeManager: NodeManager,
|
||||
private val serviceRepository: ServiceRepository,
|
||||
private val tracerouteSnapshotRepository: TracerouteSnapshotRepository,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package org.meshtastic.core.data.repository
|
|||
|
||||
import co.touchlab.kermit.Logger
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.data.datasource.BootloaderOtaQuirksJsonDataSource
|
||||
import org.meshtastic.core.data.datasource.DeviceHardwareJsonDataSource
|
||||
|
|
@ -30,14 +31,10 @@ import org.meshtastic.core.model.DeviceHardware
|
|||
import org.meshtastic.core.model.util.TimeConstants
|
||||
import org.meshtastic.core.network.DeviceHardwareRemoteDataSource
|
||||
import org.meshtastic.core.repository.DeviceHardwareRepository
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
// Annotating with Singleton to ensure a single instance manages the cache
|
||||
@Singleton
|
||||
class DeviceHardwareRepositoryImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class DeviceHardwareRepositoryImpl(
|
||||
private val remoteDataSource: DeviceHardwareRemoteDataSource,
|
||||
private val localDataSource: DeviceHardwareLocalDataSource,
|
||||
private val jsonDataSource: DeviceHardwareJsonDataSource,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.meshtastic.core.data.repository
|
|||
import co.touchlab.kermit.Logger
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.data.datasource.FirmwareReleaseJsonDataSource
|
||||
import org.meshtastic.core.data.datasource.FirmwareReleaseLocalDataSource
|
||||
|
|
@ -28,13 +29,9 @@ import org.meshtastic.core.database.entity.FirmwareReleaseType
|
|||
import org.meshtastic.core.database.entity.asExternalModel
|
||||
import org.meshtastic.core.model.util.TimeConstants
|
||||
import org.meshtastic.core.network.FirmwareReleaseRemoteDataSource
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class FirmwareReleaseRepository
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class FirmwareReleaseRepository(
|
||||
private val remoteDataSource: FirmwareReleaseRemoteDataSource,
|
||||
private val localDataSource: FirmwareReleaseLocalDataSource,
|
||||
private val jsonDataSource: FirmwareReleaseJsonDataSource,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import kotlinx.coroutines.flow.flowOn
|
|||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.data.datasource.NodeInfoReadDataSource
|
||||
import org.meshtastic.core.database.DatabaseManager
|
||||
|
|
@ -37,8 +38,6 @@ import org.meshtastic.proto.MeshPacket
|
|||
import org.meshtastic.proto.MyNodeInfo
|
||||
import org.meshtastic.proto.PortNum
|
||||
import org.meshtastic.proto.Telemetry
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* Repository implementation for managing and retrieving logs from the local database.
|
||||
|
|
@ -47,10 +46,8 @@ import javax.inject.Singleton
|
|||
* telemetry and traceroute data.
|
||||
*/
|
||||
@Suppress("TooManyFunctions")
|
||||
@Singleton
|
||||
class MeshLogRepositoryImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class MeshLogRepositoryImpl(
|
||||
private val dbManager: DatabaseManager,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
private val meshLogPrefs: MeshLogPrefs,
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ import kotlinx.coroutines.flow.onEach
|
|||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.annotation.Named
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.data.datasource.NodeInfoReadDataSource
|
||||
import org.meshtastic.core.data.datasource.NodeInfoWriteDataSource
|
||||
import org.meshtastic.core.database.entity.MeshLog
|
||||
|
|
@ -42,7 +44,6 @@ import org.meshtastic.core.database.entity.MyNodeEntity
|
|||
import org.meshtastic.core.database.entity.NodeEntity
|
||||
import org.meshtastic.core.datastore.LocalStatsDataSource
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
import org.meshtastic.core.di.ProcessLifecycle
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.core.model.MyNodeInfo
|
||||
import org.meshtastic.core.model.Node
|
||||
|
|
@ -53,16 +54,12 @@ import org.meshtastic.proto.DeviceMetadata
|
|||
import org.meshtastic.proto.HardwareModel
|
||||
import org.meshtastic.proto.LocalStats
|
||||
import org.meshtastic.proto.User
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/** Repository for managing node-related data, including hardware info, node database, and identity. */
|
||||
@Singleton
|
||||
@Single
|
||||
@Suppress("TooManyFunctions")
|
||||
class NodeRepositoryImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@ProcessLifecycle private val processLifecycle: Lifecycle,
|
||||
class NodeRepositoryImpl(
|
||||
@Named("ProcessLifecycle") private val processLifecycle: Lifecycle,
|
||||
private val nodeInfoReadDataSource: NodeInfoReadDataSource,
|
||||
private val nodeInfoWriteDataSource: NodeInfoWriteDataSource,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import kotlinx.coroutines.flow.map
|
|||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.withContext
|
||||
import okio.ByteString.Companion.toByteString
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.database.DatabaseManager
|
||||
import org.meshtastic.core.database.entity.toReaction
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
|
|
@ -37,19 +38,15 @@ import org.meshtastic.core.model.Node
|
|||
import org.meshtastic.core.model.Reaction
|
||||
import org.meshtastic.proto.ChannelSettings
|
||||
import org.meshtastic.proto.PortNum
|
||||
import javax.inject.Inject
|
||||
import org.meshtastic.core.database.entity.ContactSettings as ContactSettingsEntity
|
||||
import org.meshtastic.core.database.entity.Packet as RoomPacket
|
||||
import org.meshtastic.core.database.entity.ReactionEntity as RoomReaction
|
||||
import org.meshtastic.core.repository.PacketRepository as SharedPacketRepository
|
||||
|
||||
@Suppress("TooManyFunctions", "LongParameterList")
|
||||
class PacketRepositoryImpl
|
||||
@Inject
|
||||
constructor(
|
||||
private val dbManager: DatabaseManager,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
) : SharedPacketRepository {
|
||||
@Single
|
||||
class PacketRepositoryImpl(private val dbManager: DatabaseManager, private val dispatchers: CoroutineDispatchers) :
|
||||
SharedPacketRepository {
|
||||
|
||||
override fun getWaypoints(): Flow<List<DataPacket>> = dbManager.currentDb
|
||||
.flatMapLatest { db -> db.packetDao().getAllWaypointsFlow() }
|
||||
|
|
|
|||
|
|
@ -19,17 +19,13 @@ package org.meshtastic.core.data.repository
|
|||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.database.DatabaseManager
|
||||
import org.meshtastic.core.database.entity.QuickChatAction
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
import javax.inject.Inject
|
||||
|
||||
class QuickChatActionRepository
|
||||
@Inject
|
||||
constructor(
|
||||
private val dbManager: DatabaseManager,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
) {
|
||||
@Single
|
||||
class QuickChatActionRepository(private val dbManager: DatabaseManager, private val dispatchers: CoroutineDispatchers) {
|
||||
fun getAllActions() = dbManager.currentDb.flatMapLatest { it.quickChatActionDao().getAll() }.flowOn(dispatchers.io)
|
||||
|
||||
suspend fun upsert(action: QuickChatAction) =
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package org.meshtastic.core.data.repository
|
|||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.datastore.ChannelSetDataSource
|
||||
import org.meshtastic.core.datastore.LocalConfigDataSource
|
||||
import org.meshtastic.core.datastore.ModuleConfigDataSource
|
||||
|
|
@ -32,15 +33,13 @@ import org.meshtastic.proto.DeviceProfile
|
|||
import org.meshtastic.proto.LocalConfig
|
||||
import org.meshtastic.proto.LocalModuleConfig
|
||||
import org.meshtastic.proto.ModuleConfig
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Class responsible for radio configuration data. Combines access to [nodeDB], [ChannelSet], [LocalConfig] &
|
||||
* [LocalModuleConfig].
|
||||
*/
|
||||
open class RadioConfigRepositoryImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
open class RadioConfigRepositoryImpl(
|
||||
private val nodeDB: NodeRepository,
|
||||
private val channelSetDataSource: ChannelSetDataSource,
|
||||
private val localConfigDataSource: LocalConfigDataSource,
|
||||
|
|
|
|||
|
|
@ -23,15 +23,14 @@ import kotlinx.coroutines.flow.flatMapLatest
|
|||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.database.DatabaseManager
|
||||
import org.meshtastic.core.database.entity.TracerouteNodePositionEntity
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
import org.meshtastic.proto.Position
|
||||
import javax.inject.Inject
|
||||
|
||||
class TracerouteSnapshotRepository
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class TracerouteSnapshotRepository(
|
||||
private val dbManager: DatabaseManager,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,13 @@ class FromRadioPacketHandlerImplTest {
|
|||
@Before
|
||||
fun setup() {
|
||||
handler =
|
||||
FromRadioPacketHandlerImpl(serviceRepository, { router }, mqttManager, packetHandler, serviceNotifications)
|
||||
FromRadioPacketHandlerImpl(
|
||||
serviceRepository,
|
||||
lazy { router },
|
||||
mqttManager,
|
||||
packetHandler,
|
||||
serviceNotifications,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
*/
|
||||
package org.meshtastic.core.data.manager
|
||||
|
||||
import dagger.Lazy
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
|
|
@ -58,19 +57,19 @@ class MeshDataHandlerTest {
|
|||
private val packetHandler: PacketHandler = mockk(relaxed = true)
|
||||
private val serviceRepository: ServiceRepository = mockk(relaxed = true)
|
||||
private val packetRepository: PacketRepository = mockk(relaxed = true)
|
||||
private val packetRepositoryLazy: Lazy<PacketRepository> = mockk { every { get() } returns packetRepository }
|
||||
private val packetRepositoryLazy: Lazy<PacketRepository> = lazy { packetRepository }
|
||||
private val serviceBroadcasts: ServiceBroadcasts = mockk(relaxed = true)
|
||||
private val serviceNotifications: MeshServiceNotifications = mockk(relaxed = true)
|
||||
private val analytics: PlatformAnalytics = mockk(relaxed = true)
|
||||
private val dataMapper: MeshDataMapper = mockk(relaxed = true)
|
||||
private val configHandler: MeshConfigHandler = mockk(relaxed = true)
|
||||
private val configHandlerLazy: Lazy<MeshConfigHandler> = mockk { every { get() } returns configHandler }
|
||||
private val configHandlerLazy: Lazy<MeshConfigHandler> = lazy { configHandler }
|
||||
private val configFlowManager: MeshConfigFlowManager = mockk(relaxed = true)
|
||||
private val configFlowManagerLazy: Lazy<MeshConfigFlowManager> = mockk { every { get() } returns configFlowManager }
|
||||
private val configFlowManagerLazy: Lazy<MeshConfigFlowManager> = lazy { configFlowManager }
|
||||
private val commandSender: CommandSender = mockk(relaxed = true)
|
||||
private val historyManager: HistoryManager = mockk(relaxed = true)
|
||||
private val connectionManager: MeshConnectionManager = mockk(relaxed = true)
|
||||
private val connectionManagerLazy: Lazy<MeshConnectionManager> = mockk { every { get() } returns connectionManager }
|
||||
private val connectionManagerLazy: Lazy<MeshConnectionManager> = lazy { connectionManager }
|
||||
private val tracerouteHandler: TracerouteHandler = mockk(relaxed = true)
|
||||
private val neighborInfoHandler: NeighborInfoHandler = mockk(relaxed = true)
|
||||
private val radioConfigRepository: RadioConfigRepository = mockk(relaxed = true)
|
||||
|
|
|
|||
|
|
@ -60,10 +60,10 @@ class PacketHandlerImplTest {
|
|||
|
||||
handler =
|
||||
PacketHandlerImpl(
|
||||
{ packetRepository },
|
||||
lazy { packetRepository },
|
||||
serviceBroadcasts,
|
||||
radioInterfaceService,
|
||||
{ meshLogRepository },
|
||||
lazy { meshLogRepository },
|
||||
serviceRepository,
|
||||
)
|
||||
handler.start(testScope)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ plugins {
|
|||
alias(libs.plugins.meshtastic.android.room)
|
||||
alias(libs.plugins.meshtastic.kotlinx.serialization)
|
||||
alias(libs.plugins.kotlin.parcelize)
|
||||
id("meshtastic.koin")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
|
|
|
|||
|
|
@ -34,24 +34,19 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.database.MeshtasticDatabase.Companion.configureCommon
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import org.meshtastic.core.common.database.DatabaseManager as SharedDatabaseManager
|
||||
|
||||
/** Manages per-device Room database instances for node data, with LRU eviction. */
|
||||
@Singleton
|
||||
@Single
|
||||
@Suppress("TooManyFunctions")
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
open class DatabaseManager
|
||||
@Inject
|
||||
constructor(
|
||||
private val app: Application,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
) : SharedDatabaseManager {
|
||||
open class DatabaseManager(private val app: Application, private val dispatchers: CoroutineDispatchers) :
|
||||
SharedDatabaseManager {
|
||||
val prefs: SharedPreferences = app.getSharedPreferences("db-manager-prefs", Context.MODE_PRIVATE)
|
||||
private val managerScope = CoroutineScope(SupervisorJob() + dispatchers.default)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.database.di
|
||||
|
||||
import org.koin.core.annotation.ComponentScan
|
||||
import org.koin.core.annotation.Module
|
||||
|
||||
@Module
|
||||
@ComponentScan("org.meshtastic.core.database")
|
||||
class CoreDatabaseAndroidModule
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.database.di
|
||||
|
||||
import org.koin.core.annotation.ComponentScan
|
||||
import org.koin.core.annotation.Module
|
||||
|
||||
@Module
|
||||
@ComponentScan("org.meshtastic.core.database")
|
||||
class CoreDatabaseModule
|
||||
|
|
@ -18,7 +18,7 @@ plugins {
|
|||
alias(libs.plugins.meshtastic.kmp.library)
|
||||
alias(libs.plugins.meshtastic.kotlinx.serialization)
|
||||
alias(libs.plugins.kotlin.parcelize)
|
||||
alias(libs.plugins.devtools.ksp)
|
||||
id("meshtastic.koin")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
|
|
@ -29,12 +29,8 @@ kotlin {
|
|||
implementation(projects.core.proto)
|
||||
api(libs.androidx.datastore)
|
||||
api(libs.androidx.datastore.preferences)
|
||||
api(libs.javax.inject)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
implementation(libs.kermit)
|
||||
}
|
||||
androidMain.dependencies { implementation(libs.hilt.android) }
|
||||
}
|
||||
}
|
||||
|
||||
dependencies { "kspAndroid"(libs.hilt.compiler) }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.datastore.di
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.core.DataStoreFactory
|
||||
import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler
|
||||
import androidx.datastore.core.okio.OkioStorage
|
||||
import androidx.datastore.dataStoreFile
|
||||
import androidx.datastore.preferences.SharedPreferencesMigration
|
||||
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.emptyPreferences
|
||||
import androidx.datastore.preferences.preferencesDataStoreFile
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import okio.FileSystem
|
||||
import okio.Path.Companion.toOkioPath
|
||||
import org.koin.core.annotation.Module
|
||||
import org.koin.core.annotation.Named
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.datastore.KEY_APP_INTRO_COMPLETED
|
||||
import org.meshtastic.core.datastore.KEY_INCLUDE_UNKNOWN
|
||||
import org.meshtastic.core.datastore.KEY_NODE_SORT
|
||||
import org.meshtastic.core.datastore.KEY_ONLY_DIRECT
|
||||
import org.meshtastic.core.datastore.KEY_ONLY_ONLINE
|
||||
import org.meshtastic.core.datastore.KEY_SHOW_IGNORED
|
||||
import org.meshtastic.core.datastore.KEY_THEME
|
||||
import org.meshtastic.core.datastore.serializer.ChannelSetSerializer
|
||||
import org.meshtastic.core.datastore.serializer.LocalConfigSerializer
|
||||
import org.meshtastic.core.datastore.serializer.LocalStatsSerializer
|
||||
import org.meshtastic.core.datastore.serializer.ModuleConfigSerializer
|
||||
import org.meshtastic.proto.ChannelSet
|
||||
import org.meshtastic.proto.LocalConfig
|
||||
import org.meshtastic.proto.LocalModuleConfig
|
||||
import org.meshtastic.proto.LocalStats
|
||||
|
||||
private const val USER_PREFERENCES_NAME = "user_preferences"
|
||||
|
||||
@Module
|
||||
class PreferencesDataStoreModule {
|
||||
@Single
|
||||
@Named("CorePreferencesDataStore")
|
||||
fun providePreferencesDataStore(
|
||||
context: Context,
|
||||
@Named("DataStoreScope") scope: CoroutineScope,
|
||||
): DataStore<Preferences> = PreferenceDataStoreFactory.create(
|
||||
corruptionHandler = ReplaceFileCorruptionHandler(produceNewData = { emptyPreferences() }),
|
||||
migrations =
|
||||
listOf(
|
||||
SharedPreferencesMigration(context = context, sharedPreferencesName = USER_PREFERENCES_NAME),
|
||||
SharedPreferencesMigration(
|
||||
context = context,
|
||||
sharedPreferencesName = "ui-prefs",
|
||||
keysToMigrate =
|
||||
setOf(
|
||||
KEY_APP_INTRO_COMPLETED,
|
||||
KEY_THEME,
|
||||
KEY_NODE_SORT,
|
||||
KEY_INCLUDE_UNKNOWN,
|
||||
KEY_ONLY_ONLINE,
|
||||
KEY_ONLY_DIRECT,
|
||||
KEY_SHOW_IGNORED,
|
||||
),
|
||||
),
|
||||
),
|
||||
scope = scope,
|
||||
produceFile = { context.preferencesDataStoreFile(USER_PREFERENCES_NAME) },
|
||||
)
|
||||
}
|
||||
|
||||
@Module
|
||||
class LocalConfigDataStoreModule {
|
||||
@Single
|
||||
@Named("CoreLocalConfigDataStore")
|
||||
fun provideLocalConfigDataStore(
|
||||
context: Context,
|
||||
@Named("DataStoreScope") scope: CoroutineScope,
|
||||
): DataStore<LocalConfig> = DataStoreFactory.create(
|
||||
storage =
|
||||
OkioStorage(
|
||||
fileSystem = FileSystem.SYSTEM,
|
||||
serializer = LocalConfigSerializer,
|
||||
producePath = { context.dataStoreFile("local_config.pb").toOkioPath() },
|
||||
),
|
||||
corruptionHandler = ReplaceFileCorruptionHandler(produceNewData = { LocalConfig() }),
|
||||
scope = scope,
|
||||
)
|
||||
}
|
||||
|
||||
@Module
|
||||
class ModuleConfigDataStoreModule {
|
||||
@Single
|
||||
@Named("CoreModuleConfigDataStore")
|
||||
fun provideModuleConfigDataStore(
|
||||
context: Context,
|
||||
@Named("DataStoreScope") scope: CoroutineScope,
|
||||
): DataStore<LocalModuleConfig> = DataStoreFactory.create(
|
||||
storage =
|
||||
OkioStorage(
|
||||
fileSystem = FileSystem.SYSTEM,
|
||||
serializer = ModuleConfigSerializer,
|
||||
producePath = { context.dataStoreFile("module_config.pb").toOkioPath() },
|
||||
),
|
||||
corruptionHandler = ReplaceFileCorruptionHandler(produceNewData = { LocalModuleConfig() }),
|
||||
scope = scope,
|
||||
)
|
||||
}
|
||||
|
||||
@Module
|
||||
class ChannelSetDataStoreModule {
|
||||
@Single
|
||||
@Named("CoreChannelSetDataStore")
|
||||
fun provideChannelSetDataStore(
|
||||
context: Context,
|
||||
@Named("DataStoreScope") scope: CoroutineScope,
|
||||
): DataStore<ChannelSet> = DataStoreFactory.create(
|
||||
storage =
|
||||
OkioStorage(
|
||||
fileSystem = FileSystem.SYSTEM,
|
||||
serializer = ChannelSetSerializer,
|
||||
producePath = { context.dataStoreFile("channel_set.pb").toOkioPath() },
|
||||
),
|
||||
corruptionHandler = ReplaceFileCorruptionHandler(produceNewData = { ChannelSet() }),
|
||||
scope = scope,
|
||||
)
|
||||
}
|
||||
|
||||
@Module
|
||||
class LocalStatsDataStoreModule {
|
||||
@Single
|
||||
@Named("CoreLocalStatsDataStore")
|
||||
fun provideLocalStatsDataStore(
|
||||
context: Context,
|
||||
@Named("DataStoreScope") scope: CoroutineScope,
|
||||
): DataStore<LocalStats> = DataStoreFactory.create(
|
||||
storage =
|
||||
OkioStorage(
|
||||
fileSystem = FileSystem.SYSTEM,
|
||||
serializer = LocalStatsSerializer,
|
||||
producePath = { context.dataStoreFile("local_stats.pb").toOkioPath() },
|
||||
),
|
||||
corruptionHandler = ReplaceFileCorruptionHandler(produceNewData = { LocalStats() }),
|
||||
scope = scope,
|
||||
)
|
||||
}
|
||||
|
||||
@Module(
|
||||
includes =
|
||||
[
|
||||
PreferencesDataStoreModule::class,
|
||||
LocalConfigDataStoreModule::class,
|
||||
ModuleConfigDataStoreModule::class,
|
||||
ChannelSetDataStoreModule::class,
|
||||
LocalStatsDataStoreModule::class,
|
||||
],
|
||||
)
|
||||
class CoreDatastoreAndroidModule
|
||||
|
|
@ -25,11 +25,11 @@ import kotlinx.coroutines.flow.first
|
|||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.serialization.SerializationException
|
||||
import kotlinx.serialization.json.Json
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import org.koin.core.annotation.Named
|
||||
import org.koin.core.annotation.Single
|
||||
|
||||
@Singleton
|
||||
class BootloaderWarningDataSource @Inject constructor(private val dataStore: DataStore<Preferences>) {
|
||||
@Single
|
||||
class BootloaderWarningDataSource(@Named("CorePreferencesDataStore") private val dataStore: DataStore<Preferences>) {
|
||||
|
||||
private object PreferencesKeys {
|
||||
val DISMISSED_BOOTLOADER_ADDRESSES = stringPreferencesKey("dismissed-bootloader-addresses")
|
||||
|
|
|
|||
|
|
@ -21,16 +21,16 @@ import co.touchlab.kermit.Logger
|
|||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import okio.IOException
|
||||
import org.koin.core.annotation.Named
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.proto.Channel
|
||||
import org.meshtastic.proto.ChannelSet
|
||||
import org.meshtastic.proto.ChannelSettings
|
||||
import org.meshtastic.proto.Config
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/** Class that handles saving and retrieving [ChannelSet] data. */
|
||||
@Singleton
|
||||
class ChannelSetDataSource @Inject constructor(private val channelSetStore: DataStore<ChannelSet>) {
|
||||
@Single
|
||||
class ChannelSetDataSource(@Named("CoreChannelSetDataStore") private val channelSetStore: DataStore<ChannelSet>) {
|
||||
val channelSetFlow: Flow<ChannelSet> =
|
||||
channelSetStore.data.catch { exception ->
|
||||
// dataStore.data throws an IOException when an error is encountered when reading data
|
||||
|
|
|
|||
|
|
@ -21,14 +21,14 @@ import co.touchlab.kermit.Logger
|
|||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import okio.IOException
|
||||
import org.koin.core.annotation.Named
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.proto.Config
|
||||
import org.meshtastic.proto.LocalConfig
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/** Class that handles saving and retrieving [LocalConfig] data. */
|
||||
@Singleton
|
||||
class LocalConfigDataSource @Inject constructor(private val localConfigStore: DataStore<LocalConfig>) {
|
||||
@Single
|
||||
class LocalConfigDataSource(@Named("CoreLocalConfigDataStore") private val localConfigStore: DataStore<LocalConfig>) {
|
||||
val localConfigFlow: Flow<LocalConfig> =
|
||||
localConfigStore.data.catch { exception ->
|
||||
// dataStore.data throws an IOException when an error is encountered when reading data
|
||||
|
|
|
|||
|
|
@ -21,13 +21,13 @@ import co.touchlab.kermit.Logger
|
|||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import okio.IOException
|
||||
import org.koin.core.annotation.Named
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.proto.LocalStats
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/** Class that handles saving and retrieving [LocalStats] data. */
|
||||
@Singleton
|
||||
class LocalStatsDataSource @Inject constructor(private val localStatsStore: DataStore<LocalStats>) {
|
||||
@Single
|
||||
class LocalStatsDataSource(@Named("CoreLocalStatsDataStore") private val localStatsStore: DataStore<LocalStats>) {
|
||||
val localStatsFlow: Flow<LocalStats> =
|
||||
localStatsStore.data.catch { exception ->
|
||||
if (exception is IOException) {
|
||||
|
|
|
|||
|
|
@ -21,14 +21,16 @@ import co.touchlab.kermit.Logger
|
|||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import okio.IOException
|
||||
import org.koin.core.annotation.Named
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.proto.LocalModuleConfig
|
||||
import org.meshtastic.proto.ModuleConfig
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/** Class that handles saving and retrieving [LocalModuleConfig] data. */
|
||||
@Singleton
|
||||
class ModuleConfigDataSource @Inject constructor(private val moduleConfigStore: DataStore<LocalModuleConfig>) {
|
||||
@Single
|
||||
class ModuleConfigDataSource(
|
||||
@Named("CoreModuleConfigDataStore") private val moduleConfigStore: DataStore<LocalModuleConfig>,
|
||||
) {
|
||||
val moduleConfigFlow: Flow<LocalModuleConfig> =
|
||||
moduleConfigStore.data.catch { exception ->
|
||||
// dataStore.data throws an IOException when an error is encountered when reading data
|
||||
|
|
|
|||
|
|
@ -28,12 +28,12 @@ import kotlinx.serialization.SerializationException
|
|||
import kotlinx.serialization.json.Json
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.koin.core.annotation.Named
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.datastore.model.RecentAddress
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class RecentAddressesDataSource @Inject constructor(private val dataStore: DataStore<Preferences>) {
|
||||
@Single
|
||||
class RecentAddressesDataSource(@Named("CorePreferencesDataStore") private val dataStore: DataStore<Preferences>) {
|
||||
private object PreferencesKeys {
|
||||
val RECENT_IP_ADDRESSES = stringPreferencesKey("recent-ip-addresses")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ import kotlinx.coroutines.flow.StateFlow
|
|||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import org.koin.core.annotation.Named
|
||||
import org.koin.core.annotation.Single
|
||||
|
||||
const val KEY_APP_INTRO_COMPLETED = "app_intro_completed"
|
||||
const val KEY_THEME = "theme"
|
||||
|
|
@ -43,8 +43,8 @@ const val KEY_ONLY_ONLINE = "only-online"
|
|||
const val KEY_ONLY_DIRECT = "only-direct"
|
||||
const val KEY_SHOW_IGNORED = "show-ignored"
|
||||
|
||||
@Singleton
|
||||
class UiPreferencesDataSource @Inject constructor(private val dataStore: DataStore<Preferences>) {
|
||||
@Single
|
||||
class UiPreferencesDataSource(@Named("CorePreferencesDataStore") private val dataStore: DataStore<Preferences>) {
|
||||
|
||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.datastore.di
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import org.koin.core.annotation.ComponentScan
|
||||
import org.koin.core.annotation.Module
|
||||
import org.koin.core.annotation.Named
|
||||
import org.koin.core.annotation.Single
|
||||
|
||||
@Module
|
||||
@ComponentScan("org.meshtastic.core.datastore")
|
||||
class CoreDatastoreModule {
|
||||
@Single
|
||||
@Named("DataStoreScope")
|
||||
fun provideDataStoreScope(): CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
# `:core:di`
|
||||
|
||||
## Overview
|
||||
The `:core:di` module defines the core Dagger Hilt modules and provides standard dependencies that are shared across all other modules.
|
||||
The `:core:di` module defines the core Koin modules and provides standard dependencies that are shared across all other modules.
|
||||
|
||||
## Key Components
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ Defines bindings for application-wide singletons like `Application`, `Context`,
|
|||
Provides a wrapper for standard Kotlin `CoroutineDispatchers` (`IO`, `Default`, `Main`), allowing for easy mocking in unit tests.
|
||||
|
||||
### 3. `ProcessLifecycle.kt`
|
||||
Exposes the application's global process lifecycle as a Hilt binding, enabling components to react to the app entering the foreground or background.
|
||||
Exposes the application's global process lifecycle as a Koin binding, enabling components to react to the app entering the foreground or background.
|
||||
|
||||
## Module dependency graph
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
plugins { alias(libs.plugins.meshtastic.kmp.library) }
|
||||
plugins {
|
||||
alias(libs.plugins.meshtastic.kmp.library)
|
||||
id("meshtastic.koin")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
@Suppress("UnstableApiUsage")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.di.di
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import org.koin.core.annotation.Module
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
|
||||
@Module
|
||||
class CoreDiModule {
|
||||
@Single
|
||||
fun provideCoroutineDispatchers(): CoroutineDispatchers =
|
||||
CoroutineDispatchers(io = Dispatchers.IO, main = Dispatchers.Main, default = Dispatchers.Default)
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
plugins {
|
||||
alias(libs.plugins.meshtastic.kmp.library)
|
||||
alias(libs.plugins.devtools.ksp)
|
||||
alias(libs.plugins.meshtastic.koin)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
|
|
@ -53,5 +54,3 @@ kotlin {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies { add("kspAndroid", libs.hilt.compiler) }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.domain.di
|
||||
|
||||
import org.koin.core.annotation.ComponentScan
|
||||
import org.koin.core.annotation.Module
|
||||
|
||||
@Module
|
||||
@ComponentScan("org.meshtastic.core.domain")
|
||||
class CoreDomainModule
|
||||
|
|
@ -16,9 +16,9 @@
|
|||
*/
|
||||
package org.meshtastic.core.domain.usecase.settings
|
||||
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Use case for performing administrative and destructive actions on mesh nodes.
|
||||
|
|
@ -26,8 +26,8 @@ import javax.inject.Inject
|
|||
* This component provides methods for rebooting, shutting down, or resetting nodes within the mesh. It also handles
|
||||
* local database synchronization when these actions are performed on the locally connected device.
|
||||
*/
|
||||
@Single
|
||||
open class AdminActionsUseCase
|
||||
@Inject
|
||||
constructor(
|
||||
private val radioController: RadioController,
|
||||
private val nodeRepository: NodeRepository,
|
||||
|
|
|
|||
|
|
@ -16,15 +16,15 @@
|
|||
*/
|
||||
package org.meshtastic.core.domain.usecase.settings
|
||||
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.model.Node
|
||||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration.Companion.days
|
||||
|
||||
/** Use case for cleaning up nodes from the database. */
|
||||
@Single
|
||||
open class CleanNodeDatabaseUseCase
|
||||
@Inject
|
||||
constructor(
|
||||
private val nodeRepository: NodeRepository,
|
||||
private val radioController: RadioController,
|
||||
|
|
|
|||
|
|
@ -21,18 +21,18 @@ import kotlinx.datetime.Instant
|
|||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import okio.BufferedSink
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.model.Position
|
||||
import org.meshtastic.core.model.util.positionToMeter
|
||||
import org.meshtastic.core.repository.MeshLogRepository
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.proto.PortNum
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.roundToInt
|
||||
import org.meshtastic.proto.Position as ProtoPosition
|
||||
|
||||
/** Use case for exporting persisted packet data to a CSV format. */
|
||||
@Single
|
||||
open class ExportDataUseCase
|
||||
@Inject
|
||||
constructor(
|
||||
private val nodeRepository: NodeRepository,
|
||||
private val meshLogRepository: MeshLogRepository,
|
||||
|
|
|
|||
|
|
@ -17,11 +17,12 @@
|
|||
package org.meshtastic.core.domain.usecase.settings
|
||||
|
||||
import okio.BufferedSink
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.proto.DeviceProfile
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Use case for exporting a device profile to an output stream. */
|
||||
open class ExportProfileUseCase @Inject constructor() {
|
||||
@Single
|
||||
open class ExportProfileUseCase {
|
||||
/**
|
||||
* Exports the provided [DeviceProfile] to the given [BufferedSink].
|
||||
*
|
||||
|
|
|
|||
|
|
@ -19,12 +19,13 @@ package org.meshtastic.core.domain.usecase.settings
|
|||
import kotlinx.serialization.json.buildJsonObject
|
||||
import kotlinx.serialization.json.put
|
||||
import okio.BufferedSink
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.proto.Config
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Use case for exporting security configuration to a JSON format. */
|
||||
open class ExportSecurityConfigUseCase @Inject constructor() {
|
||||
@Single
|
||||
open class ExportSecurityConfigUseCase {
|
||||
/**
|
||||
* Exports the provided [Config.SecurityConfig] as a JSON string to the given [BufferedSink].
|
||||
*
|
||||
|
|
|
|||
|
|
@ -17,11 +17,12 @@
|
|||
package org.meshtastic.core.domain.usecase.settings
|
||||
|
||||
import okio.BufferedSource
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.proto.DeviceProfile
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Use case for importing a device profile from an input stream. */
|
||||
open class ImportProfileUseCase @Inject constructor() {
|
||||
@Single
|
||||
open class ImportProfileUseCase {
|
||||
/**
|
||||
* Imports a [DeviceProfile] from the provided [BufferedSource].
|
||||
*
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.meshtastic.core.domain.usecase.settings
|
||||
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.model.Position
|
||||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.proto.Config
|
||||
|
|
@ -24,10 +25,10 @@ import org.meshtastic.proto.LocalConfig
|
|||
import org.meshtastic.proto.LocalModuleConfig
|
||||
import org.meshtastic.proto.ModuleConfig
|
||||
import org.meshtastic.proto.User
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Use case for installing a device profile onto a radio. */
|
||||
open class InstallProfileUseCase @Inject constructor(private val radioController: RadioController) {
|
||||
@Single
|
||||
open class InstallProfileUseCase constructor(private val radioController: RadioController) {
|
||||
/**
|
||||
* Installs the provided [DeviceProfile] onto the radio at [destNum].
|
||||
*
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import kotlinx.coroutines.flow.Flow
|
|||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.model.Node
|
||||
import org.meshtastic.core.model.RadioController
|
||||
|
|
@ -29,11 +30,10 @@ import org.meshtastic.core.repository.RadioPrefs
|
|||
import org.meshtastic.core.repository.isBle
|
||||
import org.meshtastic.core.repository.isSerial
|
||||
import org.meshtastic.core.repository.isTcp
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Use case to determine if the currently connected device is capable of over-the-air (OTA) updates. */
|
||||
@Single
|
||||
open class IsOtaCapableUseCase
|
||||
@Inject
|
||||
constructor(
|
||||
private val nodeRepository: NodeRepository,
|
||||
private val radioController: RadioController,
|
||||
|
|
|
|||
|
|
@ -16,11 +16,12 @@
|
|||
*/
|
||||
package org.meshtastic.core.domain.usecase.settings
|
||||
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.model.RadioController
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Use case for controlling location sharing with the mesh. */
|
||||
open class MeshLocationUseCase @Inject constructor(private val radioController: RadioController) {
|
||||
@Single
|
||||
open class MeshLocationUseCase constructor(private val radioController: RadioController) {
|
||||
/** Starts providing the phone's location to the mesh. */
|
||||
fun startProvidingLocation() {
|
||||
radioController.startProvideLocation()
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package org.meshtastic.core.domain.usecase.settings
|
||||
|
||||
import co.touchlab.kermit.Logger
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.model.getStringResFrom
|
||||
import org.meshtastic.core.resources.UiText
|
||||
import org.meshtastic.proto.AdminMessage
|
||||
|
|
@ -28,7 +29,6 @@ import org.meshtastic.proto.MeshPacket
|
|||
import org.meshtastic.proto.PortNum
|
||||
import org.meshtastic.proto.Routing
|
||||
import org.meshtastic.proto.User
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Sealed class representing the result of processing a radio response packet. */
|
||||
sealed class RadioResponseResult {
|
||||
|
|
@ -54,7 +54,8 @@ sealed class RadioResponseResult {
|
|||
}
|
||||
|
||||
/** Use case for processing incoming [MeshPacket]s that are responses to admin requests. */
|
||||
open class ProcessRadioResponseUseCase @Inject constructor() {
|
||||
@Single
|
||||
open class ProcessRadioResponseUseCase {
|
||||
/**
|
||||
* Decodes and processes the provided [packet].
|
||||
*
|
||||
|
|
|
|||
|
|
@ -16,16 +16,17 @@
|
|||
*/
|
||||
package org.meshtastic.core.domain.usecase.settings
|
||||
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.model.Position
|
||||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.proto.Config
|
||||
import org.meshtastic.proto.ModuleConfig
|
||||
import org.meshtastic.proto.User
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Use case for interacting with radio configuration components. */
|
||||
@Suppress("TooManyFunctions")
|
||||
open class RadioConfigUseCase @Inject constructor(private val radioController: RadioController) {
|
||||
@Single
|
||||
open class RadioConfigUseCase constructor(private val radioController: RadioController) {
|
||||
/**
|
||||
* Updates the owner information on the radio.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -16,15 +16,12 @@
|
|||
*/
|
||||
package org.meshtastic.core.domain.usecase.settings
|
||||
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.datastore.UiPreferencesDataSource
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Use case for setting whether the application intro has been completed. */
|
||||
open class SetAppIntroCompletedUseCase
|
||||
@Inject
|
||||
constructor(
|
||||
private val uiPreferencesDataSource: UiPreferencesDataSource,
|
||||
) {
|
||||
@Single
|
||||
open class SetAppIntroCompletedUseCase constructor(private val uiPreferencesDataSource: UiPreferencesDataSource) {
|
||||
operator fun invoke(completed: Boolean) {
|
||||
uiPreferencesDataSource.setAppIntroCompleted(completed)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,12 +16,13 @@
|
|||
*/
|
||||
package org.meshtastic.core.domain.usecase.settings
|
||||
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.database.DatabaseManager
|
||||
import org.meshtastic.core.database.DatabaseConstants
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Use case for setting the database cache limit. */
|
||||
open class SetDatabaseCacheLimitUseCase @Inject constructor(private val databaseManager: DatabaseManager) {
|
||||
@Single
|
||||
open class SetDatabaseCacheLimitUseCase constructor(private val databaseManager: DatabaseManager) {
|
||||
operator fun invoke(limit: Int) {
|
||||
val clamped = limit.coerceIn(DatabaseConstants.MIN_CACHE_LIMIT, DatabaseConstants.MAX_CACHE_LIMIT)
|
||||
databaseManager.setCacheLimit(clamped)
|
||||
|
|
|
|||
|
|
@ -16,13 +16,13 @@
|
|||
*/
|
||||
package org.meshtastic.core.domain.usecase.settings
|
||||
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.repository.MeshLogPrefs
|
||||
import org.meshtastic.core.repository.MeshLogRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Use case for managing mesh log settings. */
|
||||
@Single
|
||||
open class SetMeshLogSettingsUseCase
|
||||
@Inject
|
||||
constructor(
|
||||
private val meshLogRepository: MeshLogRepository,
|
||||
private val meshLogPrefs: MeshLogPrefs,
|
||||
|
|
|
|||
|
|
@ -16,11 +16,12 @@
|
|||
*/
|
||||
package org.meshtastic.core.domain.usecase.settings
|
||||
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.repository.UiPrefs
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Use case for setting whether to provide the node location to the mesh. */
|
||||
open class SetProvideLocationUseCase @Inject constructor(private val uiPrefs: UiPrefs) {
|
||||
@Single
|
||||
open class SetProvideLocationUseCase constructor(private val uiPrefs: UiPrefs) {
|
||||
operator fun invoke(myNodeNum: Int, provideLocation: Boolean) {
|
||||
uiPrefs.setShouldProvideNodeLocation(myNodeNum, provideLocation)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,11 +16,12 @@
|
|||
*/
|
||||
package org.meshtastic.core.domain.usecase.settings
|
||||
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.datastore.UiPreferencesDataSource
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Use case for setting the application theme. */
|
||||
open class SetThemeUseCase @Inject constructor(private val uiPreferencesDataSource: UiPreferencesDataSource) {
|
||||
@Single
|
||||
open class SetThemeUseCase constructor(private val uiPreferencesDataSource: UiPreferencesDataSource) {
|
||||
operator fun invoke(themeMode: Int) {
|
||||
uiPreferencesDataSource.setTheme(themeMode)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,11 +16,12 @@
|
|||
*/
|
||||
package org.meshtastic.core.domain.usecase.settings
|
||||
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.repository.AnalyticsPrefs
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Use case for toggling the analytics preference. */
|
||||
open class ToggleAnalyticsUseCase @Inject constructor(private val analyticsPrefs: AnalyticsPrefs) {
|
||||
@Single
|
||||
open class ToggleAnalyticsUseCase constructor(private val analyticsPrefs: AnalyticsPrefs) {
|
||||
operator fun invoke() {
|
||||
analyticsPrefs.setAnalyticsAllowed(!analyticsPrefs.analyticsAllowed.value)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,11 +16,12 @@
|
|||
*/
|
||||
package org.meshtastic.core.domain.usecase.settings
|
||||
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.repository.HomoglyphPrefs
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Use case for toggling the homoglyph encoding preference. */
|
||||
open class ToggleHomoglyphEncodingUseCase @Inject constructor(private val homoglyphEncodingPrefs: HomoglyphPrefs) {
|
||||
@Single
|
||||
open class ToggleHomoglyphEncodingUseCase constructor(private val homoglyphEncodingPrefs: HomoglyphPrefs) {
|
||||
operator fun invoke() {
|
||||
homoglyphEncodingPrefs.setHomoglyphEncodingEnabled(!homoglyphEncodingPrefs.homoglyphEncodingEnabled.value)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,30 +14,14 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import com.android.build.api.dsl.LibraryExtension
|
||||
|
||||
/*
|
||||
* 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.kmp.library)
|
||||
alias(libs.plugins.meshtastic.kotlinx.serialization)
|
||||
}
|
||||
|
||||
configure<LibraryExtension> { namespace = "org.meshtastic.core.navigation" }
|
||||
kotlin {
|
||||
android { namespace = "org.meshtastic.core.navigation" }
|
||||
|
||||
dependencies { implementation(libs.kotlinx.serialization.core) }
|
||||
sourceSets { commonMain.dependencies { implementation(libs.kotlinx.serialization.core) } }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
plugins {
|
||||
alias(libs.plugins.meshtastic.kmp.library)
|
||||
alias(libs.plugins.meshtastic.kotlinx.serialization)
|
||||
alias(libs.plugins.devtools.ksp)
|
||||
id("meshtastic.koin")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
|
|
@ -35,7 +35,6 @@ kotlin {
|
|||
implementation(projects.core.model)
|
||||
implementation(projects.core.proto)
|
||||
|
||||
api(libs.javax.inject)
|
||||
implementation(libs.okio)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
implementation(libs.ktor.client.core)
|
||||
|
|
@ -43,8 +42,8 @@ kotlin {
|
|||
implementation(libs.ktor.serialization.kotlinx.json)
|
||||
implementation(libs.kermit)
|
||||
}
|
||||
|
||||
androidMain.dependencies {
|
||||
implementation(libs.hilt.android)
|
||||
implementation(libs.org.eclipse.paho.client.mqttv3)
|
||||
implementation(libs.coil.network.okhttp)
|
||||
implementation(libs.coil.svg)
|
||||
|
|
@ -61,5 +60,3 @@ configurations.all {
|
|||
attributes.attribute(marketplaceAttr, "fdroid")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies { add("kspAndroid", libs.hilt.compiler) }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.network.di
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.engine.okhttp.OkHttp
|
||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||
import io.ktor.serialization.kotlinx.json.json
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.koin.core.annotation.ComponentScan
|
||||
import org.koin.core.annotation.Module
|
||||
import org.koin.core.annotation.Single
|
||||
|
||||
@Module
|
||||
@ComponentScan("org.meshtastic.core.network")
|
||||
class CoreNetworkAndroidModule {
|
||||
@Single
|
||||
fun provideHttpClient(json: Json): HttpClient = HttpClient(OkHttp) { install(ContentNegotiation) { json(json) } }
|
||||
}
|
||||
|
|
@ -30,6 +30,7 @@ import org.eclipse.paho.client.mqttv3.MqttCallbackExtended
|
|||
import org.eclipse.paho.client.mqttv3.MqttConnectOptions
|
||||
import org.eclipse.paho.client.mqttv3.MqttMessage
|
||||
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.util.ignoreException
|
||||
import org.meshtastic.core.model.util.subscribeList
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
|
|
@ -37,14 +38,11 @@ import org.meshtastic.core.repository.RadioConfigRepository
|
|||
import org.meshtastic.proto.MqttClientProxyMessage
|
||||
import java.net.URI
|
||||
import java.security.SecureRandom
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import javax.net.ssl.SSLContext
|
||||
import javax.net.ssl.TrustManager
|
||||
|
||||
@Singleton
|
||||
@Single
|
||||
class MQTTRepositoryImpl
|
||||
@Inject
|
||||
constructor(
|
||||
private val radioConfigRepository: RadioConfigRepository,
|
||||
private val nodeRepository: NodeRepository,
|
||||
|
|
|
|||
|
|
@ -17,14 +17,13 @@
|
|||
package org.meshtastic.core.network
|
||||
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
import org.meshtastic.core.model.NetworkDeviceHardware
|
||||
import org.meshtastic.core.network.service.ApiService
|
||||
import javax.inject.Inject
|
||||
|
||||
class DeviceHardwareRemoteDataSource
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class DeviceHardwareRemoteDataSource(
|
||||
private val apiService: ApiService,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -17,14 +17,13 @@
|
|||
package org.meshtastic.core.network
|
||||
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
import org.meshtastic.core.model.NetworkFirmwareReleases
|
||||
import org.meshtastic.core.network.service.ApiService
|
||||
import javax.inject.Inject
|
||||
|
||||
class FirmwareReleaseRemoteDataSource
|
||||
@Inject
|
||||
constructor(
|
||||
@Single
|
||||
class FirmwareReleaseRemoteDataSource(
|
||||
private val apiService: ApiService,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.network.di
|
||||
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.koin.core.annotation.ComponentScan
|
||||
import org.koin.core.annotation.Module
|
||||
import org.koin.core.annotation.Single
|
||||
|
||||
@Module
|
||||
@ComponentScan("org.meshtastic.core.network")
|
||||
class CoreNetworkModule {
|
||||
@Single
|
||||
fun provideJson(): Json = Json {
|
||||
ignoreUnknownKeys = true
|
||||
coerceInputValues = true
|
||||
}
|
||||
}
|
||||
|
|
@ -19,9 +19,9 @@ package org.meshtastic.core.network.service
|
|||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.call.body
|
||||
import io.ktor.client.request.get
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.model.NetworkDeviceHardware
|
||||
import org.meshtastic.core.model.NetworkFirmwareReleases
|
||||
import javax.inject.Inject
|
||||
|
||||
interface ApiService {
|
||||
suspend fun getDeviceHardware(): List<NetworkDeviceHardware>
|
||||
|
|
@ -29,7 +29,8 @@ interface ApiService {
|
|||
suspend fun getFirmwareReleases(): NetworkFirmwareReleases
|
||||
}
|
||||
|
||||
class ApiServiceImpl @Inject constructor(private val client: HttpClient) : ApiService {
|
||||
@Single
|
||||
class ApiServiceImpl(private val client: HttpClient) : ApiService {
|
||||
override suspend fun getDeviceHardware(): List<NetworkDeviceHardware> =
|
||||
client.get("https://api.meshtastic.org/resource/deviceHardware").body()
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
plugins {
|
||||
alias(libs.plugins.meshtastic.kmp.library)
|
||||
alias(libs.plugins.devtools.ksp)
|
||||
id("meshtastic.koin")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
|
|
@ -34,7 +34,6 @@ kotlin {
|
|||
implementation(projects.core.common)
|
||||
implementation(projects.core.di)
|
||||
|
||||
api(libs.javax.inject)
|
||||
implementation(libs.androidx.datastore.preferences)
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
}
|
||||
|
|
@ -46,5 +45,3 @@ kotlin {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies { add("kspAndroid", libs.hilt.compiler) }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.prefs.di
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.SharedPreferencesMigration
|
||||
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.preferencesDataStoreFile
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import org.koin.core.annotation.Module
|
||||
import org.koin.core.annotation.Named
|
||||
import org.koin.core.annotation.Single
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
@Module
|
||||
class CorePrefsAndroidModule {
|
||||
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
|
||||
@Single
|
||||
@Named("AnalyticsDataStore")
|
||||
fun provideAnalyticsDataStore(context: Context): DataStore<Preferences> = PreferenceDataStoreFactory.create(
|
||||
migrations = listOf(SharedPreferencesMigration(context, "analytics-prefs")),
|
||||
scope = scope,
|
||||
produceFile = { context.preferencesDataStoreFile("analytics_ds") },
|
||||
)
|
||||
|
||||
@Single
|
||||
@Named("HomoglyphEncodingDataStore")
|
||||
fun provideHomoglyphEncodingDataStore(context: Context): DataStore<Preferences> = PreferenceDataStoreFactory.create(
|
||||
migrations = listOf(SharedPreferencesMigration(context, "homoglyph-encoding-prefs")),
|
||||
scope = scope,
|
||||
produceFile = { context.preferencesDataStoreFile("homoglyph_encoding_ds") },
|
||||
)
|
||||
|
||||
@Single
|
||||
@Named("AppDataStore")
|
||||
fun provideAppDataStore(context: Context): DataStore<Preferences> = PreferenceDataStoreFactory.create(
|
||||
migrations = listOf(SharedPreferencesMigration(context, "prefs")),
|
||||
scope = scope,
|
||||
produceFile = { context.preferencesDataStoreFile("app_ds") },
|
||||
)
|
||||
|
||||
@Single
|
||||
@Named("CustomEmojiDataStore")
|
||||
fun provideCustomEmojiDataStore(context: Context): DataStore<Preferences> = PreferenceDataStoreFactory.create(
|
||||
migrations = listOf(SharedPreferencesMigration(context, "org.geeksville.emoji.prefs")),
|
||||
scope = scope,
|
||||
produceFile = { context.preferencesDataStoreFile("custom_emoji_ds") },
|
||||
)
|
||||
|
||||
@Single
|
||||
@Named("MapDataStore")
|
||||
fun provideMapDataStore(context: Context): DataStore<Preferences> = PreferenceDataStoreFactory.create(
|
||||
migrations = listOf(SharedPreferencesMigration(context, "map_prefs")),
|
||||
scope = scope,
|
||||
produceFile = { context.preferencesDataStoreFile("map_ds") },
|
||||
)
|
||||
|
||||
@Single
|
||||
@Named("MapConsentDataStore")
|
||||
fun provideMapConsentDataStore(context: Context): DataStore<Preferences> = PreferenceDataStoreFactory.create(
|
||||
migrations = listOf(SharedPreferencesMigration(context, "map_consent_preferences")),
|
||||
scope = scope,
|
||||
produceFile = { context.preferencesDataStoreFile("map_consent_ds") },
|
||||
)
|
||||
|
||||
@Single
|
||||
@Named("MapTileProviderDataStore")
|
||||
fun provideMapTileProviderDataStore(context: Context): DataStore<Preferences> = PreferenceDataStoreFactory.create(
|
||||
migrations = listOf(SharedPreferencesMigration(context, "map_tile_provider_prefs")),
|
||||
scope = scope,
|
||||
produceFile = { context.preferencesDataStoreFile("map_tile_provider_ds") },
|
||||
)
|
||||
|
||||
@Single
|
||||
@Named("MeshDataStore")
|
||||
fun provideMeshDataStore(context: Context): DataStore<Preferences> = PreferenceDataStoreFactory.create(
|
||||
migrations = listOf(SharedPreferencesMigration(context, "mesh-prefs")),
|
||||
scope = scope,
|
||||
produceFile = { context.preferencesDataStoreFile("mesh_ds") },
|
||||
)
|
||||
|
||||
@Single
|
||||
@Named("RadioDataStore")
|
||||
fun provideRadioDataStore(context: Context): DataStore<Preferences> = PreferenceDataStoreFactory.create(
|
||||
migrations = listOf(SharedPreferencesMigration(context, "radio-prefs")),
|
||||
scope = scope,
|
||||
produceFile = { context.preferencesDataStoreFile("radio_ds") },
|
||||
)
|
||||
|
||||
@Single
|
||||
@Named("UiDataStore")
|
||||
fun provideUiDataStore(context: Context): DataStore<Preferences> = PreferenceDataStoreFactory.create(
|
||||
migrations = listOf(SharedPreferencesMigration(context, "ui-prefs")),
|
||||
scope = scope,
|
||||
produceFile = { context.preferencesDataStoreFile("ui_ds") },
|
||||
)
|
||||
|
||||
@Single
|
||||
@Named("MeshLogDataStore")
|
||||
fun provideMeshLogDataStore(context: Context): DataStore<Preferences> = PreferenceDataStoreFactory.create(
|
||||
migrations = listOf(SharedPreferencesMigration(context, "meshlog-prefs")),
|
||||
scope = scope,
|
||||
produceFile = { context.preferencesDataStoreFile("meshlog_ds") },
|
||||
)
|
||||
|
||||
@Single
|
||||
@Named("FilterDataStore")
|
||||
fun provideFilterDataStore(context: Context): DataStore<Preferences> = PreferenceDataStoreFactory.create(
|
||||
migrations = listOf(SharedPreferencesMigration(context, "filter-prefs")),
|
||||
scope = scope,
|
||||
produceFile = { context.preferencesDataStoreFile("filter_ds") },
|
||||
)
|
||||
}
|
||||
|
|
@ -28,20 +28,16 @@ import kotlinx.coroutines.flow.StateFlow
|
|||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.annotation.Named
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
import org.meshtastic.core.prefs.di.AnalyticsDataStore
|
||||
import org.meshtastic.core.prefs.di.AppDataStore
|
||||
import org.meshtastic.core.repository.AnalyticsPrefs
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
@Singleton
|
||||
class AnalyticsPrefsImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@AnalyticsDataStore private val analyticsDataStore: DataStore<Preferences>,
|
||||
@AppDataStore private val appDataStore: DataStore<Preferences>,
|
||||
@Single
|
||||
class AnalyticsPrefsImpl(
|
||||
@Named("AnalyticsDataStore") private val analyticsDataStore: DataStore<Preferences>,
|
||||
@Named("AppDataStore") private val appDataStore: DataStore<Preferences>,
|
||||
dispatchers: CoroutineDispatchers,
|
||||
) : AnalyticsPrefs {
|
||||
private val scope = CoroutineScope(SupervisorJob() + dispatchers.default)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.prefs.di
|
||||
|
||||
import org.koin.core.annotation.ComponentScan
|
||||
import org.koin.core.annotation.Module
|
||||
|
||||
@Module
|
||||
@ComponentScan("org.meshtastic.core.prefs")
|
||||
class CorePrefsModule
|
||||
|
|
@ -27,17 +27,14 @@ import kotlinx.coroutines.flow.StateFlow
|
|||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.annotation.Named
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
import org.meshtastic.core.prefs.di.CustomEmojiDataStore
|
||||
import org.meshtastic.core.repository.CustomEmojiPrefs
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class CustomEmojiPrefsImpl
|
||||
@Inject
|
||||
constructor(
|
||||
@CustomEmojiDataStore private val dataStore: DataStore<Preferences>,
|
||||
@Single
|
||||
class CustomEmojiPrefsImpl(
|
||||
@Named("CustomEmojiDataStore") private val dataStore: DataStore<Preferences>,
|
||||
dispatchers: CoroutineDispatchers,
|
||||
) : CustomEmojiPrefs {
|
||||
private val scope = CoroutineScope(SupervisorJob() + dispatchers.default)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue