From 5f25b5148788b5d644b75e285247d7fef00148be Mon Sep 17 00:00:00 2001 From: dankito Date: Sun, 25 Aug 2024 04:27:04 +0200 Subject: [PATCH] Showing AddAccountDialog on click on FloatingActionButton --- .../composeResources/drawable/visibility.png | Bin 0 -> 2087 bytes .../drawable/visibility_off.png | Bin 0 -> 2280 bytes .../kotlin/net/codinux/banking/ui/App.kt | 50 ++++++--- .../ui/composables/TransactionsList.kt | 8 +- .../banking/ui/dialogs/AddAccountDialog.kt | 97 ++++++++++++++++++ .../banking/ui/forms/OutlinedTextField.kt | 67 ++++++++++++ .../banking/ui/forms/PasswordTextField.kt | 46 +++++++++ .../banking/ui/forms/RoundedCornersCard.kt | 16 +++ .../net/codinux/banking/ui/service/Colors.kt | 5 + 9 files changed, 268 insertions(+), 21 deletions(-) create mode 100644 composeApp/src/commonMain/composeResources/drawable/visibility.png create mode 100644 composeApp/src/commonMain/composeResources/drawable/visibility_off.png create mode 100644 composeApp/src/commonMain/kotlin/net/codinux/banking/ui/dialogs/AddAccountDialog.kt create mode 100644 composeApp/src/commonMain/kotlin/net/codinux/banking/ui/forms/OutlinedTextField.kt create mode 100644 composeApp/src/commonMain/kotlin/net/codinux/banking/ui/forms/PasswordTextField.kt create mode 100644 composeApp/src/commonMain/kotlin/net/codinux/banking/ui/forms/RoundedCornersCard.kt diff --git a/composeApp/src/commonMain/composeResources/drawable/visibility.png b/composeApp/src/commonMain/composeResources/drawable/visibility.png new file mode 100644 index 0000000000000000000000000000000000000000..1fb3666725ad0dae69dc4d4a9bfef03b09147226 GIT binary patch literal 2087 zcma)-Ydq5n1IPbc!;G?qQFPokx5JTpO&Jc3g(siY95q z<9b|%R8B4#CAqZ4CzrXlLMD#q{qy-e&x_yh`{wuN_v)MM>TJIsb{GZ#zbK53hs{c#G98vn)n z<68BjExN3(QgUr(xWZBrx?!KCbOsPCPJwPfFj`v9j{Jy~zCsCWUG3s3Xhl_BZf_|( zeGCc%B~tpJfko|PD>YSPa30IxH&^JJ6sxcE3<)`~kw$v#)|dY_3D>BZJTDlAnUNFS zYL=@_c3%}M1wgiAw;QkWC8|oEVpk62Mci=S4LbpJ(qw8Z3wfS8O`vxPZt>#8!{vUv zMbKVn4okE!1ZlM;nfn+2N@B=vBYpaIOezy+x8AaY6Q;om!D@c#$a0=em<#b;=x}L_ za%AkQN09Fy+Qk%qoH&rMFn(?2kc8*N??^R3zrBrGog7_A#eUsT{CzoxF0X*LLYYRA zg7#fg$w&LvW4fZeSNa?oCkp$^sa-fr&*k&a&wyeQzV)HS%s~uxf+$HhJ-Q%6sHkE^P=pcM0;QqOz zpgTNi( z=v?JQX_5e!(=r)0TK(*^`GxH#{&fjs@mYEfI0|IjisALhcckJouVHF!T&lR?{o@uR zi$f}Qwr8{-De zE>D>sJ3%p88B!q0#irNll!k$Utt_h76_MX9-%zh|ulFNK^*V%A>5D55A*|UKttlv8 zoK0iF>4^bczNWd}-OhrayU*8?$xwzEcf<%%WOXwy7r67CUR&sY%1lrkoU3*olR6l3 zfQHvh9dyWkVWbtdNS5SzXdyA&5fTuxcU`IbLP!P@H;?T0y!*i*9ka6O3|?M&wv2kJ>^pvA8D5ku z;mk|y=f6-wMG7^{grbBaFc4OT;jvWtg4al*l%BH{Q9ctHMKiMp4I*( zRf={9)huzm?hdMTl%4<4L{(Hf;*4Pw7v!=fqy_o4&u;td-KW8YDBS%^v?p>ZfO8vob3reV| zXWK7cw1(WvRP9gSLhPO)q_M^aR-}9herYj28c;BnNwGq#lB(Pz^~zQy@o&4M9iJ(% zdhQIO=<6ole|b;`sAn(e)I~1$zWib&hAV!Hr>?CFE(6UMsnlz~FObgtHvy&G8C zg)H}#*Ns`YWYCMRxe>vsj}6O`V7iqK62GYgGTG&~%r+sSkGJ}>P8_nf+$>k)%8fTZ zK|!Qt@%K#!A04PnjQ`u*+o`B##&R;in}`n&mSnnJ&w1JN3D! zEyu$xZ@YSrveb-~TRq%clg);FADW0aAyt<&&^E^)X?zQXjDjB2n|k5S8_}53X`*Wj zC#I*zYw<90je;iPAaF)GXY3@$4u^Zj4{fR`scEY3umJao&AWe7HwarwrEN4i$~^Uf z$nzsE`}V6_PxQ$ADz;?Bw6!QEDJ|Sxd*Aa>w#&EGoTK1$s@ZDy@6k4r%%(hD2ND?E j4FA7$`9F=Co<~Ulxr@pQLoUzn$sPa*w$3=VjUV+N=E&tK literal 0 HcmV?d00001 diff --git a/composeApp/src/commonMain/composeResources/drawable/visibility_off.png b/composeApp/src/commonMain/composeResources/drawable/visibility_off.png new file mode 100644 index 0000000000000000000000000000000000000000..5be7f70304d9a392cfee960f751f47e0aa8dc95d GIT binary patch literal 2280 zcmVP)Px-qDe$SRCr$PoojO2HV}XpvhPvlBylbh%W-F-Tg16UM?d0(%Jd#pP7>u5?My47 zSw3tC1h5Z)q}u^!GI^N9W53W9okIn%uo6@N6~Mw0Sh)LY0TsZ) z5?HwVY5^6%!V*}x`)UCdz`_z(xO=t*Y&P5Vc?Gv$Kkq&+Jm&vZ_bdP?e0v4oapu;- zLxoUI2S@;}@P}?IgqZ+rw%fJ+yVHFCsu0RRh+05M^DBfhLU&sU0^kUL4tKQqb$bJ6 zSYuyjfM1O1{tVFmKK#PJANya!u#VQY{|2iSe1m`B*fhKL?=S6&TEOl7_RG&nZ8!ri z>5ewJXcgk5N(mwh zf(k&6@HG%JGiGs8rRYx$K@7kZzPnCoqCANuD1>rhFxZ!5;q0veEj+L`7_eadYRti$ z{<>?LMpX6|1CSKwI4)yO2tU^BqY9g_^p(zP?bAnf#@RS9BE5z8OhUYm8wMH~w(tZgD6m-oT+G1X}XO@igQdXAQ7eu~B$`Otv!O7{zsd}QI zf|u3}3D$$Cl?4H$%+^skjQbF`);1R|5qvSw~n6k2OW0LFqD zzhcxbS{?v$jfnx(SOTS3`^O!b6QvZ4xgd|MfB|6KZ6N@cyX_?Aqe#|57Eo$Eb0VVg zw-lGIdt_-U7o^cZU%pxwEv?k_S-UNn!~R2)SV>Suu!>F_nmsK3XzyUx-Y|LD`3r zX31E52-dD1zJC5q_4zGx9#Iz;1u$y3U@0QGXi@5(__-1SNNQPb_uOJ-YFtz?E@1^v z;i;;m+sDqNm8E%%Lu4t06~GVo1(Jk+bR8oiAGZ%qIhrgsNha-f&WRi}n`$NFK`rLI zx$?oZV+VMMANtlQ2URg3lMj}V6mj`5p?Ekt)^5Ib8nD(*_C-I_@3USkkpOVgZ|}F? zy)ENGS!k+?+{y5T|9q#!61eRP#>>hrSOA!5cKf-2fyw?cyjL^n5}9!f(8piFj0^7l}&P z+7Y1)YT=_yRW4|Np@e{siz}%p1ZV#zw&5OKgM0Gba~`^FiNsz=NwgAyAolr1T#(-g z&u0fSTk(E+j@yxB*BKD9g`aH!t}w!R0>N%ha{En}|1~^E^8=R2uC_`bXvPwIrYL|mLh8-|ihNr|4?Wvb`A)$0`M$Cen^I3 zfe_r91U5BRqco~s0yH$(p0r03PJ_oNN5QN6@aIrDF`{cA7YkJ0R$v7rzKPX5!JkaFv>G7 zL)Dz1we!;Q$wf#s5mk7|0g7#k-DP_fB^t+VOqk`7`T(1AW#7?0rU`3 zdql;;Z%ZtK{_CxsC4?ZTgkJ$DRmy{)7Jdbw1mL)%8>!FtyR0rK0|J)IB@1q-s|p|k zK#4~yfD%&7Xrlti5MGH#D}WMG%xI$m$PiwMNB;$TtG=u=VQ|U-0000>(emptyList()) } @@ -37,12 +41,28 @@ fun App() { setTransaction(bankService.getTransactions()) } - MaterialTheme(typography = typography) { - Column( - Modifier.fillMaxWidth().fillMaxHeight().background(color = Colors.Zinc100), - horizontalAlignment = Alignment.CenterHorizontally - ) { - TransactionsList(transactions) + MaterialTheme(colors = colors, typography = typography) { + Box { + Column( + Modifier.fillMaxWidth().fillMaxHeight().background(color = Colors.Zinc100), + horizontalAlignment = Alignment.CenterHorizontally + ) { + TransactionsList(transactions) + } + + Row(Modifier.align(Alignment.BottomEnd)) { + FloatingActionButton( + shape = CircleShape, + modifier = Modifier.offset((-12).dp, (-12).dp), + onClick = { showAddAccountDialog = true } + ) { + Icon(Icons.Filled.Add, contentDescription = "Add a bank account") + } + } + + if (showAddAccountDialog) { + AddAccountDialog { showAddAccountDialog = false } + } } } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/TransactionsList.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/TransactionsList.kt index af5e5da..02bae20 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/TransactionsList.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/TransactionsList.kt @@ -4,8 +4,6 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.Card import androidx.compose.material.Divider import androidx.compose.material.MaterialTheme import androidx.compose.material.Text @@ -23,6 +21,7 @@ import kotlinx.datetime.LocalDate import net.codinux.banking.client.model.AccountTransaction import net.codinux.banking.client.model.Amount import net.codinux.banking.ui.extensions.toBigDecimal +import net.codinux.banking.ui.forms.RoundedCornersCard import net.codinux.banking.ui.service.Colors import net.codinux.banking.ui.service.DI import org.jetbrains.compose.ui.tooling.preview.Preview @@ -51,10 +50,7 @@ fun TransactionsList(transactions: List) { val monthTransactions = groupedByMonth[month].orEmpty().sortedByDescending { it.valueDate } - Card( - shape = RoundedCornerShape(12.dp), // Rounded corners - elevation = 2.dp // Shadow elevation - ) { + RoundedCornersCard { Column(Modifier.background(Color.White)) { // LazyColumn inside LazyColumn is not allowed monthTransactions.forEachIndexed { index, transaction -> TransactionListItem(transaction, if (index % 2 == 1) Colors.Zinc100_50 else Color.Transparent) diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/dialogs/AddAccountDialog.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/dialogs/AddAccountDialog.kt new file mode 100644 index 0000000..6edcbf4 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/dialogs/AddAccountDialog.kt @@ -0,0 +1,97 @@ +package net.codinux.banking.ui.dialogs + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Close +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.compose.ui.window.Dialog +import net.codinux.banking.ui.forms.OutlinedTextField +import net.codinux.banking.ui.forms.PasswordTextField +import net.codinux.banking.ui.forms.RoundedCornersCard +import net.codinux.banking.ui.service.Colors + +@Composable +fun AddAccountDialog( + onDismiss: () -> Unit, +) { + var bankCode by remember { mutableStateOf("") } + var loginName by remember { mutableStateOf("") } + var password by remember { mutableStateOf("") } + + val isRequiredDataEntered by remember(bankCode, loginName, password) { + derivedStateOf { bankCode.length == 8 && loginName.length > 3 && password.length > 3 } + } + + val coroutineScope = rememberCoroutineScope() + + Dialog(onDismissRequest = onDismiss) { + RoundedCornersCard { + Column(Modifier.background(Color.White).padding(8.dp)) { + + Row(Modifier.fillMaxWidth()) { + Text( + "Bank Konto hinzufügen", + color = Color.Black, + fontSize = 20.sp, + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(top = 8.dp, bottom = 16.dp).weight(1f) + ) + + TextButton(onDismiss, colors = ButtonDefaults.buttonColors(contentColor = Colors.Zinc700, backgroundColor = Color.Transparent)) { + Icon(Icons.Filled.Close, contentDescription = "Close dialog", Modifier.size(32.dp)) + } + } + + OutlinedTextField( + value = bankCode, + onValueChange = { bankCode = it }, + label = { Text("Bank (Suche mit Name, Bankleitzahl oder Ort)") }, + singleLine = true, + modifier = Modifier.fillMaxWidth() + ) + + Spacer(modifier = Modifier.height(24.dp)) + + Text("Online-Banking Zugangsdaten", color = Colors.CodinuxSecondaryColor) + + Spacer(modifier = Modifier.height(12.dp)) + + OutlinedTextField( + value = loginName, + onValueChange = { loginName = it }, + label = { Text("Login Name") }, + singleLine = true, + modifier = Modifier.fillMaxWidth() + ) + + Spacer(modifier = Modifier.height(12.dp)) + + PasswordTextField(password) { password = it } + + Spacer(modifier = Modifier.height(16.dp)) + + Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) { + TextButton(onClick = onDismiss) { + Text("Abbrechen") + } + + Spacer(Modifier.width(8.dp)) + + TextButton( + onClick = onDismiss, + enabled = isRequiredDataEntered + ) { + Text("Hinzufügen") + } + } + } + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/forms/OutlinedTextField.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/forms/OutlinedTextField.kt new file mode 100644 index 0000000..6280fea --- /dev/null +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/forms/OutlinedTextField.kt @@ -0,0 +1,67 @@ +package net.codinux.banking.ui.forms + +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.LocalTextStyle +import androidx.compose.material.MaterialTheme +import androidx.compose.material.TextFieldDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.input.VisualTransformation +import net.codinux.banking.ui.service.Colors + +@Composable +fun OutlinedTextField( + value: String, + onValueChange: (String) -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + readOnly: Boolean = false, + textStyle: TextStyle = LocalTextStyle.current, + label: @Composable (() -> Unit)? = null, + placeholder: @Composable (() -> Unit)? = null, + leadingIcon: @Composable (() -> Unit)? = null, + trailingIcon: @Composable (() -> Unit)? = null, + isError: Boolean = false, + visualTransformation: VisualTransformation = VisualTransformation.None, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + keyboardActions: KeyboardActions = KeyboardActions.Default, + singleLine: Boolean = false, + maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE, + minLines: Int = 1, + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, + shape: Shape = MaterialTheme.shapes.small, +// colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors() // TODO: merge +) { + val textFieldColors = TextFieldDefaults.outlinedTextFieldColors( + focusedBorderColor = Colors.CodinuxSecondaryColor, + focusedLabelColor = Colors.CodinuxSecondaryColor // does not work + ) + + androidx.compose.material.OutlinedTextField( + value = value, + onValueChange = onValueChange, + modifier = modifier, + enabled = enabled, + readOnly = readOnly, + textStyle = textStyle, + label = label, + placeholder = placeholder, + leadingIcon = leadingIcon, + trailingIcon = trailingIcon, + isError = isError, + visualTransformation = visualTransformation, + keyboardOptions = keyboardOptions, + keyboardActions = keyboardActions, + singleLine = singleLine, + maxLines = maxLines, + minLines = minLines, + interactionSource = interactionSource, + shape = shape, + colors = textFieldColors + ) +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/forms/PasswordTextField.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/forms/PasswordTextField.kt new file mode 100644 index 0000000..9792446 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/forms/PasswordTextField.kt @@ -0,0 +1,46 @@ +package net.codinux.banking.ui.forms + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.Icon +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.unit.dp +import bankmeister.composeapp.generated.resources.Res +import bankmeister.composeapp.generated.resources.visibility +import bankmeister.composeapp.generated.resources.visibility_off +import org.jetbrains.compose.resources.imageResource + +@Composable +fun PasswordTextField(password: String = "", label: String = "Passwort", onChange: (String) -> Unit) { + + var passwordVisible by remember { mutableStateOf(false) } + + OutlinedTextField( + value = password, + onValueChange = { onChange(it) }, + label = { Text(label) }, + singleLine = true, + modifier = Modifier.fillMaxWidth(), + visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), + trailingIcon = { + val visibilityIcon = if (passwordVisible) { + Res.drawable.visibility_off + } else { + Res.drawable.visibility + } + Icon( + bitmap = imageResource(visibilityIcon), + contentDescription = if (passwordVisible) "Hide password" else "Show password", + modifier = Modifier.size(24.dp).clickable { passwordVisible = !passwordVisible } + ) + }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password) + ) +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/forms/RoundedCornersCard.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/forms/RoundedCornersCard.kt new file mode 100644 index 0000000..c9bcf42 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/forms/RoundedCornersCard.kt @@ -0,0 +1,16 @@ +package net.codinux.banking.ui.forms + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Card +import androidx.compose.runtime.Composable +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + +@Composable +fun RoundedCornersCard(cornerSize: Dp = 12.dp, shadowElevation: Dp = 2.dp, content: @Composable () -> Unit) { + Card( + shape = RoundedCornerShape(cornerSize), // Rounded corners + elevation = shadowElevation, // Shadow elevation + content = content + ) +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/Colors.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/Colors.kt index 72abca4..430787e 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/Colors.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/Colors.kt @@ -4,6 +4,11 @@ import androidx.compose.ui.graphics.Color object Colors { + val CodinuxPrimaryColor = Color(30, 54, 78) + + val CodinuxSecondaryColor = Color(251, 187, 33) + + val Zinc100 = Color(244, 244, 245) val Zinc100_50 = Zinc100.copy(alpha = 0.5f)