mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
feat: Implement iOS support and unify Compose Multiplatform infrastructure (#4876)
This commit is contained in:
parent
f04924ded5
commit
d136b162a4
170 changed files with 2208 additions and 2432 deletions
|
|
@ -19,7 +19,6 @@ package org.meshtastic.core.data.manager
|
|||
import co.touchlab.kermit.Logger
|
||||
import kotlinx.atomicfu.atomic
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
|
|
@ -27,6 +26,7 @@ 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.ioDispatcher
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.core.model.MessageStatus
|
||||
|
|
@ -58,7 +58,7 @@ class CommandSenderImpl(
|
|||
private val nodeManager: NodeManager,
|
||||
private val radioConfigRepository: RadioConfigRepository,
|
||||
) : CommandSender {
|
||||
private var scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
private var scope: CoroutineScope = CoroutineScope(ioDispatcher + SupervisorJob())
|
||||
private val currentPacketId = atomic(Random(nowMillis).nextLong().absoluteValue)
|
||||
private val sessionPasskey = atomic(ByteString.EMPTY)
|
||||
override val tracerouteStartTimes = mutableMapOf<Int, Long>()
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@
|
|||
package org.meshtastic.core.data.manager
|
||||
|
||||
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
|
||||
import org.meshtastic.core.common.util.ioDispatcher
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.core.model.MeshUser
|
||||
|
|
@ -64,7 +64,7 @@ class MeshActionHandlerImpl(
|
|||
private val notificationManager: NotificationManager,
|
||||
private val messageProcessor: Lazy<MeshMessageProcessor>,
|
||||
) : MeshActionHandler {
|
||||
private var scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
private var scope: CoroutineScope = CoroutineScope(ioDispatcher + SupervisorJob())
|
||||
|
||||
override fun start(scope: CoroutineScope) {
|
||||
this.scope = scope
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ package org.meshtastic.core.data.manager
|
|||
|
||||
import co.touchlab.kermit.Logger
|
||||
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.common.util.ioDispatcher
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.repository.CommandSender
|
||||
import org.meshtastic.core.repository.MeshConfigFlowManager
|
||||
|
|
@ -56,7 +56,7 @@ class MeshConfigFlowManagerImpl(
|
|||
private val commandSender: CommandSender,
|
||||
private val packetHandler: PacketHandler,
|
||||
) : MeshConfigFlowManager {
|
||||
private var scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
private var scope: CoroutineScope = CoroutineScope(ioDispatcher + SupervisorJob())
|
||||
private val configOnlyNonce = 69420
|
||||
private val nodeInfoNonce = 69421
|
||||
private val wantConfigDelay = 100L
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
package org.meshtastic.core.data.manager
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
|
@ -25,6 +24,7 @@ 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.common.util.ioDispatcher
|
||||
import org.meshtastic.core.repository.MeshConfigHandler
|
||||
import org.meshtastic.core.repository.NodeManager
|
||||
import org.meshtastic.core.repository.RadioConfigRepository
|
||||
|
|
@ -41,7 +41,7 @@ class MeshConfigHandlerImpl(
|
|||
private val serviceRepository: ServiceRepository,
|
||||
private val nodeManager: NodeManager,
|
||||
) : MeshConfigHandler {
|
||||
private var scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
private var scope: CoroutineScope = CoroutineScope(ioDispatcher + SupervisorJob())
|
||||
|
||||
private val _localConfig = MutableStateFlow(LocalConfig())
|
||||
override val localConfig = _localConfig.asStateFlow()
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package org.meshtastic.core.data.manager
|
|||
import co.touchlab.kermit.Logger
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
|
|
@ -30,6 +29,7 @@ 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.ioDispatcher
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.common.util.nowSeconds
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
|
|
@ -89,7 +89,7 @@ class MeshConnectionManagerImpl(
|
|||
private val workerManager: MeshWorkerManager,
|
||||
private val appWidgetUpdater: AppWidgetUpdater,
|
||||
) : MeshConnectionManager {
|
||||
private var scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
private var scope: CoroutineScope = CoroutineScope(ioDispatcher + SupervisorJob())
|
||||
private var sleepTimeout: Job? = null
|
||||
private var locationRequestsJob: Job? = null
|
||||
private var handshakeTimeout: Job? = null
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package org.meshtastic.core.data.manager
|
|||
import co.touchlab.kermit.Logger
|
||||
import co.touchlab.kermit.Severity
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
|
@ -30,6 +29,7 @@ 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.ioDispatcher
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.common.util.nowSeconds
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
|
|
@ -63,7 +63,7 @@ import org.meshtastic.core.repository.TracerouteHandler
|
|||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.critical_alert
|
||||
import org.meshtastic.core.resources.error_duty_cycle
|
||||
import org.meshtastic.core.resources.getString
|
||||
import org.meshtastic.core.resources.getStringSuspend
|
||||
import org.meshtastic.core.resources.low_battery_message
|
||||
import org.meshtastic.core.resources.low_battery_title
|
||||
import org.meshtastic.core.resources.unknown_username
|
||||
|
|
@ -114,7 +114,7 @@ class MeshDataHandlerImpl(
|
|||
private val radioConfigRepository: RadioConfigRepository,
|
||||
private val messageFilter: MessageFilter,
|
||||
) : MeshDataHandler {
|
||||
private var scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
private var scope: CoroutineScope = CoroutineScope(ioDispatcher + SupervisorJob())
|
||||
|
||||
override fun start(scope: CoroutineScope) {
|
||||
this.scope = scope
|
||||
|
|
@ -433,9 +433,13 @@ class MeshDataHandlerImpl(
|
|||
if (shouldBatteryNotificationShow(fromNum, t, myNodeNum)) {
|
||||
notificationManager.dispatch(
|
||||
Notification(
|
||||
title = getString(Res.string.low_battery_title, nextNode.user.short_name),
|
||||
title =
|
||||
getStringSuspend(
|
||||
Res.string.low_battery_title,
|
||||
nextNode.user.short_name,
|
||||
),
|
||||
message =
|
||||
getString(
|
||||
getStringSuspend(
|
||||
Res.string.low_battery_message,
|
||||
nextNode.user.long_name,
|
||||
nextNode.deviceMetrics.battery_level ?: 0,
|
||||
|
|
@ -502,7 +506,9 @@ class MeshDataHandlerImpl(
|
|||
val payload = packet.decoded?.payload ?: return
|
||||
val r = Routing.ADAPTER.decodeOrNull(payload, Logger) ?: return
|
||||
if (r.error_reason == Routing.Error.DUTY_CYCLE_LIMIT) {
|
||||
serviceRepository.setErrorMessage(getString(Res.string.error_duty_cycle), Severity.Warn)
|
||||
scope.launch {
|
||||
serviceRepository.setErrorMessage(getStringSuspend(Res.string.error_duty_cycle), Severity.Warn)
|
||||
}
|
||||
}
|
||||
handleAckNak(
|
||||
packet.decoded?.request_id ?: 0,
|
||||
|
|
@ -659,25 +665,27 @@ class MeshDataHandlerImpl(
|
|||
val nodeMuted = nodeManager.nodeDBbyID[dataPacket.from]?.isMuted == true
|
||||
val isSilent = conversationMuted || nodeMuted
|
||||
if (dataPacket.dataType == PortNum.ALERT_APP.value && !isSilent) {
|
||||
notificationManager.dispatch(
|
||||
Notification(
|
||||
title = getSenderName(dataPacket),
|
||||
message = dataPacket.alert ?: getString(Res.string.critical_alert),
|
||||
category = Notification.Category.Alert,
|
||||
contactKey = contactKey,
|
||||
),
|
||||
)
|
||||
scope.launch {
|
||||
notificationManager.dispatch(
|
||||
Notification(
|
||||
title = getSenderName(dataPacket),
|
||||
message = dataPacket.alert ?: getStringSuspend(Res.string.critical_alert),
|
||||
category = Notification.Category.Alert,
|
||||
contactKey = contactKey,
|
||||
),
|
||||
)
|
||||
}
|
||||
} else if (updateNotification && !isSilent) {
|
||||
scope.handledLaunch { updateNotification(contactKey, dataPacket, isSilent) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSenderName(packet: DataPacket): String {
|
||||
private suspend fun getSenderName(packet: DataPacket): String {
|
||||
if (packet.from == DataPacket.ID_LOCAL) {
|
||||
val myId = nodeManager.getMyId()
|
||||
return nodeManager.nodeDBbyID[myId]?.user?.long_name ?: getString(Res.string.unknown_username)
|
||||
return nodeManager.nodeDBbyID[myId]?.user?.long_name ?: getStringSuspend(Res.string.unknown_username)
|
||||
}
|
||||
return nodeManager.nodeDBbyID[packet.from]?.user?.long_name ?: getString(Res.string.unknown_username)
|
||||
return nodeManager.nodeDBbyID[packet.from]?.user?.long_name ?: getStringSuspend(Res.string.unknown_username)
|
||||
}
|
||||
|
||||
private suspend fun updateNotification(contactKey: String, dataPacket: DataPacket, isSilent: Boolean) {
|
||||
|
|
@ -701,7 +709,7 @@ class MeshDataHandlerImpl(
|
|||
}
|
||||
|
||||
PortNum.WAYPOINT_APP.value -> {
|
||||
val message = getString(Res.string.waypoint_received, dataPacket.waypoint!!.name)
|
||||
val message = getStringSuspend(Res.string.waypoint_received, dataPacket.waypoint!!.name)
|
||||
notificationManager.dispatch(
|
||||
Notification(
|
||||
title = getSenderName(dataPacket),
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ package org.meshtastic.core.data.manager
|
|||
|
||||
import co.touchlab.kermit.Logger
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
|
|
@ -28,6 +27,7 @@ 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.ioDispatcher
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.common.util.nowSeconds
|
||||
import org.meshtastic.core.model.MeshLog
|
||||
|
|
@ -55,7 +55,7 @@ class MeshMessageProcessorImpl(
|
|||
private val router: Lazy<MeshRouter>,
|
||||
private val fromRadioDispatcher: FromRadioPacketHandler,
|
||||
) : MeshMessageProcessor {
|
||||
private var scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
private var scope: CoroutineScope = CoroutineScope(ioDispatcher + SupervisorJob())
|
||||
|
||||
private val mapsMutex = Mutex()
|
||||
private val logUuidByPacketId = mutableMapOf<Int, String>()
|
||||
|
|
|
|||
|
|
@ -19,13 +19,13 @@ package org.meshtastic.core.data.manager
|
|||
import co.touchlab.kermit.Logger
|
||||
import co.touchlab.kermit.Severity
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
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.common.util.ioDispatcher
|
||||
import org.meshtastic.core.network.repository.MQTTRepository
|
||||
import org.meshtastic.core.repository.MqttManager
|
||||
import org.meshtastic.core.repository.PacketHandler
|
||||
|
|
@ -39,7 +39,7 @@ class MqttManagerImpl(
|
|||
private val packetHandler: PacketHandler,
|
||||
private val serviceRepository: ServiceRepository,
|
||||
) : MqttManager {
|
||||
private var scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
private var scope: CoroutineScope = CoroutineScope(ioDispatcher + SupervisorJob())
|
||||
private var mqttMessageFlow: Job? = null
|
||||
|
||||
override fun start(scope: CoroutineScope, enabled: Boolean, proxyToClientEnabled: Boolean) {
|
||||
|
|
|
|||
|
|
@ -18,10 +18,10 @@ package org.meshtastic.core.data.manager
|
|||
|
||||
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.NumberFormatter
|
||||
import org.meshtastic.core.common.util.ioDispatcher
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.repository.CommandSender
|
||||
import org.meshtastic.core.repository.NeighborInfoHandler
|
||||
|
|
@ -38,7 +38,7 @@ class NeighborInfoHandlerImpl(
|
|||
private val commandSender: CommandSender,
|
||||
private val serviceBroadcasts: ServiceBroadcasts,
|
||||
) : NeighborInfoHandler {
|
||||
private var scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
private var scope: CoroutineScope = CoroutineScope(ioDispatcher + SupervisorJob())
|
||||
|
||||
override fun start(scope: CoroutineScope) {
|
||||
this.scope = scope
|
||||
|
|
|
|||
|
|
@ -21,13 +21,13 @@ import kotlinx.atomicfu.atomic
|
|||
import kotlinx.atomicfu.update
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
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.common.util.ioDispatcher
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.core.model.DeviceMetrics
|
||||
import org.meshtastic.core.model.EnvironmentMetrics
|
||||
|
|
@ -43,7 +43,7 @@ import org.meshtastic.core.repository.Notification
|
|||
import org.meshtastic.core.repository.NotificationManager
|
||||
import org.meshtastic.core.repository.ServiceBroadcasts
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.getString
|
||||
import org.meshtastic.core.resources.getStringSuspend
|
||||
import org.meshtastic.core.resources.new_node_seen
|
||||
import org.meshtastic.proto.DeviceMetadata
|
||||
import org.meshtastic.proto.HardwareModel
|
||||
|
|
@ -62,7 +62,7 @@ class NodeManagerImpl(
|
|||
private val serviceBroadcasts: ServiceBroadcasts,
|
||||
private val notificationManager: NotificationManager,
|
||||
) : NodeManager {
|
||||
private var scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
private var scope: CoroutineScope = CoroutineScope(ioDispatcher + SupervisorJob())
|
||||
|
||||
private val _nodeDBbyNodeNum = atomic(persistentMapOf<Int, Node>())
|
||||
private val _nodeDBbyID = atomic(persistentMapOf<String, Node>())
|
||||
|
|
@ -196,13 +196,15 @@ class NodeManagerImpl(
|
|||
node.copy(user = newUser, channel = channel, manuallyVerified = manuallyVerified)
|
||||
}
|
||||
if (newNode && !shouldPreserve) {
|
||||
notificationManager.dispatch(
|
||||
Notification(
|
||||
title = getString(Res.string.new_node_seen, next.user.short_name),
|
||||
message = next.user.long_name,
|
||||
category = Notification.Category.NodeEvent,
|
||||
),
|
||||
)
|
||||
scope.handledLaunch {
|
||||
notificationManager.dispatch(
|
||||
Notification(
|
||||
title = getStringSuspend(Res.string.new_node_seen, next.user.short_name),
|
||||
message = next.user.long_name,
|
||||
category = Notification.Category.NodeEvent,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
next
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package org.meshtastic.core.data.manager
|
|||
import co.touchlab.kermit.Logger
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.TimeoutCancellationException
|
||||
import kotlinx.coroutines.delay
|
||||
|
|
@ -30,6 +29,7 @@ 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.ioDispatcher
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
|
|
@ -67,7 +67,7 @@ class PacketHandlerImpl(
|
|||
}
|
||||
|
||||
private var queueJob: Job? = null
|
||||
private var scope: CoroutineScope = CoroutineScope(Dispatchers.IO)
|
||||
private var scope: CoroutineScope = CoroutineScope(ioDispatcher)
|
||||
|
||||
private val queueMutex = Mutex()
|
||||
private val queuedPackets = mutableListOf<MeshPacket>()
|
||||
|
|
|
|||
|
|
@ -18,11 +18,11 @@ package org.meshtastic.core.data.manager
|
|||
|
||||
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.NumberFormatter
|
||||
import org.meshtastic.core.common.util.handledLaunch
|
||||
import org.meshtastic.core.common.util.ioDispatcher
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.model.Node
|
||||
import org.meshtastic.core.model.fullRouteDiscovery
|
||||
|
|
@ -44,7 +44,7 @@ class TracerouteHandlerImpl(
|
|||
private val nodeRepository: NodeRepository,
|
||||
private val commandSender: CommandSender,
|
||||
) : TracerouteHandler {
|
||||
private var scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
private var scope: CoroutineScope = CoroutineScope(ioDispatcher + SupervisorJob())
|
||||
|
||||
override fun start(scope: CoroutineScope) {
|
||||
this.scope = scope
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue