From 88ba0aa449bd616e6a14e5ac863f6a2e8e8b5837 Mon Sep 17 00:00:00 2001 From: Phil Oliver <3497406+poliver@users.noreply.github.com> Date: Thu, 16 Oct 2025 12:12:20 -0400 Subject: [PATCH] Align `CoroutineDispatchers` usage (#3481) --- .../geeksville/mesh/CoroutineDispatchers.kt | 32 ------------------ .../geeksville/mesh/model/MetricsViewModel.kt | 2 +- .../bluetooth/BluetoothRepository.kt | 2 +- .../repository/network/NetworkRepository.kt | 2 +- .../repository/radio/RadioInterfaceService.kt | 2 +- .../mesh/repository/usb/UsbRepository.kt | 2 +- .../geeksville/mesh/service/MeshService.kt | 2 +- .../CustomTileProviderRepository.kt | 7 ++-- .../core/data/repository/MeshLogRepository.kt | 25 +++++++------- .../core/data/repository/NodeRepository.kt | 33 +++++++++---------- .../repository/QuickChatActionRepository.kt | 15 ++++----- .../org/meshtastic/core/di/AppModule.kt | 11 ++----- ...tDispatcher.kt => CoroutineDispatchers.kt} | 13 +++++--- .../core/di/annotation/IoDispatcher.kt | 24 -------------- 14 files changed, 55 insertions(+), 117 deletions(-) delete mode 100644 app/src/main/java/com/geeksville/mesh/CoroutineDispatchers.kt rename core/di/src/main/kotlin/org/meshtastic/core/di/{annotation/DefaultDispatcher.kt => CoroutineDispatchers.kt} (68%) delete mode 100644 core/di/src/main/kotlin/org/meshtastic/core/di/annotation/IoDispatcher.kt diff --git a/app/src/main/java/com/geeksville/mesh/CoroutineDispatchers.kt b/app/src/main/java/com/geeksville/mesh/CoroutineDispatchers.kt deleted file mode 100644 index b0153f32e..000000000 --- a/app/src/main/java/com/geeksville/mesh/CoroutineDispatchers.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 . - */ - -package com.geeksville.mesh - -import kotlinx.coroutines.Dispatchers -import javax.inject.Inject - -/** - * Wrapper around `Dispatchers` to allow for easier testing when using dispatchers - * in injected classes. - */ -class CoroutineDispatchers @Inject constructor() { - val main = Dispatchers.Main - val mainImmediate = Dispatchers.Main.immediate - val default = Dispatchers.Default - val io = Dispatchers.IO -} \ No newline at end of file diff --git a/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt b/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt index 19cdfc68e..ec8a28c37 100644 --- a/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt +++ b/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt @@ -23,7 +23,6 @@ import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.navigation.toRoute -import com.geeksville.mesh.CoroutineDispatchers import com.geeksville.mesh.util.safeNumber import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow @@ -47,6 +46,7 @@ import org.meshtastic.core.data.repository.NodeRepository import org.meshtastic.core.data.repository.RadioConfigRepository import org.meshtastic.core.database.entity.MeshLog import org.meshtastic.core.database.model.Node +import org.meshtastic.core.di.CoroutineDispatchers import org.meshtastic.core.model.DataPacket import org.meshtastic.core.navigation.NodesRoutes import org.meshtastic.core.prefs.map.MapPrefs diff --git a/app/src/main/java/com/geeksville/mesh/repository/bluetooth/BluetoothRepository.kt b/app/src/main/java/com/geeksville/mesh/repository/bluetooth/BluetoothRepository.kt index 58756fa38..5e1548abf 100644 --- a/app/src/main/java/com/geeksville/mesh/repository/bluetooth/BluetoothRepository.kt +++ b/app/src/main/java/com/geeksville/mesh/repository/bluetooth/BluetoothRepository.kt @@ -27,7 +27,6 @@ import android.bluetooth.le.ScanSettings import androidx.annotation.RequiresPermission import androidx.lifecycle.Lifecycle import androidx.lifecycle.coroutineScope -import com.geeksville.mesh.CoroutineDispatchers import com.geeksville.mesh.util.registerReceiverCompat import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -37,6 +36,7 @@ import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch import org.meshtastic.core.common.hasBluetoothPermission +import org.meshtastic.core.di.CoroutineDispatchers import timber.log.Timber import javax.inject.Inject import javax.inject.Singleton diff --git a/app/src/main/java/com/geeksville/mesh/repository/network/NetworkRepository.kt b/app/src/main/java/com/geeksville/mesh/repository/network/NetworkRepository.kt index a7bb09006..ca7308c4c 100644 --- a/app/src/main/java/com/geeksville/mesh/repository/network/NetworkRepository.kt +++ b/app/src/main/java/com/geeksville/mesh/repository/network/NetworkRepository.kt @@ -20,10 +20,10 @@ package com.geeksville.mesh.repository.network import android.net.ConnectivityManager import android.net.nsd.NsdManager import android.net.nsd.NsdServiceInfo -import com.geeksville.mesh.CoroutineDispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.flowOn +import org.meshtastic.core.di.CoroutineDispatchers import javax.inject.Inject import javax.inject.Singleton diff --git a/app/src/main/java/com/geeksville/mesh/repository/radio/RadioInterfaceService.kt b/app/src/main/java/com/geeksville/mesh/repository/radio/RadioInterfaceService.kt index 803faadb2..7765cf514 100644 --- a/app/src/main/java/com/geeksville/mesh/repository/radio/RadioInterfaceService.kt +++ b/app/src/main/java/com/geeksville/mesh/repository/radio/RadioInterfaceService.kt @@ -22,7 +22,6 @@ import android.provider.Settings import androidx.lifecycle.Lifecycle import androidx.lifecycle.coroutineScope import com.geeksville.mesh.BuildConfig -import com.geeksville.mesh.CoroutineDispatchers import com.geeksville.mesh.android.BinaryLogFile import com.geeksville.mesh.android.BuildUtils import com.geeksville.mesh.concurrent.handledLaunch @@ -45,6 +44,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.meshtastic.core.analytics.platform.PlatformAnalytics +import org.meshtastic.core.di.CoroutineDispatchers import org.meshtastic.core.model.util.anonymize import org.meshtastic.core.prefs.radio.RadioPrefs import org.meshtastic.core.service.ConnectionState diff --git a/app/src/main/java/com/geeksville/mesh/repository/usb/UsbRepository.kt b/app/src/main/java/com/geeksville/mesh/repository/usb/UsbRepository.kt index f60ec4778..95d7d8a4c 100644 --- a/app/src/main/java/com/geeksville/mesh/repository/usb/UsbRepository.kt +++ b/app/src/main/java/com/geeksville/mesh/repository/usb/UsbRepository.kt @@ -22,7 +22,6 @@ import android.hardware.usb.UsbDevice import android.hardware.usb.UsbManager import androidx.lifecycle.Lifecycle import androidx.lifecycle.coroutineScope -import com.geeksville.mesh.CoroutineDispatchers import com.geeksville.mesh.util.registerReceiverCompat import com.hoho.android.usbserial.driver.UsbSerialDriver import com.hoho.android.usbserial.driver.UsbSerialProber @@ -36,6 +35,7 @@ import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import org.meshtastic.core.di.CoroutineDispatchers import javax.inject.Inject import javax.inject.Singleton diff --git a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt index 45bf98d24..f3fb2b45f 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -29,7 +29,6 @@ import android.os.RemoteException import androidx.core.app.ServiceCompat import androidx.core.location.LocationCompat import com.geeksville.mesh.BuildConfig -import com.geeksville.mesh.CoroutineDispatchers import com.geeksville.mesh.concurrent.handledLaunch import com.geeksville.mesh.model.NO_DEVICE_SELECTED import com.geeksville.mesh.repository.network.MQTTRepository @@ -66,6 +65,7 @@ import org.meshtastic.core.database.entity.NodeEntity import org.meshtastic.core.database.entity.Packet import org.meshtastic.core.database.entity.ReactionEntity import org.meshtastic.core.database.model.Node +import org.meshtastic.core.di.CoroutineDispatchers import org.meshtastic.core.model.DataPacket import org.meshtastic.core.model.DeviceVersion import org.meshtastic.core.model.MeshUser diff --git a/core/data/src/google/kotlin/org/meshtastic/core/data/repository/CustomTileProviderRepository.kt b/core/data/src/google/kotlin/org/meshtastic/core/data/repository/CustomTileProviderRepository.kt index f2c0262a8..219a247ce 100644 --- a/core/data/src/google/kotlin/org/meshtastic/core/data/repository/CustomTileProviderRepository.kt +++ b/core/data/src/google/kotlin/org/meshtastic/core/data/repository/CustomTileProviderRepository.kt @@ -17,7 +17,6 @@ package org.meshtastic.core.data.repository -import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow @@ -25,7 +24,7 @@ import kotlinx.coroutines.withContext import kotlinx.serialization.SerializationException import kotlinx.serialization.json.Json import org.meshtastic.core.data.model.CustomTileProviderConfig -import org.meshtastic.core.di.annotation.IoDispatcher +import org.meshtastic.core.di.CoroutineDispatchers import org.meshtastic.core.prefs.map.MapTileProviderPrefs import timber.log.Timber import javax.inject.Inject @@ -49,7 +48,7 @@ class CustomTileProviderRepositoryImpl @Inject constructor( private val json: Json, - @IoDispatcher private val ioDispatcher: CoroutineDispatcher, + private val dispatchers: CoroutineDispatchers, private val mapTileProviderPrefs: MapTileProviderPrefs, ) : CustomTileProviderRepository { @@ -98,7 +97,7 @@ constructor( } private suspend fun saveDataToPrefs(providers: List) { - withContext(ioDispatcher) { + withContext(dispatchers.io) { try { val jsonString = json.encodeToString(providers) mapTileProviderPrefs.customTileProviders = jsonString diff --git a/core/data/src/main/kotlin/org/meshtastic/core/data/repository/MeshLogRepository.kt b/core/data/src/main/kotlin/org/meshtastic/core/data/repository/MeshLogRepository.kt index 0ca56aa97..901c76e9d 100644 --- a/core/data/src/main/kotlin/org/meshtastic/core/data/repository/MeshLogRepository.kt +++ b/core/data/src/main/kotlin/org/meshtastic/core/data/repository/MeshLogRepository.kt @@ -18,7 +18,6 @@ package org.meshtastic.core.data.repository import dagger.Lazy -import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.distinctUntilChanged @@ -27,7 +26,7 @@ import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.withContext import org.meshtastic.core.database.dao.MeshLogDao import org.meshtastic.core.database.entity.MeshLog -import org.meshtastic.core.di.annotation.IoDispatcher +import org.meshtastic.core.di.CoroutineDispatchers import org.meshtastic.proto.MeshProtos import org.meshtastic.proto.MeshProtos.MeshPacket import org.meshtastic.proto.Portnums @@ -39,15 +38,15 @@ class MeshLogRepository @Inject constructor( private val meshLogDaoLazy: Lazy, - @IoDispatcher private val ioDispatcher: CoroutineDispatcher, + private val dispatchers: CoroutineDispatchers, ) { private val meshLogDao by lazy { meshLogDaoLazy.get() } fun getAllLogs(maxItems: Int = MAX_ITEMS): Flow> = - meshLogDao.getAllLogs(maxItems).flowOn(ioDispatcher).conflate() + meshLogDao.getAllLogs(maxItems).flowOn(dispatchers.io).conflate() fun getAllLogsInReceiveOrder(maxItems: Int = MAX_ITEMS): Flow> = - meshLogDao.getAllLogsInReceiveOrder(maxItems).flowOn(ioDispatcher).conflate() + meshLogDao.getAllLogsInReceiveOrder(maxItems).flowOn(dispatchers.io).conflate() private fun parseTelemetryLog(log: MeshLog): Telemetry? = runCatching { Telemetry.parseFrom(log.fromRadio.packet.decoded.payload) @@ -111,34 +110,34 @@ constructor( .getLogsFrom(nodeNum, Portnums.PortNum.TELEMETRY_APP_VALUE, MAX_MESH_PACKETS) .distinctUntilChanged() .mapLatest { list -> list.mapNotNull(::parseTelemetryLog) } - .flowOn(ioDispatcher) + .flowOn(dispatchers.io) fun getLogsFrom( nodeNum: Int, portNum: Int = Portnums.PortNum.UNKNOWN_APP_VALUE, maxItem: Int = MAX_MESH_PACKETS, ): Flow> = - meshLogDao.getLogsFrom(nodeNum, portNum, maxItem).distinctUntilChanged().flowOn(ioDispatcher) + meshLogDao.getLogsFrom(nodeNum, portNum, maxItem).distinctUntilChanged().flowOn(dispatchers.io) /* * Retrieves MeshPackets matching 'nodeNum' and 'portNum'. * If 'portNum' is not specified, returns all MeshPackets. Otherwise, filters by 'portNum'. */ fun getMeshPacketsFrom(nodeNum: Int, portNum: Int = Portnums.PortNum.UNKNOWN_APP_VALUE): Flow> = - getLogsFrom(nodeNum, portNum).mapLatest { list -> list.map { it.fromRadio.packet } }.flowOn(ioDispatcher) + getLogsFrom(nodeNum, portNum).mapLatest { list -> list.map { it.fromRadio.packet } }.flowOn(dispatchers.io) fun getMyNodeInfo(): Flow = getLogsFrom(0, 0) .mapLatest { list -> list.firstOrNull { it.myNodeInfo != null }?.myNodeInfo } - .flowOn(ioDispatcher) + .flowOn(dispatchers.io) - suspend fun insert(log: MeshLog) = withContext(ioDispatcher) { meshLogDao.insert(log) } + suspend fun insert(log: MeshLog) = withContext(dispatchers.io) { meshLogDao.insert(log) } - suspend fun deleteAll() = withContext(ioDispatcher) { meshLogDao.deleteAll() } + suspend fun deleteAll() = withContext(dispatchers.io) { meshLogDao.deleteAll() } - suspend fun deleteLog(uuid: String) = withContext(ioDispatcher) { meshLogDao.deleteLog(uuid) } + suspend fun deleteLog(uuid: String) = withContext(dispatchers.io) { meshLogDao.deleteLog(uuid) } suspend fun deleteLogs(nodeNum: Int, portNum: Int) = - withContext(ioDispatcher) { meshLogDao.deleteLogs(nodeNum, portNum) } + withContext(dispatchers.io) { meshLogDao.deleteLogs(nodeNum, portNum) } companion object { private const val MAX_ITEMS = 500 diff --git a/core/data/src/main/kotlin/org/meshtastic/core/data/repository/NodeRepository.kt b/core/data/src/main/kotlin/org/meshtastic/core/data/repository/NodeRepository.kt index 5d3fcd056..1da31109d 100644 --- a/core/data/src/main/kotlin/org/meshtastic/core/data/repository/NodeRepository.kt +++ b/core/data/src/main/kotlin/org/meshtastic/core/data/repository/NodeRepository.kt @@ -19,7 +19,6 @@ package org.meshtastic.core.data.repository import androidx.lifecycle.Lifecycle import androidx.lifecycle.coroutineScope -import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -37,7 +36,7 @@ import org.meshtastic.core.database.entity.MyNodeEntity import org.meshtastic.core.database.entity.NodeEntity import org.meshtastic.core.database.model.Node import org.meshtastic.core.database.model.NodeSortOption -import org.meshtastic.core.di.annotation.IoDispatcher +import org.meshtastic.core.di.CoroutineDispatchers import org.meshtastic.core.model.DataPacket import org.meshtastic.core.model.util.onlineTimeThreshold import org.meshtastic.proto.MeshProtos @@ -52,13 +51,13 @@ class NodeRepository constructor( processLifecycle: Lifecycle, private val nodeInfoDao: NodeInfoDao, - @IoDispatcher private val ioDispatcher: CoroutineDispatcher, + private val dispatchers: CoroutineDispatchers, ) { // hardware info about our local device (can be null) val myNodeInfo: StateFlow = nodeInfoDao .getMyNodeInfo() - .flowOn(ioDispatcher) + .flowOn(dispatchers.io) .stateIn(processLifecycle.coroutineScope, SharingStarted.Eagerly, null) // our node info @@ -83,7 +82,7 @@ constructor( _ourNodeInfo.value = ourNodeInfo _myId.value = ourNodeInfo?.user?.id } - .flowOn(ioDispatcher) + .flowOn(dispatchers.io) .conflate() .stateIn(processLifecycle.coroutineScope, SharingStarted.Eagerly, emptyMap()) @@ -115,43 +114,43 @@ constructor( lastHeardMin = if (onlyOnline) onlineTimeThreshold() else -1, ) .mapLatest { list -> list.map { it.toModel() } } - .flowOn(ioDispatcher) + .flowOn(dispatchers.io) .conflate() - suspend fun upsert(node: NodeEntity) = withContext(ioDispatcher) { nodeInfoDao.upsert(node) } + suspend fun upsert(node: NodeEntity) = withContext(dispatchers.io) { nodeInfoDao.upsert(node) } suspend fun installConfig(mi: MyNodeEntity, nodes: List) = - withContext(ioDispatcher) { nodeInfoDao.installConfig(mi, nodes) } + withContext(dispatchers.io) { nodeInfoDao.installConfig(mi, nodes) } - suspend fun clearNodeDB() = withContext(ioDispatcher) { nodeInfoDao.clearNodeInfo() } + suspend fun clearNodeDB() = withContext(dispatchers.io) { nodeInfoDao.clearNodeInfo() } - suspend fun deleteNode(num: Int) = withContext(ioDispatcher) { + suspend fun deleteNode(num: Int) = withContext(dispatchers.io) { nodeInfoDao.deleteNode(num) nodeInfoDao.deleteMetadata(num) } - suspend fun deleteNodes(nodeNums: List) = withContext(ioDispatcher) { + suspend fun deleteNodes(nodeNums: List) = withContext(dispatchers.io) { nodeInfoDao.deleteNodes(nodeNums) nodeNums.forEach { nodeInfoDao.deleteMetadata(it) } } suspend fun getNodesOlderThan(lastHeard: Int): List = - withContext(ioDispatcher) { nodeInfoDao.getNodesOlderThan(lastHeard) } + withContext(dispatchers.io) { nodeInfoDao.getNodesOlderThan(lastHeard) } - suspend fun getUnknownNodes(): List = withContext(ioDispatcher) { nodeInfoDao.getUnknownNodes() } + suspend fun getUnknownNodes(): List = withContext(dispatchers.io) { nodeInfoDao.getUnknownNodes() } - suspend fun insertMetadata(metadata: MetadataEntity) = withContext(ioDispatcher) { nodeInfoDao.upsert(metadata) } + suspend fun insertMetadata(metadata: MetadataEntity) = withContext(dispatchers.io) { nodeInfoDao.upsert(metadata) } val onlineNodeCount: Flow = nodeInfoDao .nodeDBbyNum() .mapLatest { map -> map.values.count { it.node.lastHeard > onlineTimeThreshold() } } - .flowOn(ioDispatcher) + .flowOn(dispatchers.io) .conflate() val totalNodeCount: Flow = - nodeInfoDao.nodeDBbyNum().mapLatest { map -> map.values.count() }.flowOn(ioDispatcher).conflate() + nodeInfoDao.nodeDBbyNum().mapLatest { map -> map.values.count() }.flowOn(dispatchers.io).conflate() suspend fun setNodeNotes(num: Int, notes: String) = - withContext(ioDispatcher) { nodeInfoDao.setNodeNotes(num, notes) } + withContext(dispatchers.io) { nodeInfoDao.setNodeNotes(num, notes) } } diff --git a/core/data/src/main/kotlin/org/meshtastic/core/data/repository/QuickChatActionRepository.kt b/core/data/src/main/kotlin/org/meshtastic/core/data/repository/QuickChatActionRepository.kt index f05c75453..2a4069d63 100644 --- a/core/data/src/main/kotlin/org/meshtastic/core/data/repository/QuickChatActionRepository.kt +++ b/core/data/src/main/kotlin/org/meshtastic/core/data/repository/QuickChatActionRepository.kt @@ -18,30 +18,29 @@ package org.meshtastic.core.data.repository import dagger.Lazy -import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.withContext import org.meshtastic.core.database.dao.QuickChatActionDao import org.meshtastic.core.database.entity.QuickChatAction -import org.meshtastic.core.di.annotation.IoDispatcher +import org.meshtastic.core.di.CoroutineDispatchers import javax.inject.Inject class QuickChatActionRepository @Inject constructor( private val quickChatDaoLazy: Lazy, - @IoDispatcher private val ioDispatcher: CoroutineDispatcher, + private val dispatchers: CoroutineDispatchers, ) { private val quickChatActionDao by lazy { quickChatDaoLazy.get() } - fun getAllActions() = quickChatActionDao.getAll().flowOn(ioDispatcher) + fun getAllActions() = quickChatActionDao.getAll().flowOn(dispatchers.io) - suspend fun upsert(action: QuickChatAction) = withContext(ioDispatcher) { quickChatActionDao.upsert(action) } + suspend fun upsert(action: QuickChatAction) = withContext(dispatchers.io) { quickChatActionDao.upsert(action) } - suspend fun deleteAll() = withContext(ioDispatcher) { quickChatActionDao.deleteAll() } + suspend fun deleteAll() = withContext(dispatchers.io) { quickChatActionDao.deleteAll() } - suspend fun delete(action: QuickChatAction) = withContext(ioDispatcher) { quickChatActionDao.delete(action) } + suspend fun delete(action: QuickChatAction) = withContext(dispatchers.io) { quickChatActionDao.delete(action) } suspend fun setItemPosition(uuid: Long, newPos: Int) = - withContext(ioDispatcher) { quickChatActionDao.updateActionPosition(uuid, newPos) } + withContext(dispatchers.io) { quickChatActionDao.updateActionPosition(uuid, newPos) } } diff --git a/core/di/src/main/kotlin/org/meshtastic/core/di/AppModule.kt b/core/di/src/main/kotlin/org/meshtastic/core/di/AppModule.kt index c4a43371e..4c834d897 100644 --- a/core/di/src/main/kotlin/org/meshtastic/core/di/AppModule.kt +++ b/core/di/src/main/kotlin/org/meshtastic/core/di/AppModule.kt @@ -21,18 +21,13 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent -import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers -import org.meshtastic.core.di.annotation.DefaultDispatcher -import org.meshtastic.core.di.annotation.IoDispatcher @Module @InstallIn(SingletonComponent::class) object AppModule { - @Provides @DefaultDispatcher - fun provideDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default - - @Provides @IoDispatcher - fun provideIoDispatcher(): CoroutineDispatcher = Dispatchers.IO + @Provides + fun provideCoroutineDispatchers(): CoroutineDispatchers = + CoroutineDispatchers(io = Dispatchers.IO, main = Dispatchers.Main, default = Dispatchers.Default) } diff --git a/core/di/src/main/kotlin/org/meshtastic/core/di/annotation/DefaultDispatcher.kt b/core/di/src/main/kotlin/org/meshtastic/core/di/CoroutineDispatchers.kt similarity index 68% rename from core/di/src/main/kotlin/org/meshtastic/core/di/annotation/DefaultDispatcher.kt rename to core/di/src/main/kotlin/org/meshtastic/core/di/CoroutineDispatchers.kt index e7452bf9d..a7d4ad92c 100644 --- a/core/di/src/main/kotlin/org/meshtastic/core/di/annotation/DefaultDispatcher.kt +++ b/core/di/src/main/kotlin/org/meshtastic/core/di/CoroutineDispatchers.kt @@ -15,10 +15,13 @@ * along with this program. If not, see . */ -package org.meshtastic.core.di.annotation +package org.meshtastic.core.di -import javax.inject.Qualifier +import kotlinx.coroutines.CoroutineDispatcher -@Qualifier -@Retention(AnnotationRetention.BINARY) -annotation class DefaultDispatcher +/** Wrapper around `Dispatchers` to allow for easier testing when using dispatchers in injected classes. */ +data class CoroutineDispatchers( + val io: CoroutineDispatcher, + val main: CoroutineDispatcher, + val default: CoroutineDispatcher, +) diff --git a/core/di/src/main/kotlin/org/meshtastic/core/di/annotation/IoDispatcher.kt b/core/di/src/main/kotlin/org/meshtastic/core/di/annotation/IoDispatcher.kt deleted file mode 100644 index c47e18797..000000000 --- a/core/di/src/main/kotlin/org/meshtastic/core/di/annotation/IoDispatcher.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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 . - */ - -package org.meshtastic.core.di.annotation - -import javax.inject.Qualifier - -@Qualifier -@Retention(AnnotationRetention.BINARY) -annotation class IoDispatcher