Show current block number in Import Account screen.
- Updated NodeStatus component to show the current block count if connected to the Dero node, or a 'Not connected' text otherwise. - Updated ImportAccountScreenModel to extend from StateScreenModel with a State data class that contains the blockCount for now. This State is observed by ImportAccountScreen which automatically adjusts to the latest State and shows the proper UI.
This commit is contained in:
parent
8189b590d3
commit
26436eb687
4 changed files with 60 additions and 14 deletions
|
@ -7,8 +7,13 @@ import org.jetbrains.compose.ui.tooling.preview.Preview
|
|||
import ui.theme.KeeTheme
|
||||
|
||||
@Composable
|
||||
fun NodeStatus() {
|
||||
Text("Connected to X.X.X.X", color = MaterialTheme.colorScheme.onBackground)
|
||||
fun NodeStatus(blockCount: Int? = null) {
|
||||
val text = if (blockCount == null) {
|
||||
"Not connected"
|
||||
} else {
|
||||
"Block #: $blockCount"
|
||||
}
|
||||
Text(text, color = MaterialTheme.colorScheme.onBackground)
|
||||
}
|
||||
|
||||
@Preview
|
||||
|
|
|
@ -27,13 +27,15 @@ class ImportAccountScreen : Screen {
|
|||
override fun Content() = KeeTheme {
|
||||
val screenModel = rememberScreenModel { ImportAccountScreenModel() }
|
||||
|
||||
ImportAccountScreenContent()
|
||||
val state by screenModel.state.collectAsState()
|
||||
|
||||
ImportAccountScreenContent(state)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalResourceApi::class)
|
||||
@Composable
|
||||
private fun ImportAccountScreenContent() {
|
||||
private fun ImportAccountScreenContent(state: ImportAccountScreenModel.State) {
|
||||
val navigator = LocalNavigator.current
|
||||
|
||||
Scaffold(
|
||||
|
@ -79,7 +81,7 @@ private fun ImportAccountScreenContent() {
|
|||
Text("Import Account")
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
NodeStatus()
|
||||
NodeStatus(state.blockCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -87,11 +89,11 @@ private fun ImportAccountScreenContent() {
|
|||
@Preview
|
||||
@Composable
|
||||
private fun ImportAccountScreenContentLightPreview() = KeeTheme(useDarkTheme = false) {
|
||||
ImportAccountScreenContent()
|
||||
ImportAccountScreenContent(ImportAccountScreenModel.State())
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun ImportAccountScreenContentDarkPreview() = KeeTheme(useDarkTheme = true) {
|
||||
ImportAccountScreenContent()
|
||||
ImportAccountScreenContent(ImportAccountScreenModel.State())
|
||||
}
|
||||
|
|
|
@ -1,19 +1,35 @@
|
|||
package net.agorise.kee.ui.screen.importaccount
|
||||
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.IO
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import net.agorise.shared.stargate.StargateBridge
|
||||
|
||||
class ImportAccountScreenModel : ScreenModel {
|
||||
class ImportAccountScreenModel : StateScreenModel<ImportAccountScreenModel.State>(State()) {
|
||||
|
||||
data class State(
|
||||
val blockCount: Int? = null,
|
||||
)
|
||||
|
||||
private val stargateBridge = StargateBridge()
|
||||
|
||||
init {
|
||||
screenModelScope.launch(Dispatchers.IO) {
|
||||
stargateBridge.start()
|
||||
}
|
||||
|
||||
listenForBlockCount()
|
||||
}
|
||||
|
||||
private fun listenForBlockCount() {
|
||||
stargateBridge.blockCountChannel.receiveAsFlow().onEach { blockCount ->
|
||||
mutableState.value = state.value.copy(blockCount = blockCount)
|
||||
}.launchIn(screenModelScope)
|
||||
}
|
||||
|
||||
override fun onDispose() {
|
||||
|
|
|
@ -8,6 +8,7 @@ import io.ktor.client.plugins.websocket.webSocket
|
|||
import io.ktor.websocket.Frame
|
||||
import io.ktor.websocket.readText
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.Channel.Factory.CONFLATED
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
|
@ -18,11 +19,22 @@ import kotlinx.coroutines.flow.receiveAsFlow
|
|||
class StargateBridge {
|
||||
private val foundationNode = DeroNode(host = "node.derofoundation.org", port = 11012, path = "/ws")
|
||||
|
||||
/**
|
||||
* Configure http client to use WebSockets
|
||||
*/
|
||||
private val client: HttpClient = HttpClient(CIO) { install(WebSockets) }
|
||||
|
||||
private val rendezvousChannel = Channel<Boolean>()
|
||||
/**
|
||||
* Internal channel that listens for block broadcasts and is used to request the block count.
|
||||
*/
|
||||
private val blockBroadcastChannel = Channel<Boolean>(CONFLATED)
|
||||
|
||||
private val blockCountRequest = "{ \"jsonrpc\": \"2.0\", \"id\": \"1\", \"method\": \"DERO.GetBlockCount\" }"
|
||||
private var currentRequestId: Int = 0
|
||||
|
||||
/**
|
||||
* Public channel that broadcasts the block count.
|
||||
*/
|
||||
val blockCountChannel = Channel<Int>(CONFLATED)
|
||||
|
||||
suspend fun start() {
|
||||
val node = foundationNode
|
||||
|
@ -42,16 +54,27 @@ class StargateBridge {
|
|||
val text = textFrame.readText()
|
||||
println(text)
|
||||
if (text.contains("\"method\":\"Block\"")) {
|
||||
rendezvousChannel.send(true)
|
||||
blockBroadcastChannel.send(true)
|
||||
} else if (text.contains("\"count\":")) {
|
||||
// Rudimentary parsing to obtain block count. Implement proper serialization
|
||||
// using kotlinx.serialization
|
||||
val blockCount = text.substringAfter("\"count\":").substringBefore(",").toInt()
|
||||
blockCountChannel.send(blockCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun DefaultClientWebSocketSession.writeMessages() {
|
||||
rendezvousChannel.receiveAsFlow().onEach {
|
||||
println("Prepared to send...")
|
||||
blockBroadcastChannel.receiveAsFlow().onEach {
|
||||
val blockCountRequest = getBlockCountRequest()
|
||||
println("Requesting: $blockCountRequest")
|
||||
outgoing.send(Frame.Text(blockCountRequest))
|
||||
}.launchIn(this)
|
||||
}
|
||||
|
||||
// Temporary request to get block count
|
||||
private fun getBlockCountRequest() = "{ \"jsonrpc\": \"2.0\", \"id\": \"${getNextRequestId()}\", \"method\": \"DERO.GetBlockCount\" }"
|
||||
|
||||
private fun getNextRequestId() = ++currentRequestId
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue