Finish laying out registration screen
This commit is contained in:
parent
dd0cc9ba2f
commit
149ce13e3e
9 changed files with 240 additions and 37 deletions
|
@ -16,12 +16,15 @@ import androidx.navigation.compose.rememberNavController
|
|||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import ing.bikeshedengineer.debtpirate.auth.presentation.login.LoginScreen
|
||||
import ing.bikeshedengineer.debtpirate.auth.presentation.register.RegistrationScreen
|
||||
import ing.bikeshedengineer.debtpirate.domain.usecase.pref.UpdateCurrentRouteUseCase
|
||||
import ing.bikeshedengineer.debtpirate.navigation.Destination
|
||||
import ing.bikeshedengineer.debtpirate.navigation.NavigationAction
|
||||
import ing.bikeshedengineer.debtpirate.navigation.Navigator
|
||||
import ing.bikeshedengineer.debtpirate.theme.DebtPirateTheme
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -30,6 +33,9 @@ class MainActivity : ComponentActivity() {
|
|||
@Inject
|
||||
lateinit var navigator: Navigator
|
||||
|
||||
@Inject
|
||||
lateinit var updateCurrentRoute: UpdateCurrentRouteUseCase
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
|
@ -40,9 +46,14 @@ class MainActivity : ComponentActivity() {
|
|||
when (action) {
|
||||
is NavigationAction.Navigate -> {
|
||||
navController.navigate(action.destination) {
|
||||
val scope = CoroutineScope(context = Dispatchers.IO)
|
||||
scope.launch {
|
||||
updateCurrentRoute(action.destination)
|
||||
}
|
||||
action.navOptions(this)
|
||||
}
|
||||
}
|
||||
|
||||
NavigationAction.NavigateUp -> {
|
||||
navController.navigateUp()
|
||||
}
|
||||
|
@ -51,8 +62,8 @@ class MainActivity : ComponentActivity() {
|
|||
|
||||
DebtPirateTheme {
|
||||
NavHost(navController = navController, startDestination = Destination.AuthGraph) {
|
||||
navigation<Destination.AuthGraph>(startDestination = Destination.LoginScreen) {
|
||||
composable<Destination.LoginScreen>() { LoginScreen(navController = navController) }
|
||||
navigation<Destination.AuthGraph>(startDestination = Destination.RegistrationScreen) {
|
||||
composable<Destination.LoginScreen>() { LoginScreen() }
|
||||
composable<Destination.RegistrationScreen>() { RegistrationScreen() }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,21 +45,8 @@ import ing.bikeshedengineer.debtpirate.R
|
|||
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
|
||||
@Composable
|
||||
fun LoginScreen(
|
||||
navController: NavController,
|
||||
viewModel: LoginScreenViewModel = hiltViewModel<LoginScreenViewModel>()
|
||||
) {
|
||||
// LaunchedEffect(viewModel.navigationEvent) {
|
||||
// viewModel.navigationEvent.collect { event ->
|
||||
// when (event) {
|
||||
// is AuthNavigationEvent.NavigateToRegistrationScreen -> {
|
||||
// navController.navigate(RegistrationRoute)
|
||||
// }
|
||||
//
|
||||
// else -> {}
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
|
@ -77,6 +64,7 @@ fun LoginScreen(
|
|||
) {
|
||||
val emailAddress = viewModel.emailAddress.collectAsState()
|
||||
val password = viewModel.password.collectAsState()
|
||||
|
||||
LoginComponent(
|
||||
emailAddress = emailAddress,
|
||||
onUpdateEmailAddress = viewModel::updateUsername,
|
||||
|
|
|
@ -38,7 +38,6 @@ enum class InvalidReason {
|
|||
@HiltViewModel
|
||||
class LoginScreenViewModel @Inject constructor(
|
||||
private val navigator: Navigator,
|
||||
private val authRepository: AuthRepository,
|
||||
private val prefsStore: DataStore<PrefsDataStore>,
|
||||
private val submitLoginCredentials: SubmitLoginCredentialsUseCase,
|
||||
private val validateLoginCredentials: ValidateLoginCredentialsUseCase,
|
||||
|
|
|
@ -1,39 +1,208 @@
|
|||
package ing.bikeshedengineer.debtpirate.auth.presentation.register
|
||||
|
||||
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.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
|
||||
import androidx.compose.material.icons.outlined.Mail
|
||||
import androidx.compose.material.icons.outlined.Password
|
||||
import androidx.compose.material.icons.outlined.Person
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.MediumTopAppBar
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
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.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import ing.bikeshedengineer.debtpirate.R
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
|
||||
@Composable()
|
||||
fun RegistrationScreen() {
|
||||
fun RegistrationScreen(viewModel: RegistrationScreenViewModel = hiltViewModel<RegistrationScreenViewModel>()) {
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
Column {
|
||||
RegistrationScreenTopAppBar(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
.weight(1f)
|
||||
)
|
||||
topBar = { RegistrationTopAppBar(onNavigateUp = viewModel::navigateUp) },
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||
) { innerPadding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.padding(16.dp)
|
||||
) {
|
||||
RegistrationComponent()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun RegistrationScreenTopAppBar(modifier: Modifier = Modifier) {
|
||||
Box(modifier = modifier.background(Color.Green)) {
|
||||
private fun RegistrationTopAppBar(onNavigateUp: () -> Unit, modifier: Modifier = Modifier) {
|
||||
MediumTopAppBar(
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = MaterialTheme.colorScheme.primaryContainer,
|
||||
titleContentColor = MaterialTheme.colorScheme.primary,
|
||||
),
|
||||
title = {
|
||||
Text(
|
||||
stringResource(R.string.auth__createAccount),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onNavigateUp) {
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Outlined.ArrowBack,
|
||||
contentDescription = "back"
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RegistrationComponent(modifier: Modifier = Modifier) {
|
||||
Column(modifier = modifier.verticalScroll(rememberScrollState())) {
|
||||
OutlinedTextField(
|
||||
value = "",
|
||||
label = { Text(text = stringResource(R.string.auth__email)) },
|
||||
placeholder = { Text(text = stringResource(R.string.auth__email)) },
|
||||
leadingIcon = { Icon(Icons.Outlined.Mail, stringResource(R.string.auth__email)) },
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
capitalization = KeyboardCapitalization.None,
|
||||
keyboardType = KeyboardType.Email,
|
||||
imeAction = ImeAction.Next
|
||||
),
|
||||
onValueChange = {},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
OutlinedTextField(
|
||||
value = "",
|
||||
label = { Text(text = stringResource(R.string.auth__name)) },
|
||||
placeholder = { Text(text = stringResource(R.string.auth__name)) },
|
||||
leadingIcon = { Icon(Icons.Outlined.Person, stringResource(R.string.auth__name)) },
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
capitalization = KeyboardCapitalization.Words,
|
||||
keyboardType = KeyboardType.Text,
|
||||
imeAction = ImeAction.Next
|
||||
),
|
||||
onValueChange = {},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(PaddingValues(top = 4.dp))
|
||||
)
|
||||
|
||||
OutlinedTextField(
|
||||
value = "",
|
||||
label = { Text(text = stringResource(R.string.auth__password)) },
|
||||
placeholder = { Text(text = stringResource(R.string.auth__password)) },
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
Icons.Outlined.Password,
|
||||
stringResource(R.string.auth__password)
|
||||
)
|
||||
},
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
capitalization = KeyboardCapitalization.None,
|
||||
keyboardType = KeyboardType.Password,
|
||||
imeAction = ImeAction.Next
|
||||
),
|
||||
onValueChange = {},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(PaddingValues(top = 4.dp))
|
||||
)
|
||||
|
||||
OutlinedTextField(
|
||||
value = "",
|
||||
label = { Text(text = stringResource(R.string.auth__confirmPassword)) },
|
||||
placeholder = { Text(text = stringResource(R.string.auth__confirmPassword)) },
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
Icons.Outlined.Password,
|
||||
stringResource(R.string.auth__confirmPassword)
|
||||
)
|
||||
},
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
capitalization = KeyboardCapitalization.None,
|
||||
keyboardType = KeyboardType.Password,
|
||||
imeAction = ImeAction.Done
|
||||
),
|
||||
onValueChange = {},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(PaddingValues(top = 4.dp))
|
||||
)
|
||||
|
||||
var linkStyle = SpanStyle(color = Color.Blue, textDecoration = TextDecoration.Underline)
|
||||
Text(
|
||||
text = "Hello from Registration! I'm in a box!",
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
modifier = Modifier.padding(paddingValues = PaddingValues(top = 16.dp, bottom = 16.dp)),
|
||||
text = buildAnnotatedString {
|
||||
append("By registering, you agree to the ")
|
||||
|
||||
withStyle(style = linkStyle) {
|
||||
append("Terms & Conditions")
|
||||
}
|
||||
|
||||
append(" and ")
|
||||
|
||||
withStyle(style = linkStyle) {
|
||||
append("Privacy Policy")
|
||||
}
|
||||
|
||||
append(".")
|
||||
},
|
||||
softWrap = true
|
||||
)
|
||||
|
||||
RegisterButton()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RegisterButton() {
|
||||
Button(
|
||||
onClick = { },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Text(
|
||||
"Register"
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,19 @@
|
|||
package ing.bikeshedengineer.debtpirate.auth.presentation.register
|
||||
|
||||
class RegistrationScreenViewModel {
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import ing.bikeshedengineer.debtpirate.navigation.Navigator
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class RegistrationScreenViewModel @Inject constructor(
|
||||
private val navigator: Navigator
|
||||
) : ViewModel() {
|
||||
fun navigateUp() {
|
||||
viewModelScope.launch {
|
||||
navigator.navigateUp()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package ing.bikeshedengineer.debtpirate.domain.usecase.pref
|
||||
|
||||
import androidx.datastore.core.DataStore
|
||||
import ing.bikeshedengineer.debtpirate.PrefsDataStore
|
||||
import ing.bikeshedengineer.debtpirate.navigation.Destination
|
||||
import javax.inject.Inject
|
||||
|
||||
class UpdateCurrentRouteUseCase @Inject constructor(
|
||||
private val store: DataStore<PrefsDataStore>
|
||||
) {
|
||||
suspend operator fun invoke(destination: Destination) {
|
||||
store.updateData { data ->
|
||||
data.toBuilder()
|
||||
.setCurrentRoute(destination.toString())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,6 @@ import androidx.navigation.NavOptionsBuilder
|
|||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import javax.inject.Inject
|
||||
|
||||
interface Navigator {
|
||||
val startDestination: Destination
|
||||
|
@ -16,7 +15,7 @@ interface Navigator {
|
|||
}
|
||||
|
||||
class NavigatorImpl(
|
||||
override val startDestination: Destination
|
||||
override val startDestination: Destination,
|
||||
) : Navigator {
|
||||
private val _navigationActions = Channel<NavigationAction>()
|
||||
override val navigationActions = _navigationActions.receiveAsFlow()
|
||||
|
|
|
@ -9,7 +9,8 @@ message Token {
|
|||
}
|
||||
|
||||
message PrefsDataStore {
|
||||
int32 user_id = 1;
|
||||
Token auth_token = 2;
|
||||
Token session_token = 3;
|
||||
string current_route = 1;
|
||||
int32 user_id = 2;
|
||||
Token auth_token = 3;
|
||||
Token session_token = 4;
|
||||
}
|
|
@ -2,4 +2,7 @@
|
|||
<string name="app_name">Debt Pirate</string>
|
||||
<string name="auth__email">Email</string>
|
||||
<string name="auth__password">Password</string>
|
||||
<string name="auth__confirmPassword">Confirm Password</string>
|
||||
<string name="auth__createAccount">Create Account</string>
|
||||
<string name="auth__name">Name</string>
|
||||
</resources>
|
Loading…
Add table
Reference in a new issue