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
|
import ui.theme.KeeTheme
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NodeStatus() {
|
fun NodeStatus(blockCount: Int? = null) {
|
||||||
Text("Connected to X.X.X.X", color = MaterialTheme.colorScheme.onBackground)
|
val text = if (blockCount == null) {
|
||||||
|
"Not connected"
|
||||||
|
} else {
|
||||||
|
"Block #: $blockCount"
|
||||||
|
}
|
||||||
|
Text(text, color = MaterialTheme.colorScheme.onBackground)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
|
|
|
@ -27,13 +27,15 @@ class ImportAccountScreen : Screen {
|
||||||
override fun Content() = KeeTheme {
|
override fun Content() = KeeTheme {
|
||||||
val screenModel = rememberScreenModel { ImportAccountScreenModel() }
|
val screenModel = rememberScreenModel { ImportAccountScreenModel() }
|
||||||
|
|
||||||
ImportAccountScreenContent()
|
val state by screenModel.state.collectAsState()
|
||||||
|
|
||||||
|
ImportAccountScreenContent(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalResourceApi::class)
|
@OptIn(ExperimentalResourceApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun ImportAccountScreenContent() {
|
private fun ImportAccountScreenContent(state: ImportAccountScreenModel.State) {
|
||||||
val navigator = LocalNavigator.current
|
val navigator = LocalNavigator.current
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
|
@ -79,7 +81,7 @@ private fun ImportAccountScreenContent() {
|
||||||
Text("Import Account")
|
Text("Import Account")
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
NodeStatus()
|
NodeStatus(state.blockCount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,11 +89,11 @@ private fun ImportAccountScreenContent() {
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
private fun ImportAccountScreenContentLightPreview() = KeeTheme(useDarkTheme = false) {
|
private fun ImportAccountScreenContentLightPreview() = KeeTheme(useDarkTheme = false) {
|
||||||
ImportAccountScreenContent()
|
ImportAccountScreenContent(ImportAccountScreenModel.State())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
private fun ImportAccountScreenContentDarkPreview() = KeeTheme(useDarkTheme = true) {
|
private fun ImportAccountScreenContentDarkPreview() = KeeTheme(useDarkTheme = true) {
|
||||||
ImportAccountScreenContent()
|
ImportAccountScreenContent(ImportAccountScreenModel.State())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,35 @@
|
||||||
package net.agorise.kee.ui.screen.importaccount
|
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 cafe.adriel.voyager.core.model.screenModelScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.IO
|
import kotlinx.coroutines.IO
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import net.agorise.shared.stargate.StargateBridge
|
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()
|
private val stargateBridge = StargateBridge()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
screenModelScope.launch(Dispatchers.IO) {
|
screenModelScope.launch(Dispatchers.IO) {
|
||||||
stargateBridge.start()
|
stargateBridge.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listenForBlockCount()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun listenForBlockCount() {
|
||||||
|
stargateBridge.blockCountChannel.receiveAsFlow().onEach { blockCount ->
|
||||||
|
mutableState.value = state.value.copy(blockCount = blockCount)
|
||||||
|
}.launchIn(screenModelScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDispose() {
|
override fun onDispose() {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import io.ktor.client.plugins.websocket.webSocket
|
||||||
import io.ktor.websocket.Frame
|
import io.ktor.websocket.Frame
|
||||||
import io.ktor.websocket.readText
|
import io.ktor.websocket.readText
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
|
import kotlinx.coroutines.channels.Channel.Factory.CONFLATED
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
|
@ -18,11 +19,22 @@ import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
class StargateBridge {
|
class StargateBridge {
|
||||||
private val foundationNode = DeroNode(host = "node.derofoundation.org", port = 11012, path = "/ws")
|
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 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() {
|
suspend fun start() {
|
||||||
val node = foundationNode
|
val node = foundationNode
|
||||||
|
@ -42,16 +54,27 @@ class StargateBridge {
|
||||||
val text = textFrame.readText()
|
val text = textFrame.readText()
|
||||||
println(text)
|
println(text)
|
||||||
if (text.contains("\"method\":\"Block\"")) {
|
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() {
|
private suspend fun DefaultClientWebSocketSession.writeMessages() {
|
||||||
rendezvousChannel.receiveAsFlow().onEach {
|
blockBroadcastChannel.receiveAsFlow().onEach {
|
||||||
println("Prepared to send...")
|
val blockCountRequest = getBlockCountRequest()
|
||||||
|
println("Requesting: $blockCountRequest")
|
||||||
outgoing.send(Frame.Text(blockCountRequest))
|
outgoing.send(Frame.Text(blockCountRequest))
|
||||||
}.launchIn(this)
|
}.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