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 23b7437940a4806f92a4ea713ffdc54df1f67856
parent 71f8d234eefe9aa930f8c9207d95a652ee0042a7
Author: MTRNord <mtrnord1@gmail.com>
Date:   Tue, 26 Sep 2023 21:25:14 +0200

Feat: Partially implement password login

Diffstat:
A.idea/uiDesigner.xml | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M.idea/workspace.xml | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
D.run/browser.run.xml | 24------------------------
Mbuild.gradle.kts | 5-----
Mgradle/libs.versions.toml | 2+-
Msettings.gradle.kts | 6+++++-
Asrc/jsMain/kotlin/Main.kt | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/jsMain/kotlin/pages/Login.kt | 174+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/jsMain/resources/index.html | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/main/kotlin/main.kt | 92-------------------------------------------------------------------------------
Dsrc/main/kotlin/pages/Login.kt | 6------
Dsrc/main/resources/index.html | 12------------
12 files changed, 526 insertions(+), 147 deletions(-)

diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="Palette2"> + <group name="Swing"> + <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" /> + </item> + <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" /> + </item> + <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" /> + </item> + <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true"> + <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" /> + </item> + <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" /> + <initial-values> + <property name="text" value="Button" /> + </initial-values> + </item> + <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" /> + <initial-values> + <property name="text" value="RadioButton" /> + </initial-values> + </item> + <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" /> + <initial-values> + <property name="text" value="CheckBox" /> + </initial-values> + </item> + <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" /> + <initial-values> + <property name="text" value="Label" /> + </initial-values> + </item> + <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1"> + <preferred-size width="150" height="-1" /> + </default-constraints> + </item> + <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1"> + <preferred-size width="150" height="-1" /> + </default-constraints> + </item> + <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1"> + <preferred-size width="150" height="-1" /> + </default-constraints> + </item> + <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" /> + </item> + <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3"> + <preferred-size width="200" height="200" /> + </default-constraints> + </item> + <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3"> + <preferred-size width="200" height="200" /> + </default-constraints> + </item> + <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" /> + </item> + <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" /> + </item> + <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" /> + </item> + <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" /> + </item> + <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1"> + <preferred-size width="-1" height="20" /> + </default-constraints> + </item> + <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" /> + </item> + <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" /> + </item> + </group> + </component> +</project> +\ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml @@ -4,10 +4,28 @@ <option name="autoReloadType" value="SELECTIVE" /> </component> <component name="ChangeListManager"> - <list default="true" id="fc5af14b-7484-46dc-b4cb-0394f9dc3dda" name="Changes" comment="Feat: Add very early and basic state handling"> + <list default="true" id="fc5af14b-7484-46dc-b4cb-0394f9dc3dda" name="Changes" comment="Cleanup"> + <change afterPath="$PROJECT_DIR$/.idea/uiDesigner.xml" afterDir="false" /> + <change afterPath="$PROJECT_DIR$/src/jsMain/kotlin/pages/Login.kt" afterDir="false" /> + <change afterPath="$PROJECT_DIR$/src/jsMain/resources/index.html" afterDir="false" /> + <change afterPath="/var/home/marcel/IdeaProjects/MagicMatrix/.idea/uiDesigner.xml" afterDir="false" /> + <change afterPath="/var/home/marcel/IdeaProjects/MagicMatrix/src/jsMain/kotlin/pages/Login.kt" afterDir="false" /> + <change afterPath="/var/home/marcel/IdeaProjects/MagicMatrix/src/jsMain/resources/index.html" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> + <change beforePath="$PROJECT_DIR$/.run/browser.run.xml" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/build.gradle.kts" beforeDir="false" afterPath="$PROJECT_DIR$/build.gradle.kts" afterDir="false" /> + <change beforePath="$PROJECT_DIR$/settings.gradle.kts" beforeDir="false" afterPath="$PROJECT_DIR$/settings.gradle.kts" afterDir="false" /> + <change beforePath="$PROJECT_DIR$/src/main/kotlin/main.kt" beforeDir="false" afterPath="$PROJECT_DIR$/src/jsMain/kotlin/Main.kt" afterDir="false" /> + <change beforePath="$PROJECT_DIR$/src/main/kotlin/pages/Login.kt" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/main/resources/index.html" beforeDir="false" /> <change beforePath="/var/home/marcel/IdeaProjects/MagicMatrix/.idea/workspace.xml" beforeDir="false" afterPath="/var/home/marcel/IdeaProjects/MagicMatrix/.idea/workspace.xml" afterDir="false" /> - <change beforePath="/var/home/marcel/IdeaProjects/MagicMatrix/src/main/kotlin/main.kt" beforeDir="false" afterPath="/var/home/marcel/IdeaProjects/MagicMatrix/src/main/kotlin/main.kt" afterDir="false" /> + <change beforePath="/var/home/marcel/IdeaProjects/MagicMatrix/.run/browser.run.xml" beforeDir="false" /> + <change beforePath="/var/home/marcel/IdeaProjects/MagicMatrix/build.gradle.kts" beforeDir="false" afterPath="/var/home/marcel/IdeaProjects/MagicMatrix/build.gradle.kts" afterDir="false" /> + <change beforePath="/var/home/marcel/IdeaProjects/MagicMatrix/gradle/libs.versions.toml" beforeDir="false" afterPath="/var/home/marcel/IdeaProjects/MagicMatrix/gradle/libs.versions.toml" afterDir="false" /> + <change beforePath="/var/home/marcel/IdeaProjects/MagicMatrix/settings.gradle.kts" beforeDir="false" afterPath="/var/home/marcel/IdeaProjects/MagicMatrix/settings.gradle.kts" afterDir="false" /> + <change beforePath="/var/home/marcel/IdeaProjects/MagicMatrix/src/main/kotlin/main.kt" beforeDir="false" afterPath="/var/home/marcel/IdeaProjects/MagicMatrix/src/jsMain/kotlin/Main.kt" afterDir="false" /> + <change beforePath="/var/home/marcel/IdeaProjects/MagicMatrix/src/main/kotlin/pages/Login.kt" beforeDir="false" /> + <change beforePath="/var/home/marcel/IdeaProjects/MagicMatrix/src/main/resources/index.html" beforeDir="false" /> </list> <option name="SHOW_DIALOG" value="false" /> <option name="HIGHLIGHT_CONFLICTS" value="true" /> @@ -86,7 +104,29 @@ "vue.rearranger.settings.migration": "true" } }]]></component> - <component name="RunManager" selected="Gradle.browser"> + <component name="RunManager" selected="Gradle.MagicMatrix::var:home:marcel:IdeaProjects:MagicMatrix [jsBrowserRun]"> + <configuration name="MagicMatrix::var:home:marcel:IdeaProjects:MagicMatrix [jsBrowserRun]" type="GradleRunConfiguration" factoryName="Gradle" temporary="true"> + <ExternalSystemSettings> + <option name="executionName" /> + <option name="externalProjectPath" value="/var/home/marcel/IdeaProjects/MagicMatrix" /> + <option name="externalSystemIdString" value="GRADLE" /> + <option name="scriptParameters" value="--continuous" /> + <option name="taskDescriptions"> + <list /> + </option> + <option name="taskNames"> + <list> + <option value="jsBrowserRun" /> + </list> + </option> + <option name="vmOptions" /> + </ExternalSystemSettings> + <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess> + <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess> + <DebugAllEnabled>false</DebugAllEnabled> + <RunAsTest>false</RunAsTest> + <method v="2" /> + </configuration> <configuration name="MagicMatrix::var:home:marcel:IdeaProjects:MagicMatrix [kotlinUpgradeYarnLock]" type="GradleRunConfiguration" factoryName="Gradle" temporary="true"> <ExternalSystemSettings> <option name="executionName" /> @@ -111,6 +151,7 @@ </configuration> <recent_temporary> <list> + <item itemvalue="Gradle.MagicMatrix::var:home:marcel:IdeaProjects:MagicMatrix [jsBrowserRun]" /> <item itemvalue="Gradle.MagicMatrix::var:home:marcel:IdeaProjects:MagicMatrix [kotlinUpgradeYarnLock]" /> </list> </recent_temporary> @@ -123,7 +164,7 @@ <option name="number" value="Default" /> <option name="presentableId" value="Default" /> <updated>1695740188018</updated> - <workItem from="1695740189223" duration="5352000" /> + <workItem from="1695740189223" duration="13483000" /> </task> <task id="LOCAL-00001" summary="Fix: Fix typo in workflow file"> <option name="closed" value="true" /> @@ -165,7 +206,15 @@ <option name="project" value="LOCAL" /> <updated>1695745278124</updated> </task> - <option name="localTasksCounter" value="6" /> + <task id="LOCAL-00006" summary="Cleanup"> + <option name="closed" value="true" /> + <created>1695746206343</created> + <option name="number" value="00006" /> + <option name="presentableId" value="LOCAL-00006" /> + <option name="project" value="LOCAL" /> + <updated>1695746206343</updated> + </task> + <option name="localTasksCounter" value="7" /> <servers /> </component> <component name="TypeScriptGeneratedFilesManager"> @@ -190,6 +239,7 @@ <MESSAGE value="Feat: Add silk and make sure the right folder is packaged" /> <MESSAGE value="Fix: use correct github action" /> <MESSAGE value="Feat: Add very early and basic state handling" /> - <option name="LAST_COMMIT_MESSAGE" value="Feat: Add very early and basic state handling" /> + <MESSAGE value="Cleanup" /> + <option name="LAST_COMMIT_MESSAGE" value="Cleanup" /> </component> </project> \ No newline at end of file diff --git a/.run/browser.run.xml b/.run/browser.run.xml @@ -1,23 +0,0 @@ -<component name="ProjectRunConfigurationManager"> - <configuration default="false" name="browser" type="GradleRunConfiguration" factoryName="Gradle"> - <ExternalSystemSettings> - <option name="executionName" /> - <option name="externalProjectPath" value="$PROJECT_DIR$" /> - <option name="externalSystemIdString" value="GRADLE" /> - <option name="scriptParameters" value="" /> - <option name="taskDescriptions"> - <list /> - </option> - <option name="taskNames"> - <list> - <option value=":jsBrowserRun" /> - </list> - </option> - <option name="vmOptions" /> - </ExternalSystemSettings> - <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess> - <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess> - <DebugAllEnabled>false</DebugAllEnabled> - <method v="2" /> - </configuration> -</component> -\ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts @@ -1,5 +1,3 @@ -import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension - plugins { alias(libs.plugins.kotlin.multiplatform) alias(libs.plugins.jetbrains.compose) @@ -20,9 +18,6 @@ kotlin { } sourceSets { val jsMain by getting { - kotlin.srcDir("src/main/kotlin") - resources.srcDir("src/main/resources") - dependencies { implementation(compose.html.core) implementation(compose.runtime) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -jetbrains-compose = "1.5.1" +jetbrains-compose = "1.5.2" kotlin = "1.9.10" trixnity = "1.0.5" koin = "1.1.0" diff --git a/settings.gradle.kts b/settings.gradle.kts @@ -2,9 +2,13 @@ pluginManagement { repositories { gradlePluginPortal() maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") - maven("https://us-central1-maven.pkg.dev/varabyte-repos/public") } + + plugins { + kotlin("multiplatform").version("1.9.10") + id("org.jetbrains.compose").version("1.5.2") + } } rootProject.name = "MagicMatrix" \ No newline at end of file diff --git a/src/jsMain/kotlin/Main.kt b/src/jsMain/kotlin/Main.kt @@ -0,0 +1,112 @@ +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import com.arkivanov.decompose.DefaultComponentContext +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 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 +import org.jetbrains.compose.web.dom.Div +import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.renderComposable +import org.koin.dsl.koinApplication +import org.w3c.dom.HTMLElement + +fun main() { + // Init Kobweb + initSilk() + + val koinApplication = koinApplication { + modules(trixnityMessengerModule()) + } + val matrixClientService = DefaultMatrixClientService(koinApplication.koin) + val componentContext = DefaultComponentContext(LifecycleRegistry()) + + val rootViewModel = RootViewModelImpl( + componentContext = componentContext, + matrixClientService = matrixClientService, + koinApplication = koinApplication, + initialSyncOnceIsFinished = { finished -> + + } + ) + renderComposable(rootElementId = "root") { + // Further Init for kobweb + val root = remember { document.getElementById("root") as HTMLElement } + root.setSilkVariables() + Style(SilkStyleSheet) + + Base(rootViewModel) + } + +} + +@OptIn(ExperimentalCoroutinesApi::class) +@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) { + is RootRouter.RootWrapper.None -> { + None() + } + + is RootRouter.RootWrapper.MatrixClientInitialization -> { + Init((routerState as RootRouter.RootWrapper.MatrixClientInitialization).matrixClientInitializationViewModel) + } // show initialization of the MatrixClient (aka loading screen) + + is RootRouter.RootWrapper.Main -> { + Main((routerState as RootRouter.RootWrapper.Main).mainViewModel) + } + + is RootRouter.RootWrapper.AddMatrixAccount -> { + Login((routerState as RootRouter.RootWrapper.AddMatrixAccount).addMatrixAccountViewModel) + } + + is RootRouter.RootWrapper.PasswordLogin -> { + PasswordLogin((routerState as RootRouter.RootWrapper.PasswordLogin).passwordLoginViewModel) + } + + else -> {} // add more cases + } +} + +@Composable +fun Main(mainViewModel: MainViewModel) { + Div({ style { padding(25.px) } }) { + Text("Main") + } +} + +@Composable +fun Init(matrixClientInitializationViewModel: MatrixClientInitializationViewModel) { + val initState by matrixClientInitializationViewModel.currentState.collectAsState(); + Div({ style { padding(25.px) } }) { + Text(initState) + } +} + +@Composable +fun None() { + Div({ style { padding(25.px) } }) { + Text("Initializing matrix") + } +} +\ No newline at end of file diff --git a/src/jsMain/kotlin/pages/Login.kt b/src/jsMain/kotlin/pages/Login.kt @@ -0,0 +1,173 @@ +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import com.varabyte.kobweb.compose.foundation.layout.Row +import com.varabyte.kobweb.compose.ui.Modifier +import com.varabyte.kobweb.compose.ui.modifiers.* +import com.varabyte.kobweb.silk.components.forms.InputGroup +import com.varabyte.kobweb.silk.components.forms.TextInput +import de.connect2x.trixnity.messenger.viewmodel.connecting.AddMatrixAccountMethod +import de.connect2x.trixnity.messenger.viewmodel.connecting.AddMatrixAccountViewModel +import de.connect2x.trixnity.messenger.viewmodel.connecting.PasswordLoginViewModel +import kotlinx.coroutines.flow.update +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.Button +import org.jetbrains.compose.web.dom.Div +import org.jetbrains.compose.web.dom.Text + + +@Composable +fun PasswordLogin(passwordLoginViewModel: PasswordLoginViewModel) { + val username by passwordLoginViewModel.username.collectAsState(); + val password by passwordLoginViewModel.password.collectAsState(); + Row( + Modifier + .display(DisplayStyle.Flex) + .fillMaxWidth() + .fillMaxHeight() + .justifyContent(JustifyContent.Center) + .alignItems(AlignItems.Center) + ) { + Div({ + style { + display(DisplayStyle.Flex) + flexDirection(FlexDirection.Column) + alignItems(AlignItems.FlexStart) + } + }) { + InputGroup(Modifier.display(DisplayStyle.Flex)) { + LeftAddon( + Modifier.display(DisplayStyle.Flex).alignItems(AlignItems.Center) + ) { Text("Username:") } + TextInput( + username, + password = false, + onTextChanged = { newText -> + passwordLoginViewModel.username.update { + newText + } + passwordLoginViewModel.accountName.update { + newText + } + }) + } + InputGroup(Modifier.display(DisplayStyle.Flex)) { + LeftAddon( + Modifier.display(DisplayStyle.Flex).alignItems(AlignItems.Center) + ) { Text("Password:") } + TextInput( + password, + password = true, + onTextChanged = { newText -> + passwordLoginViewModel.password.update { + newText + } + }) + } + Button(attrs = { + onClick { + if (username.isNotBlank() && password.isNotBlank()) { + passwordLoginViewModel.tryLogin() + } + } + }) { + Text("Login") + } + } + } +} + +@Composable +fun Login(addMatrixAccountViewModel: AddMatrixAccountViewModel) { + val isFirstMatrixClient by addMatrixAccountViewModel.isFirstMatrixClient.collectAsState(); + val serverUrl by addMatrixAccountViewModel.serverUrl.collectAsState(); + val serverDiscoveryState by addMatrixAccountViewModel.serverDiscoveryState.collectAsState(); + + + if (isFirstMatrixClient == true) { + Row( + Modifier + .display(DisplayStyle.Flex) + .fillMaxWidth() + .fillMaxHeight() + .justifyContent(JustifyContent.Center) + .alignItems(AlignItems.Center) + ) { + Div({ + style { + display(DisplayStyle.Flex) + flexDirection(FlexDirection.Column) + alignItems(AlignItems.FlexStart) + } + }) { + InputGroup(Modifier.display(DisplayStyle.Flex)) { + LeftAddon(Modifier.display(DisplayStyle.Flex).alignItems(AlignItems.Center)) { Text("Homeserver:") } + TextInput( + serverUrl, + password = false, + onTextChanged = { newText -> + addMatrixAccountViewModel.serverUrl.update { + newText + } + }) + } + when (serverDiscoveryState) { + is AddMatrixAccountViewModel.ServerDiscoveryState.Loading -> Div({ + classes("lds-dual-ring") + }) + + is AddMatrixAccountViewModel.ServerDiscoveryState.Failure -> { + Div({ style { color(Color("red")) } }) { Text((serverDiscoveryState as AddMatrixAccountViewModel.ServerDiscoveryState.Failure).message) } + } + + is AddMatrixAccountViewModel.ServerDiscoveryState.Success -> { + val availableMethods = + (serverDiscoveryState as AddMatrixAccountViewModel.ServerDiscoveryState.Success).addMatrixAccountMethods + + Div({ + style { + display(DisplayStyle.Flex) + flexDirection(FlexDirection.Row) + alignItems(AlignItems.Center) + justifyContent(JustifyContent.Center) + } + }) { + // FIXME: Make this a tab view instead to change between register and login + availableMethods.map { loginMethod -> + if (loginMethod is AddMatrixAccountMethod.Password) { + Button(attrs = { + onClick { + addMatrixAccountViewModel.selectAddMatrixAccountMethod(loginMethod) + } + }) { + Text("Login") + } + } + if (loginMethod is AddMatrixAccountMethod.Register) { + Button(attrs = { + onClick { + addMatrixAccountViewModel.selectAddMatrixAccountMethod(loginMethod) + } + }) { + Text("Register") + } + } + } + + } + + } + + AddMatrixAccountViewModel.ServerDiscoveryState.None -> {} + } + } + } + // Render the login + // 3. Use selectAddMatrixAccountMethod + } else { + // Render all accounts + add more + Div({ style { padding(25.px) } }) { + Text("not isFirstMatrixClient") + } + } +} +\ No newline at end of file diff --git a/src/jsMain/resources/index.html b/src/jsMain/resources/index.html @@ -0,0 +1,51 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>Magic Matrix</title> + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> + <style> + html { + height: 100%; + margin: 0; + } + + #root, body { + height: 100%; + margin: 0; + } + + .lds-dual-ring { + display: inline-block; + width: 80px; + height: 80px; + } + + .lds-dual-ring:after { + content: " "; + display: block; + width: 64px; + height: 64px; + margin: 8px; + border-radius: 50%; + border: 6px solid #000; + border-color: #000 transparent #000 transparent; + animation: lds-dual-ring 1.2s linear infinite; + } + + @keyframes lds-dual-ring { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } + } + + </style> +</head> +<body> +<div id="root"></div> +<script src="MagicMatrix.js"></script> +</body> +</html> +\ No newline at end of file diff --git a/src/main/kotlin/main.kt b/src/main/kotlin/main.kt @@ -1,91 +0,0 @@ -import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import com.arkivanov.decompose.DefaultComponentContext -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.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 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 -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.Text -import org.jetbrains.compose.web.renderComposable -import org.koin.dsl.koinApplication -import org.w3c.dom.HTMLElement - -fun main() { - // Init Kobweb - initSilk() - - val koinApplication = koinApplication { - modules(trixnityMessengerModule()) - } - val matrixClientService = DefaultMatrixClientService(koinApplication.koin) - val componentContext = DefaultComponentContext(LifecycleRegistry()) - - val rootViewModel = RootViewModelImpl( - componentContext = componentContext, - matrixClientService = matrixClientService, - koinApplication = koinApplication, - initialSyncOnceIsFinished = { finished -> - - } - ) - renderComposable(rootElementId = "root") { - // Further Init for kobweb - val root = remember { document.getElementById("root") as HTMLElement } - root.setSilkVariables() - Style(SilkStyleSheet) - - Base(rootViewModel) - } - -} - -@OptIn(ExperimentalCoroutinesApi::class) -@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) { - is RootRouter.RootWrapper.None -> { - None() - } - - is RootRouter.RootWrapper.MatrixClientInitialization -> { - Init((routerState as RootRouter.RootWrapper.MatrixClientInitialization).matrixClientInitializationViewModel) - } // show initialization of the MatrixClient (aka loading screen) - else -> {} // add more cases - } -} - -@Composable -fun Init(matrixClientInitializationViewModel: MatrixClientInitializationViewModel) { - val initState by matrixClientInitializationViewModel.currentState.collectAsState(); - Div({ style { padding(25.px) } }) { - Text(initState) - } -} - -@Composable -fun None() { - Div({ style { padding(25.px) } }) { - Text("Initializing matrix") - } -} -\ No newline at end of file diff --git a/src/main/kotlin/pages/Login.kt b/src/main/kotlin/pages/Login.kt @@ -1,5 +0,0 @@ -import androidx.compose.runtime.Composable -import de.connect2x.trixnity.messenger.viewmodel.RootViewModel - -@Composable -fun Login() {} -\ No newline at end of file diff --git a/src/main/resources/index.html b/src/main/resources/index.html @@ -1,11 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="UTF-8"> - <title>Magic Matrix</title> -</head> -<body> -<div id="root"></div> -<script src="MagicMatrix.js"></script> -</body> -</html> -\ No newline at end of file