Create login module

This commit is contained in:
Benoit Marty
2022-10-07 17:31:27 +02:00
parent 94d031ffce
commit a18d272462
13 changed files with 224 additions and 37 deletions

View File

@@ -47,6 +47,7 @@ android {
dependencies {
implementation project(":libraries:ui:theme")
implementation project(":libraries:ui:screens:login")
implementation 'androidx.core:core-ktx:1.9.0'
implementation "androidx.compose.ui:ui:$compose_version"

View File

@@ -11,12 +11,10 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ElementX"
tools:targetApi="31">
tools:targetApi="33">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.ElementX">
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

View File

@@ -1,43 +1,16 @@
package io.element.android.x
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import io.element.android.x.ui.theme.ElementXTheme
import io.element.android.x.ui.screen.login.LoginActivity
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ElementXTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Greeting("Android")
}
}
}
// Just start the LoginActivity for now.
// TODO if a session exist, start the room list
startActivity(Intent(this, LoginActivity::class.java))
finish()
}
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
ElementXTheme {
Greeting("Android")
}
}

View File

@@ -0,0 +1,57 @@
plugins {
id 'com.android.library'
id 'org.jetbrains.kotlin.android'
}
android {
namespace 'io.element.android.x.ui.screen.login'
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:ui:theme")
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'
}

View File

@@ -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="LoginActivity" />
</application>
</manifest>

View File

@@ -0,0 +1,7 @@
package io.element.android.x.ui.screen.login
sealed interface LoginActions {
data class SetLogin(val login: String) : LoginActions
data class SetPassword(val password: String) : LoginActions
object Submit : LoginActions
}

View File

@@ -0,0 +1,62 @@
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
import io.element.android.x.ui.theme.components.VectorButton
import io.element.android.x.ui.theme.components.VectorTextField
class LoginActivity : ComponentActivity() {
private val viewModel: LoginViewModel 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()
) {
val state = viewModel.state.collectAsState().value
VectorTextField(
value = state.login,
onValueChange = {
viewModel.handle(LoginActions.SetLogin(it))
})
VectorTextField(
value = state.password,
onValueChange = {
viewModel.handle(LoginActions.SetPassword(it))
}
)
VectorButton(
text = "Submit",
onClick = {
viewModel.handle(LoginActions.Submit)
},
enabled = state.submitEnabled,
)
}
}
}
}
}
}

View File

@@ -0,0 +1,37 @@
package io.element.android.x.ui.screen.login
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
class LoginViewModel : ViewModel() {
private val _state = MutableStateFlow(LoginViewState())
val state = _state.asStateFlow()
fun handle(action: LoginActions) {
when (action) {
is LoginActions.SetLogin -> handleSetName(action)
is LoginActions.SetPassword -> handleSetPassword(action)
LoginActions.Submit -> handleSubmit()
}
}
private fun handleSubmit() {
// TODO
}
private fun handleSetPassword(action: LoginActions.SetPassword) {
_state.value = _state.value.copy(
password = action.password,
submitEnabled = _state.value.login.isNotEmpty() && action.password.isNotEmpty()
)
}
private fun handleSetName(action: LoginActions.SetLogin) {
_state.value = _state.value.copy(
login = action.login,
submitEnabled = action.login.isNotEmpty() && _state.value.password.isNotEmpty()
)
}
}

View File

@@ -0,0 +1,7 @@
package io.element.android.x.ui.screen.login
data class LoginViewState(
val login: String = "",
val password: String = "",
val submitEnabled: Boolean = false,
)

View File

@@ -45,4 +45,6 @@ dependencies {
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-viewmodel-compose:2.5.1"
}

View File

@@ -0,0 +1,16 @@
package io.element.android.x.ui.theme.components
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@Composable
fun VectorButton(text: String, enabled: Boolean, onClick: () -> Unit) {
Button(
onClick = onClick,
enabled = enabled,
) {
Text(text = text)
}
}

View File

@@ -0,0 +1,18 @@
package io.element.android.x.ui.theme.components
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.OutlinedTextField
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun VectorTextField(value: String, onValueChange: (String) -> Unit) {
OutlinedTextField(
value = value,
onValueChange = onValueChange,
modifier = Modifier.fillMaxWidth()
)
}

View File

@@ -15,3 +15,4 @@ dependencyResolutionManagement {
rootProject.name = "ElementX"
include ':app'
include ':libraries:ui:theme'
include ':libraries:ui:screens:login'