Fiddling with the login and signup screens

This commit is contained in:
Z. Charles Dziura 2024-08-17 21:48:49 -04:00
parent ecea0e12d6
commit 45d632f786
7 changed files with 180 additions and 35 deletions

View file

@ -64,6 +64,8 @@ dependencies {
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.lifecycle.runtime.compose)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)

View file

@ -1,28 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.DebtPirate"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/title_activity_main"
android:theme="@style/Theme.DebtPirate">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.DebtPirate">
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.DebtPirate"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View file

@ -4,12 +4,14 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import kotlinx.serialization.Serializable
import software.makeshift.debtpirate.ui.theme.DebtPirateTheme
import software.makeshift.debtpirate.usecases.login.LoginScreen
import software.makeshift.debtpirate.usecases.login.LoginScreenViewModel
@Serializable
object LoginRoute
@ -24,7 +26,11 @@ class MainActivity : ComponentActivity() {
DebtPirateTheme {
NavHost(navController = navController, startDestination = LoginRoute) {
composable<LoginRoute> {
LoginScreen()
val viewModel: LoginScreenViewModel by viewModels()
LoginScreen(
viewModel.loginState,
viewModel::updateLoginUsername
)
}
}
}

View file

@ -1,23 +1,123 @@
@file:OptIn(ExperimentalMaterial3Api::class)
package software.makeshift.debtpirate.usecases.login
import android.annotation.SuppressLint
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SecondaryTabRow
import androidx.compose.material3.Tab
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.flow.StateFlow
import software.makeshift.debtpirate.R
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun LoginScreen() {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(modifier = Modifier.padding(innerPadding))
fun LoginScreen(
loginState: StateFlow<LoginState>,
updateLoginUsername: (String) -> Unit
) {
Scaffold(modifier = Modifier.fillMaxSize()) {
Column {
Banner(
modifier = Modifier
.fillMaxWidth()
.weight(1f)
)
LoginAndSignUpForms(
loginState,
modifier = Modifier
.weight(3f)
)
}
}
}
@Composable
private fun Greeting(modifier: Modifier = Modifier) {
Text(
text = "Hello from Login!",
modifier = modifier
)
private fun Banner(modifier: Modifier = Modifier) {
Box(modifier = modifier.background(Color.Green)) {
Text(
text = "Hello from Login! I'm in a box!",
modifier = Modifier.align(Alignment.Center)
)
}
}
@Composable
private fun LoginAndSignUpForms(
loginTabState: StateFlow<LoginState>,
modifier: Modifier = Modifier
) {
Column(modifier = modifier) {
val pagerState = rememberPagerState(initialPage = 0) { 2 }
SecondaryTabRow(
selectedTabIndex = pagerState.currentPage,
modifier = Modifier.height(48.dp)
) {
val tabTextStyle = MaterialTheme.typography.titleLarge
Tab(
selected = pagerState.currentPage == 0,
onClick = { pagerState.requestScrollToPage(0) },
modifier = Modifier.fillMaxHeight()
) {
Text(
text = stringResource(id = R.string.loginscreen_logintab_logintitle),
style = tabTextStyle,
modifier = Modifier.fillMaxHeight()
)
}
Tab(
selected = pagerState.currentPage == 1,
onClick = { pagerState.requestScrollToPage(1) },
modifier = Modifier.fillMaxHeight()
) {
Text(
text = stringResource(id = R.string.loginscreen_logintab_signuptitle),
style = tabTextStyle,
modifier = Modifier.fillMaxHeight()
)
}
}
HorizontalPager(
state = pagerState,
userScrollEnabled = false,
modifier = Modifier.fillMaxSize()
) { page ->
when (page) {
0 -> {
Text("Page 1!")
}
1 -> {
Text("Page 2!")
}
}
}
}
}
//@Composable
//private fun LoginForm(state: StateFlow<LoginState>, onUsernameUpdate: (String) -> Unit, onPasswordUpdate: (String) -> Unit) {
// Column {
// OutlinedTextField(value = , onValueChange = )
// }
//}

View file

@ -0,0 +1,32 @@
package software.makeshift.debtpirate.usecases.login
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.update
data class LoginState(val username: String? = null, val password: String? = null)
data class SignUpState(
val username: String? = null,
val password: String? = null,
val passwordConfirmed: String? = null,
val email: String? = null
)
class LoginScreenViewModel : ViewModel() {
private val _loginState = MutableStateFlow(LoginState())
val loginState = _loginState.asStateFlow()
val loginUsername: Flow<String?>
get() = loginState.map { loginState -> loginState.username }
fun updateLoginUsername(username: String) {
_loginState.update { state ->
val (_, password) = state
LoginState(username, password)
}
}
}

View file

@ -1,4 +1,7 @@
<resources>
<string name="app_name">Debt Pirate</string>
<string name="title_activity_main">MainActivity</string>
<!-- Login Screen -->
<string name="loginscreen_logintab_logintitle">Login</string>
<string name="loginscreen_logintab_signuptitle">Sign Up</string>
</resources>

View file

@ -9,6 +9,8 @@ appcompat = "1.7.0"
material = "1.12.0"
material3 = "1.3.0-beta05"
kotlinxSerializationJson = "1.7.1"
lifecycleRuntimeCompose = "2.8.4"
lifecycleViewmodelCompose = "2.8.4"
lifecycleRuntimeKtx = "2.8.4"
activityCompose = "1.9.1"
composeBom = "2024.06.00"
@ -23,6 +25,8 @@ androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" }
kotlinx-serialization = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycleRuntimeCompose" }
androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycleViewmodelCompose" }
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }