Skip to content

Commit fc0b406

Browse files
Sign in ui and view model (#2851)
1 parent 067c43c commit fc0b406

File tree

8 files changed

+307
-134
lines changed

8 files changed

+307
-134
lines changed

core/designsystem/src/commonMain/kotlin/org/mifos/mobile/core/designsystem/component/MifosPasswordField.kt

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ import androidx.compose.foundation.text.KeyboardActions
1313
import androidx.compose.foundation.text.KeyboardOptions
1414
import androidx.compose.material3.Icon
1515
import androidx.compose.material3.IconButton
16+
import androidx.compose.material3.MaterialTheme
17+
import androidx.compose.material3.OutlinedTextFieldDefaults
18+
import androidx.compose.material3.TextFieldColors
1619
import androidx.compose.runtime.Composable
1720
import androidx.compose.runtime.LaunchedEffect
1821
import androidx.compose.runtime.getValue
@@ -23,6 +26,8 @@ import androidx.compose.runtime.setValue
2326
import androidx.compose.ui.Modifier
2427
import androidx.compose.ui.focus.FocusRequester
2528
import androidx.compose.ui.focus.focusRequester
29+
import androidx.compose.ui.graphics.Color
30+
import androidx.compose.ui.graphics.Shape
2631
import androidx.compose.ui.semantics.semantics
2732
import androidx.compose.ui.semantics.testTag
2833
import androidx.compose.ui.text.input.ImeAction
@@ -42,6 +47,9 @@ fun MifosPasswordField(
4247
showPasswordChange: (Boolean) -> Unit,
4348
onValueChange: (String) -> Unit,
4449
modifier: Modifier = Modifier,
50+
shape: Shape = OutlinedTextFieldDefaults.shape,
51+
colors: TextFieldColors = OutlinedTextFieldDefaults.colors(),
52+
isError: Boolean = false,
4553
readOnly: Boolean = false,
4654
singleLine: Boolean = true,
4755
hint: String? = null,
@@ -56,6 +64,8 @@ fun MifosPasswordField(
5664
modifier = modifier
5765
.tabNavigation()
5866
.focusRequester(focusRequester),
67+
shape = shape,
68+
colors = colors,
5969
label = label,
6070
value = value,
6171
onValueChange = onValueChange,
@@ -67,27 +77,33 @@ fun MifosPasswordField(
6777
},
6878
singleLine = singleLine,
6979
readOnly = readOnly,
80+
isError = isError,
7081
keyboardOptions = KeyboardOptions(
7182
keyboardType = keyboardType,
7283
imeAction = imeAction,
7384
),
7485
keyboardActions = keyboardActions,
7586
errorText = hint,
7687
trailingIcon = {
77-
IconButton(
78-
onClick = { showPasswordChange.invoke(!showPassword) },
79-
) {
80-
val imageVector = if (showPassword) {
81-
MifosIcons.OutlinedVisibilityOff
82-
} else {
83-
MifosIcons.OutlinedVisibility
84-
}
85-
88+
if (isError) {
8689
Icon(
87-
modifier = Modifier.semantics { showPasswordTestTag?.let { testTag = it } },
88-
imageVector = imageVector,
89-
contentDescription = "togglePassword",
90+
imageVector = MifosIcons.EyeFilled,
91+
contentDescription = "Error",
92+
tint = MaterialTheme.colorScheme.error,
9093
)
94+
} else {
95+
IconButton(
96+
onClick = { showPasswordChange.invoke(!showPassword) },
97+
) {
98+
val imageVector = if (showPassword) MifosIcons.EyeOff else MifosIcons.Eye
99+
100+
Icon(
101+
modifier = Modifier.semantics { showPasswordTestTag?.let { testTag = it } },
102+
imageVector = imageVector,
103+
contentDescription = "togglePassword",
104+
tint = Color.Unspecified,
105+
)
106+
}
91107
}
92108
},
93109
),
@@ -103,6 +119,9 @@ fun MifosPasswordField(
103119
value: String,
104120
onValueChange: (String) -> Unit,
105121
modifier: Modifier = Modifier,
122+
shape: Shape = OutlinedTextFieldDefaults.shape,
123+
colors: TextFieldColors = OutlinedTextFieldDefaults.colors(),
124+
isError: Boolean = false,
106125
readOnly: Boolean = false,
107126
singleLine: Boolean = true,
108127
hint: String? = null,
@@ -117,6 +136,9 @@ fun MifosPasswordField(
117136
MifosPasswordField(
118137
modifier = modifier,
119138
label = label,
139+
shape = shape,
140+
colors = colors,
141+
isError = isError,
120142
value = value,
121143
showPassword = showPassword,
122144
showPasswordChange = { showPassword = !showPassword },

core/designsystem/src/commonMain/kotlin/org/mifos/mobile/core/designsystem/component/MifosTextField.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,16 @@ import androidx.compose.material3.IconButton
2121
import androidx.compose.material3.LocalTextStyle
2222
import androidx.compose.material3.MaterialTheme
2323
import androidx.compose.material3.OutlinedTextField
24+
import androidx.compose.material3.OutlinedTextFieldDefaults
2425
import androidx.compose.material3.Text
26+
import androidx.compose.material3.TextFieldColors
27+
import androidx.compose.material3.TextFieldDefaults
2528
import androidx.compose.runtime.Composable
2629
import androidx.compose.runtime.getValue
2730
import androidx.compose.runtime.remember
2831
import androidx.compose.runtime.rememberUpdatedState
2932
import androidx.compose.ui.Modifier
33+
import androidx.compose.ui.graphics.Shape
3034
import androidx.compose.ui.graphics.vector.ImageVector
3135
import androidx.compose.ui.platform.testTag
3236
import androidx.compose.ui.semantics.contentDescription
@@ -35,13 +39,16 @@ import androidx.compose.ui.text.TextStyle
3539
import androidx.compose.ui.text.input.ImeAction
3640
import androidx.compose.ui.text.input.VisualTransformation
3741
import org.mifos.mobile.core.designsystem.icon.MifosIcons
42+
import org.mifos.mobile.core.designsystem.theme.MifosTypography
3843

3944
@Composable
4045
fun MifosOutlinedTextField(
4146
value: String,
4247
onValueChange: (String) -> Unit,
4348
label: String,
4449
modifier: Modifier = Modifier,
50+
shape: Shape = OutlinedTextFieldDefaults.shape,
51+
colors: TextFieldColors = TextFieldDefaults.colors(),
4552
textStyle: TextStyle = LocalTextStyle.current,
4653
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
4754
config: MifosTextFieldConfig = MifosTextFieldConfig(),
@@ -51,6 +58,8 @@ fun MifosOutlinedTextField(
5158
val showIcon by rememberUpdatedState(value.isNotEmpty())
5259

5360
OutlinedTextField(
61+
shape = shape,
62+
colors = colors,
5463
value = value,
5564
label = { Text(text = label) },
5665
onValueChange = onValueChange,
@@ -87,7 +96,7 @@ fun MifosOutlinedTextField(
8796
Text(
8897
modifier = Modifier.testTag("errorTag"),
8998
text = it,
90-
style = MaterialTheme.typography.labelSmall,
99+
style = MifosTypography.bodySmall,
91100
color = MaterialTheme.colorScheme.error,
92101
)
93102
}
@@ -146,7 +155,7 @@ fun MifosTextField(
146155
Text(
147156
modifier = Modifier.testTag("errorTag"),
148157
text = it ?: "",
149-
style = MaterialTheme.typography.labelSmall,
158+
style = MifosTypography.bodySmall,
150159
color = MaterialTheme.colorScheme.error,
151160
)
152161
}

core/designsystem/src/commonMain/kotlin/org/mifos/mobile/core/designsystem/icon/MifosIcons.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,11 @@ import androidx.compose.material.icons.rounded.Home
5454
import androidx.compose.material.icons.rounded.SwapHoriz
5555
import androidx.compose.ui.graphics.vector.ImageVector
5656
import fluent.ui.system.icons.FluentIcons
57+
import fluent.ui.system.icons.filled.ErrorCircle
58+
import fluent.ui.system.icons.filled.Eye
5759
import fluent.ui.system.icons.regular.CardUi
60+
import fluent.ui.system.icons.regular.Eye
61+
import fluent.ui.system.icons.regular.EyeOff
5862
import fluent.ui.system.icons.regular.Image
5963

6064
object MifosIcons {
@@ -105,4 +109,9 @@ object MifosIcons {
105109

106110
val UploadId = FluentIcons.Regular.CardUi
107111
val Image = FluentIcons.Regular.Image
112+
113+
val Eye = FluentIcons.Regular.Eye
114+
val EyeOff = FluentIcons.Regular.EyeOff
115+
val EyeFilled = FluentIcons.Filled.Eye
116+
val ErrorCircle = FluentIcons.Filled.ErrorCircle
108117
}

feature/auth/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ android {
2323
kotlin {
2424
sourceSets {
2525
commonMain.dependencies {
26+
implementation(projects.core.ui)
2627
implementation(compose.material3)
2728
implementation(compose.foundation)
2829
implementation(compose.ui)

feature/auth/src/commonMain/composeResources/values/strings.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,16 @@
6161
<string name="error_enter_user_name">Please enter your user name</string>
6262
<string name="error_enter_country">Please enter your country</string>
6363

64+
65+
<string name="feature_sign_in_title">Sign in</string>
66+
<string name="feature_sign_in_sub_title">Enter your email and password to log in </string>
67+
<string name="feature_sign_in_username_label">Username or Email</string>
68+
<string name="feature_sign_in_password_label">Password</string>
69+
<string name="feature_sign_in_forgot_password">Forgot Password ?</string>
70+
<string name="feature_sign_in_Sign_in">Sign in</string>
71+
<string name="feature_sign_in_dont_have_an_account">Don’t have an account?</string>
72+
<string name="feature_sign_in_sign_up">Sign up!</string>
73+
<string name="feature_sign_in_username_error">Email address not found</string>
74+
<string name="feature_sign_in_password_error">Your password is not correct!</string>
75+
6476
</resources>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2025 Mifos Initiative
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*
8+
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
9+
*/
10+
@file:Suppress("MatchingDeclarationName")
11+
12+
package org.mifos.mobile.feature.auth.login
13+
14+
import androidx.navigation.NavController
15+
import androidx.navigation.NavGraphBuilder
16+
import androidx.navigation.NavOptions
17+
import kotlinx.serialization.Serializable
18+
import org.mifos.mobile.core.ui.composableWithStayTransitions
19+
20+
@Serializable
21+
data object LoginRoute
22+
23+
@Suppress("UnusedParameter")
24+
fun NavController.navigateToLogin(navOptions: NavOptions? = null) {
25+
this.navigate(route = LoginRoute, navOptions = navOptions)
26+
}
27+
28+
@Suppress("UnusedParameter")
29+
fun NavGraphBuilder.loginDestination(
30+
navigateToRegisterScreen: () -> Unit,
31+
navigateToPasscodeScreen: () -> Unit,
32+
) {
33+
composableWithStayTransitions<LoginRoute> {
34+
LoginScreen(
35+
navigateToRegisterScreen = navigateToRegisterScreen,
36+
navigateToPasscodeScreen = navigateToPasscodeScreen,
37+
)
38+
}
39+
}

0 commit comments

Comments
 (0)