trixnity-messenger-playground

A playground for trixnity-messenger based on jetbrains compose-html
git clone git://archive.git.mtrnord.blog/MTRNord/trixnity-messenger-playground.git
Log | Files | Refs | README

commit 54263ce89a079a71737966602ed021fa2fdd5e94
parent e1e087aeb6aa9a0a73f62193b67a28dfec25e1a0
Author: MTRNord <mtrnord1@gmail.com>
Date:   Wed, 27 Sep 2023 13:37:45 +0200

Feat: Implement very basic Roomlist

Diffstat:
Mbuild.gradle.kts | 2++
Mgradle/libs.versions.toml | 3+++
Msrc/jsMain/kotlin/Main.kt | 26++++++++------------------
Asrc/jsMain/kotlin/pages/Main.kt | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 99 insertions(+), 18 deletions(-)

diff --git a/build.gradle.kts b/build.gradle.kts @@ -24,6 +24,8 @@ kotlin { implementation(compose.runtime) implementation(libs.trixnity.messenger) implementation(libs.kobweb.silk) + implementation(libs.decompose) + implementation(libs.decompose.extensions.compose.jetbrains) } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml @@ -4,12 +4,15 @@ kotlin = "1.9.10" trixnity = "1.0.6" koin = "1.1.0" kobweb = "0.14.0" +decompose = "2.1.0-compose-experimental" [libraries] trixnity-messenger = { module = "de.connect2x:trixnity-messenger", version.ref = "trixnity" } koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" } koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koin" } kobweb-silk = { module = "com.varabyte.kobweb:kobweb-silk", version.ref = "kobweb" } +decompose-extensions-compose-jetbrains = { module = "com.arkivanov.decompose:extensions-compose-jetbrains", version.ref = "decompose" } +decompose = { module = "com.arkivanov.decompose:decompose", version.ref = "decompose" } [plugins] jetbrains-compose = { id = "org.jetbrains.compose", version.ref = "jetbrains-compose" } diff --git a/src/jsMain/kotlin/Main.kt b/src/jsMain/kotlin/Main.kt @@ -3,23 +3,21 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import com.arkivanov.decompose.DefaultComponentContext +import com.arkivanov.decompose.extensions.compose.jetbrains.subscribeAsState import com.arkivanov.essenty.lifecycle.LifecycleRegistry import com.varabyte.kobweb.silk.SilkStyleSheet import com.varabyte.kobweb.silk.init.initSilk import com.varabyte.kobweb.silk.init.setSilkVariables import de.connect2x.trixnity.messenger.DefaultMatrixClientService import de.connect2x.trixnity.messenger.trixnityMessengerModule -import de.connect2x.trixnity.messenger.viewmodel.MainViewModel import de.connect2x.trixnity.messenger.viewmodel.RootRouter import de.connect2x.trixnity.messenger.viewmodel.RootViewModel import de.connect2x.trixnity.messenger.viewmodel.RootViewModelImpl import de.connect2x.trixnity.messenger.viewmodel.connecting.MatrixClientInitializationViewModel -import de.connect2x.trixnity.messenger.viewmodel.util.toFlow import io.github.oshai.kotlinlogging.KotlinLoggingConfiguration import io.github.oshai.kotlinlogging.Level import kotlinx.browser.document import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.mapLatest import org.jetbrains.compose.web.css.Style import org.jetbrains.compose.web.css.padding import org.jetbrains.compose.web.css.px @@ -28,6 +26,7 @@ import org.jetbrains.compose.web.dom.Text import org.jetbrains.compose.web.renderComposable import org.koin.dsl.koinApplication import org.w3c.dom.HTMLElement +import pages.Main fun main() { KotlinLoggingConfiguration.LOG_LEVEL = Level.DEBUG @@ -63,41 +62,32 @@ fun main() { @Composable fun Base(rootViewModel: RootViewModel) { // Trixnity messenger router - // FIXME: This seems to loose type info? - val routerState by rootViewModel.rootStack.toFlow() - .mapLatest { it.active.instance }.collectAsState(RootRouter.RootWrapper.None) - - when (routerState) { + val routerState by rootViewModel.rootStack.subscribeAsState() + when (val route = routerState.active.instance) { is RootRouter.RootWrapper.None -> { None() } is RootRouter.RootWrapper.MatrixClientInitialization -> { - Init((routerState as RootRouter.RootWrapper.MatrixClientInitialization).matrixClientInitializationViewModel) + Init(route.matrixClientInitializationViewModel) } // show initialization of the MatrixClient (aka loading screen) is RootRouter.RootWrapper.Main -> { - Main((routerState as RootRouter.RootWrapper.Main).mainViewModel) + Main(route.mainViewModel) } is RootRouter.RootWrapper.AddMatrixAccount -> { - Login((routerState as RootRouter.RootWrapper.AddMatrixAccount).addMatrixAccountViewModel) + Login(route.addMatrixAccountViewModel) } is RootRouter.RootWrapper.PasswordLogin -> { - PasswordLogin((routerState as RootRouter.RootWrapper.PasswordLogin).passwordLoginViewModel) + PasswordLogin(route.passwordLoginViewModel) } else -> {} // add more cases } } -@Composable -fun Main(mainViewModel: MainViewModel) { - Div({ style { padding(25.px) } }) { - Text("Main") - } -} @Composable fun Init(matrixClientInitializationViewModel: MatrixClientInitializationViewModel) { diff --git a/src/jsMain/kotlin/pages/Main.kt b/src/jsMain/kotlin/pages/Main.kt @@ -0,0 +1,86 @@ +package pages + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import com.arkivanov.decompose.extensions.compose.jetbrains.subscribeAsState +import com.varabyte.kobweb.compose.css.borderRight +import de.connect2x.trixnity.messenger.viewmodel.MainViewModel +import de.connect2x.trixnity.messenger.viewmodel.roomlist.RoomListElementViewModel +import de.connect2x.trixnity.messenger.viewmodel.roomlist.RoomListRouter +import de.connect2x.trixnity.messenger.viewmodel.roomlist.RoomListViewModel +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.Div +import org.jetbrains.compose.web.dom.Text + + +@Composable +fun Main(mainViewModel: MainViewModel) { + mainViewModel.start() + val roomListData by mainViewModel.roomListRouterStack.subscribeAsState() + val roomList = roomListData.active.instance + + + Div({ + style { + display(DisplayStyle.Flex) + flexDirection(FlexDirection.Row) + gap(2.px) + height(100.percent) + } + }) { + Div({ + style { + height(100.percent) + width(25.em) + display(DisplayStyle.Flex) + flexDirection(FlexDirection.Column) + gap(2.px) + borderRight(width = 1.px, style = LineStyle.Solid, color = Color("black")) + padding(4.px) + } + }) { + if (roomList is RoomListRouter.RoomListWrapper.List) { + RoomList(roomList.roomListViewModel) + } + } + Div({ + style { + display(DisplayStyle.Flex) + flexDirection(FlexDirection.Column) + gap(2.px) + height(100.percent) + width(100.percent) + padding(4.px) + } + }) { + Text("Room") + } + } +} + +@Composable +fun RoomList(roomListViewModel: RoomListViewModel) { + val initialSyncFinished by roomListViewModel.initialSyncFinished.collectAsState(); + val selectedRoomId by roomListViewModel.selectedRoomId.collectAsState(); + val rooms by roomListViewModel.sortedRoomListElementViewModels.collectAsState(); + + if (!initialSyncFinished) { + Div({ + classes("lds-dual-ring") + }) + } else { + rooms.forEach { room -> + Room(room.second, room.first == selectedRoomId) + } + } +} + +@Composable +fun Room(roomViewModel: RoomListElementViewModel, selected: Boolean) { + val roomName by roomViewModel.roomName.collectAsState(); + val roomId = roomViewModel.roomId + Div { + Text(roomName ?: roomId.full) + } +}