Introduce mavericks-compose and room list module - WIP
This commit is contained in:
parent
98eeb08772
commit
8ce670995a
18 changed files with 328 additions and 43 deletions
|
|
@ -57,6 +57,7 @@ android {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(":libraries:ui:theme")
|
implementation project(":libraries:ui:theme")
|
||||||
implementation project(":libraries:ui:screens:login")
|
implementation project(":libraries:ui:screens:login")
|
||||||
|
implementation project(":libraries:ui:screens:roomlist")
|
||||||
implementation project(":libraries:sdk:matrix")
|
implementation project(":libraries:sdk:matrix")
|
||||||
|
|
||||||
implementation 'androidx.core:core-ktx:1.9.0'
|
implementation 'androidx.core:core-ktx:1.9.0'
|
||||||
|
|
@ -67,4 +68,6 @@ dependencies {
|
||||||
implementation 'androidx.activity:activity-compose:1.6.0'
|
implementation 'androidx.activity:activity-compose:1.6.0'
|
||||||
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
|
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
|
||||||
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
|
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
|
||||||
|
|
||||||
|
implementation 'com.airbnb.android:mavericks-compose:2.7.0'
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package io.element.android.x
|
package io.element.android.x
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import com.airbnb.mvrx.Mavericks
|
||||||
import io.element.android.x.sdk.matrix.MatrixInstance
|
import io.element.android.x.sdk.matrix.MatrixInstance
|
||||||
|
|
||||||
class ElementXApplication : Application() {
|
class ElementXApplication : Application() {
|
||||||
|
|
@ -8,5 +9,6 @@ class ElementXApplication : Application() {
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
MatrixInstance.init(this)
|
MatrixInstance.init(this)
|
||||||
|
Mavericks.initialize(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,14 +3,30 @@ package io.element.android.x
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import io.element.android.x.ui.screen.login.LoginActivity
|
import io.element.android.x.ui.screen.login.LoginActivity
|
||||||
|
import io.element.android.x.ui.screen.login.RoomListActivity
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
|
private val launcher =
|
||||||
|
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
|
if (it.resultCode == RESULT_OK) {
|
||||||
|
// Launch the room Activity and finish
|
||||||
|
startRoomActivityAndFinish()
|
||||||
|
} else {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
// Just start the LoginActivity for now.
|
// Just start the LoginActivity for now.
|
||||||
// TODO if a session exist, start the room list
|
// TODO if a session exist, start the room list
|
||||||
startActivity(Intent(this, LoginActivity::class.java))
|
launcher.launch(Intent(this, LoginActivity::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startRoomActivityAndFinish() {
|
||||||
|
startActivity(Intent(this, RoomListActivity::class.java))
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
51
libraries/core/build.gradle
Normal file
51
libraries/core/build.gradle
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
plugins {
|
||||||
|
id 'com.android.library'
|
||||||
|
id 'org.jetbrains.kotlin.android'
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace 'io.element.android.x.core'
|
||||||
|
compileSdk 33
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdk 29
|
||||||
|
targetSdk 33
|
||||||
|
|
||||||
|
consumerProguardFiles "consumer-rules.pro"
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
buildFeatures {
|
||||||
|
compose true
|
||||||
|
}
|
||||||
|
composeOptions {
|
||||||
|
kotlinCompilerExtensionVersion compose_version
|
||||||
|
}
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = '1.8'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation 'androidx.core:core-ktx:1.9.0'
|
||||||
|
implementation 'androidx.appcompat:appcompat:1.5.1'
|
||||||
|
|
||||||
|
implementation 'com.google.android.material:material:1.6.1'
|
||||||
|
|
||||||
|
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
|
||||||
|
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1"
|
||||||
|
implementation 'androidx.activity:activity-compose:1.6.0'
|
||||||
|
|
||||||
|
implementation 'androidx.fragment:fragment-ktx:1.5.3'
|
||||||
|
|
||||||
|
implementation 'com.airbnb.android:mavericks-compose:2.7.0'
|
||||||
|
}
|
||||||
2
libraries/core/src/main/AndroidManifest.xml
Normal file
2
libraries/core/src/main/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest />
|
||||||
|
|
@ -36,6 +36,7 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation project(":libraries:core")
|
||||||
implementation project(":libraries:ui:theme")
|
implementation project(":libraries:ui:theme")
|
||||||
implementation project(":libraries:sdk:matrix")
|
implementation project(":libraries:sdk:matrix")
|
||||||
|
|
||||||
|
|
@ -55,4 +56,6 @@ dependencies {
|
||||||
implementation 'androidx.activity:activity-compose:1.6.0'
|
implementation 'androidx.activity:activity-compose:1.6.0'
|
||||||
|
|
||||||
implementation 'androidx.fragment:fragment-ktx:1.5.3'
|
implementation 'androidx.fragment:fragment-ktx:1.5.3'
|
||||||
|
|
||||||
|
implementation 'com.airbnb.android:mavericks-compose:2.7.0'
|
||||||
}
|
}
|
||||||
|
|
@ -1,25 +1,31 @@
|
||||||
package io.element.android.x.ui.screen.login
|
package io.element.android.x.ui.screen.login
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.viewModels
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.airbnb.mvrx.Fail
|
||||||
|
import com.airbnb.mvrx.Loading
|
||||||
|
import com.airbnb.mvrx.Success
|
||||||
|
import com.airbnb.mvrx.compose.collectAsState
|
||||||
|
import com.airbnb.mvrx.compose.mavericksViewModel
|
||||||
import io.element.android.x.ui.theme.ElementXTheme
|
import io.element.android.x.ui.theme.ElementXTheme
|
||||||
import io.element.android.x.ui.theme.components.VectorButton
|
import io.element.android.x.ui.theme.components.VectorButton
|
||||||
import io.element.android.x.ui.theme.components.VectorTextField
|
import io.element.android.x.ui.theme.components.VectorTextField
|
||||||
|
|
||||||
class LoginActivity : ComponentActivity() {
|
class LoginActivity : ComponentActivity() {
|
||||||
|
|
||||||
private val viewModel: LoginViewModel by viewModels()
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
|
@ -35,9 +41,10 @@ class LoginActivity : ComponentActivity() {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
val state = viewModel.state.collectAsState().value
|
val viewModel: LoginViewModel = mavericksViewModel()
|
||||||
VectorTextField(
|
val state by viewModel.collectAsState()
|
||||||
value = state.homeserver,
|
val isError = state.isLoggedIn is Fail
|
||||||
|
VectorTextField(value = state.homeserver,
|
||||||
onValueChange = {
|
onValueChange = {
|
||||||
viewModel.handle(LoginActions.SetHomeserver(it))
|
viewModel.handle(LoginActions.SetHomeserver(it))
|
||||||
})
|
})
|
||||||
|
|
@ -50,18 +57,42 @@ class LoginActivity : ComponentActivity() {
|
||||||
value = state.password,
|
value = state.password,
|
||||||
onValueChange = {
|
onValueChange = {
|
||||||
viewModel.handle(LoginActions.SetPassword(it))
|
viewModel.handle(LoginActions.SetPassword(it))
|
||||||
}
|
},
|
||||||
|
isError = isError
|
||||||
)
|
)
|
||||||
|
if (isError) {
|
||||||
|
Text(
|
||||||
|
text = (state.isLoggedIn as? Fail)?.toString().orEmpty(),
|
||||||
|
color = MaterialTheme.colorScheme.error,
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
modifier = Modifier.padding(start = 16.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
VectorButton(
|
VectorButton(
|
||||||
text = "Submit",
|
text = "Submit",
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.handle(LoginActions.Submit)
|
viewModel.handle(LoginActions.Submit)
|
||||||
},
|
},
|
||||||
enabled = state.submitEnabled,
|
enabled = state.submitEnabled,
|
||||||
|
modifier = Modifier.align(Alignment.End)
|
||||||
)
|
)
|
||||||
|
if (state.isLoggedIn is Loading) {
|
||||||
|
// FIXME This does not work, we never enter this if block
|
||||||
|
CircularProgressIndicator(
|
||||||
|
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (state.isLoggedIn is Success) {
|
||||||
|
openRoomList()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun openRoomList() {
|
||||||
|
setResult(Activity.RESULT_OK)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,38 @@
|
||||||
package io.element.android.x.ui.screen.login
|
package io.element.android.x.ui.screen.login
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.lifecycle.ViewModel
|
import com.airbnb.mvrx.Fail
|
||||||
import androidx.lifecycle.viewModelScope
|
import com.airbnb.mvrx.Loading
|
||||||
|
import com.airbnb.mvrx.MavericksViewModel
|
||||||
|
import com.airbnb.mvrx.Success
|
||||||
import io.element.android.x.sdk.matrix.MatrixInstance
|
import io.element.android.x.sdk.matrix.MatrixInstance
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class LoginViewModel : ViewModel() {
|
class LoginViewModel(initialState: LoginViewState) :
|
||||||
|
MavericksViewModel<LoginViewState>(initialState) {
|
||||||
|
|
||||||
private val matrix = MatrixInstance.getInstance()
|
private val matrix = MatrixInstance.getInstance()
|
||||||
|
|
||||||
private val _state = MutableStateFlow(LoginViewState())
|
|
||||||
val state = _state.asStateFlow()
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
observeState()
|
observeState()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeState() {
|
private fun observeState() {
|
||||||
// TODO Update submitEnabled when other state members are updated.
|
onEach(
|
||||||
|
LoginViewState::homeserver,
|
||||||
|
LoginViewState::login,
|
||||||
|
LoginViewState::password,
|
||||||
|
LoginViewState::isLoggedIn,
|
||||||
|
) { homeserver, login, password, isLoggedIn ->
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
submitEnabled = homeserver.isNotEmpty() &&
|
||||||
|
login.isNotEmpty() &&
|
||||||
|
password.isNotEmpty() &&
|
||||||
|
isLoggedIn !is Loading
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handle(action: LoginActions) {
|
fun handle(action: LoginActions) {
|
||||||
|
|
@ -33,40 +45,40 @@ class LoginViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSetHomeserver(action: LoginActions.SetHomeserver) {
|
private fun handleSetHomeserver(action: LoginActions.SetHomeserver) {
|
||||||
_state.value = _state.value.copy(
|
setState {
|
||||||
homeserver = action.homeserver,
|
copy(
|
||||||
submitEnabled = _state.value.login.isNotEmpty() &&
|
homeserver = action.homeserver
|
||||||
_state.value.password.isNotEmpty() &&
|
)
|
||||||
action.homeserver.isNotEmpty()
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSubmit() {
|
private fun handleSubmit() = withState { state ->
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val currentState = state.value
|
setState { copy(isLoggedIn = Loading()) }
|
||||||
try {
|
try {
|
||||||
matrix.login(currentState.homeserver, currentState.login, currentState.password)
|
matrix.login(state.homeserver, state.login, state.password)
|
||||||
|
setState { copy(isLoggedIn = Success(Unit)) }
|
||||||
} catch (throwable: Throwable) {
|
} catch (throwable: Throwable) {
|
||||||
Log.e("Error", "Cannot login", throwable)
|
Log.e("Error", "Cannot login", throwable)
|
||||||
|
setState { copy(isLoggedIn = Fail(throwable)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSetPassword(action: LoginActions.SetPassword) {
|
private fun handleSetPassword(action: LoginActions.SetPassword) {
|
||||||
_state.value = _state.value.copy(
|
setState {
|
||||||
password = action.password,
|
copy(
|
||||||
submitEnabled = _state.value.login.isNotEmpty() &&
|
password = action.password
|
||||||
_state.value.homeserver.isNotEmpty() &&
|
)
|
||||||
action.password.isNotEmpty()
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSetName(action: LoginActions.SetLogin) {
|
private fun handleSetName(action: LoginActions.SetLogin) {
|
||||||
_state.value = _state.value.copy(
|
setState {
|
||||||
login = action.login,
|
copy(
|
||||||
submitEnabled = action.login.isNotEmpty() &&
|
|
||||||
_state.value.homeserver.isNotEmpty() &&
|
login = action.login
|
||||||
_state.value.password.isNotEmpty()
|
)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,13 @@
|
||||||
package io.element.android.x.ui.screen.login
|
package io.element.android.x.ui.screen.login
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.Async
|
||||||
|
import com.airbnb.mvrx.MavericksState
|
||||||
|
import com.airbnb.mvrx.Uninitialized
|
||||||
|
|
||||||
data class LoginViewState(
|
data class LoginViewState(
|
||||||
val homeserver: String = "matrix.org",
|
val homeserver: String = "matrix.org",
|
||||||
val login: String = "",
|
val login: String = "",
|
||||||
val password: String = "",
|
val password: String = "",
|
||||||
val submitEnabled: Boolean = false,
|
val submitEnabled: Boolean = false,
|
||||||
)
|
val isLoggedIn: Async<Unit> = Uninitialized,
|
||||||
|
) : MavericksState
|
||||||
|
|
|
||||||
61
libraries/ui/screens/roomlist/build.gradle
Normal file
61
libraries/ui/screens/roomlist/build.gradle
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
plugins {
|
||||||
|
id 'com.android.library'
|
||||||
|
id 'org.jetbrains.kotlin.android'
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace 'io.element.android.x.ui.screen.roomlist'
|
||||||
|
compileSdk 33
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdk 29
|
||||||
|
targetSdk 33
|
||||||
|
|
||||||
|
consumerProguardFiles "consumer-rules.pro"
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
buildFeatures {
|
||||||
|
compose true
|
||||||
|
}
|
||||||
|
composeOptions {
|
||||||
|
kotlinCompilerExtensionVersion compose_version
|
||||||
|
}
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = '1.8'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation project(":libraries:core")
|
||||||
|
implementation project(":libraries:ui:theme")
|
||||||
|
implementation project(":libraries:sdk:matrix")
|
||||||
|
|
||||||
|
implementation 'androidx.core:core-ktx:1.9.0'
|
||||||
|
implementation 'androidx.appcompat:appcompat:1.5.1'
|
||||||
|
|
||||||
|
implementation 'com.google.android.material:material:1.6.1'
|
||||||
|
|
||||||
|
implementation "androidx.compose.ui:ui:$compose_version"
|
||||||
|
implementation 'androidx.compose.material3:material3:1.0.0-rc01'
|
||||||
|
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
|
||||||
|
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
|
||||||
|
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
|
||||||
|
|
||||||
|
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
|
||||||
|
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1"
|
||||||
|
implementation 'androidx.activity:activity-compose:1.6.0'
|
||||||
|
|
||||||
|
implementation 'androidx.fragment:fragment-ktx:1.5.3'
|
||||||
|
|
||||||
|
implementation 'com.airbnb.android:mavericks-compose:2.7.0'
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<application>
|
||||||
|
<activity android:name="RoomListActivity" />
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package io.element.android.x.ui.screen.login
|
||||||
|
|
||||||
|
sealed interface RoomListActions {
|
||||||
|
object LoadMore : RoomListActions
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
package io.element.android.x.ui.screen.login
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.activity.viewModels
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.element.android.x.ui.theme.ElementXTheme
|
||||||
|
|
||||||
|
class RoomListActivity : ComponentActivity() {
|
||||||
|
|
||||||
|
private val viewModel: RoomListViewModel by viewModels()
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
setContent {
|
||||||
|
ElementXTheme {
|
||||||
|
// A surface container using the 'background' color from the theme
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(16.dp),
|
||||||
|
color = MaterialTheme.colorScheme.background
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
/* TODO
|
||||||
|
val state = viewModel.state.collectAsState().value
|
||||||
|
RoomListHeader()
|
||||||
|
RoomList()
|
||||||
|
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package io.element.android.x.ui.screen.login
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import io.element.android.x.sdk.matrix.MatrixInstance
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
|
||||||
|
class RoomListViewModel : ViewModel() {
|
||||||
|
|
||||||
|
private val matrix = MatrixInstance.getInstance()
|
||||||
|
|
||||||
|
private val _state = MutableStateFlow(RoomListViewState())
|
||||||
|
val state = _state.asStateFlow()
|
||||||
|
|
||||||
|
init {
|
||||||
|
observeState()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeState() {
|
||||||
|
// TODO Update submitEnabled when other state members are updated.
|
||||||
|
}
|
||||||
|
|
||||||
|
fun handle(action: RoomListActions) {
|
||||||
|
when (action) {
|
||||||
|
RoomListActions.LoadMore -> TODO()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package io.element.android.x.ui.screen.login
|
||||||
|
|
||||||
|
data class RoomListViewState(
|
||||||
|
val list: List<String> = emptyList(),
|
||||||
|
val canLoadMore: Boolean = false,
|
||||||
|
)
|
||||||
|
|
@ -3,13 +3,15 @@ package io.element.android.x.ui.theme.components
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun VectorButton(text: String, enabled: Boolean, onClick: () -> Unit) {
|
fun VectorButton(text: String, enabled: Boolean, onClick: () -> Unit, modifier: Modifier? = null) {
|
||||||
Button(
|
Button(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
enabled = enabled,
|
enabled = enabled,
|
||||||
|
modifier = modifier ?: Modifier
|
||||||
) {
|
) {
|
||||||
Text(text = text)
|
Text(text = text)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,11 @@ import androidx.compose.ui.Modifier
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun VectorTextField(value: String, onValueChange: (String) -> Unit) {
|
fun VectorTextField(value: String, onValueChange: (String) -> Unit, isError: Boolean = false) {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = value,
|
value = value,
|
||||||
onValueChange = onValueChange,
|
onValueChange = onValueChange,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
isError = isError
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ dependencyResolutionManagement {
|
||||||
}
|
}
|
||||||
rootProject.name = "ElementX"
|
rootProject.name = "ElementX"
|
||||||
include ':app'
|
include ':app'
|
||||||
|
include ':libraries:core'
|
||||||
include ':libraries:ui:theme'
|
include ':libraries:ui:theme'
|
||||||
include ':libraries:ui:screens:login'
|
include ':libraries:ui:screens:login'
|
||||||
|
include ':libraries:ui:screens:roomlist'
|
||||||
include ':libraries:sdk:matrix'
|
include ':libraries:sdk:matrix'
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue