- created custom text block, dropdown,

- created extract, goals and block card screen.
- generated tests for design system components.
- updated restore password and home screens to 17/11 design.
This commit is contained in:
2025-12-03 15:28:10 +01:00
parent 8201bff0a7
commit 62ffc9ef7c
53 changed files with 3070 additions and 882 deletions

View File

@@ -4,4 +4,5 @@ export 'src/login/link_phone_builder.dart';
export 'src/login/phone_code_builder.dart';
export 'src/login/login_builder.dart';
export 'src/recover_password/recover_password_builder.dart';
export 'src/device_sign_up/device_signup_builder.dart';
export 'src/device_sign_up/device_signup_builder.dart';
export 'src/sign_up/signup_builder.dart';

View File

@@ -1,13 +1,18 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class AddKidScreen extends StatelessWidget {
class AddKidScreen extends ConsumerWidget {
final nextStep;
const AddKidScreen({super.key, required this.nextStep});
@override
Widget build(BuildContext context) {
Widget build(BuildContext context, WidgetRef ref) {
final theme = ref.watch(themePortProvider);
return Scaffold(
backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary),
body: Container(
margin: EdgeInsets.all(30),
child: Column(
@@ -17,13 +22,39 @@ class AddKidScreen extends StatelessWidget {
Text("Añade a tu peque", style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold)),
Text(
"Controla su gasto a la vez que aprende hábitos financieros responsables",
textAlign: TextAlign.center,
),
Container(
margin: EdgeInsets.symmetric(vertical: 30, horizontal: 50),
child: Row(
spacing: 10,
children: [
Column(children: [Text("1"), Text("2"), Text("3")]),
Stack(
children: [
Column(
spacing: 16,
children: List<Widget>.generate(3, (int index) =>
Container(
decoration: ShapeDecoration(
shape: CircleBorder(),
color: theme.getColorFor(ThemeCode.buttonPrimary)
),
width: 32,
height: 32,
child: Center(child: Text(
(index + 1).toString(),
style: TextStyle(
color: theme.getColorFor(ThemeCode.backgroundPrimary)
)
))
)
)
),
Divider(color: Colors.red, thickness: 4,),
],
),
Column(
spacing: 16,
children: [
Text("Crea su perfil"),
Text("Vincula su correa y su reloj"),
@@ -33,18 +64,28 @@ class AddKidScreen extends StatelessWidget {
],
),
),
Text("¡Y todo listo para que tenga su dinero!", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
Text("Recuerda que necesitas tener un Plan SaveFamily"),
Text(
"¡Y todo listo para que tenga su dinero!",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
letterSpacing: 0
)
),
Text(
"Recuerda que necesitas tener un Plan SaveFamily",
textAlign: TextAlign.center
),
Text(
"Si aún no lo tienes, puedes conseguirlo a través de nuestra web",
textAlign: TextAlign.center,
),
Spacer(flex: 8),
Container(
width: double.infinity,
child: FilledButton(
onPressed: nextStep,
child: Text("¡Empezar!"),
),
PrimaryButton(
onPressed: nextStep,
text: "¡Empezar!",
color: theme.getColorFor(ThemeCode.buttonPrimary)
),
],
),

View File

@@ -1,12 +1,16 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class ContactScreen extends StatelessWidget {
class ContactScreen extends ConsumerWidget {
const ContactScreen({super.key});
@override
Widget build(BuildContext context) {
Widget build(BuildContext context, WidgetRef ref) {
final theme = ref.watch(themePortProvider);
return Scaffold(
backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary),
body: Container(
margin: EdgeInsets.all(30),
child: Center(

View File

@@ -38,15 +38,13 @@ class DeviceSignupScreenState extends ConsumerState<DeviceSignupScreen>{
final theme = ref.watch(themePortProvider);
final continueBtn = Container(
padding: EdgeInsets.all(24),
color: theme.getColorFor(ThemeCode.backgroundPrimary),
child: FilledButton(
child: PrimaryButton(
onPressed: ()=>{setState(() {
currentStep++;
})},
child: Container(
width: double.infinity,
child: Expanded(child: Center(child: Text("Continuar"))))
text: "Continuar",
color: theme.getColorFor(ThemeCode.buttonPrimary)
)
);

View File

@@ -16,7 +16,8 @@ class CreateProfileScreen extends ConsumerWidget {
children: [
Text(
"Comienza con un peque; luego podrás agregar más",
style: TextStyle(fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500, letterSpacing: 0),
),
CustomTextField(
label: "Nombre",
@@ -26,30 +27,41 @@ class CreateProfileScreen extends ConsumerWidget {
label: "Apellidos",
hint: "Apellidos",
),
Row(
spacing: 10,
Column(
spacing: 8,
children: [
Expanded(
child: CustomTextField(
numeric: true,
label: "Fecha de nacimiento",
hint: "DD",
length: 2,
Align(
alignment: Alignment.bottomLeft,
child: Text(
"Fecha de nacimiento",
style: TextStyle(fontSize: 14, letterSpacing: 0),
),
),
Expanded(
child: CustomTextField(
numeric: true,
hint: "MM",
length: 2,
),
),
Expanded(
child: CustomTextField(
numeric: true,
hint: "AAAA",
length: 4,
),
Row(
spacing: 10,
children: [
Expanded(
child: CustomTextField(
numeric: true,
hint: "DD",
length: 2,
),
),
Expanded(
child: CustomTextField(
numeric: true,
hint: "MM",
length: 2,
),
),
Expanded(
child: CustomTextField(
numeric: true,
hint: "AAAA",
length: 4,
),
),
],
),
],
),
@@ -57,13 +69,15 @@ class CreateProfileScreen extends ConsumerWidget {
label: "Dirección completa",
hint: "Nombre de la calle",
),
TextButton(
onPressed: () => {},
child: Text(
"Cambiar dirección",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18, color: theme.getColorFor(ThemeCode.textPrimary)),
Align(
alignment: Alignment.topLeft,
child: CustomTextButton(
onPressed: () => {},
text: "Cambiar dirección",
size: 18,
weight: FontWeight.w500,
),
),
)
],
);
}

View File

@@ -37,8 +37,8 @@ class LinkWatchPreviousScreen extends ConsumerWidget{
children: [
Container(
decoration: ShapeDecoration(
shape: CircleBorder(side: BorderSide(color: theme.getColorFor(ThemeCode.backgroundSecondary))),
color: theme.getColorFor(ThemeCode.backgroundSecondary)
shape: CircleBorder(side: BorderSide(color: theme.getColorFor(ThemeCode.backgroundSecondary))),
color: theme.getColorFor(ThemeCode.backgroundSecondary)
),
width: 48,
height: 48,

View File

@@ -21,13 +21,69 @@ class LinkWatchScreenState extends ConsumerState<LinkWatchScreen>{
return Column(
spacing: 32,
children: [
Row(
Stack(
children: [
Text("Escanea la correa"),
Spacer(),
Text("Escanea el reloj")
Divider(
color: theme.getColorFor(ThemeCode.buttonPrimary),
thickness: 4,
indent: 93,
endIndent: 93,
height: 48,
),
if (widget.step==1)Divider(
color: theme.getColorFor(ThemeCode.backgroundSecondary),
thickness: 4,
indent: 186,
endIndent: 93,
height: 48,
),
Container(
padding: EdgeInsets.symmetric(horizontal: 69),
child: Row(
children: [
Container(
decoration: ShapeDecoration(
shape: CircleBorder(),
color: theme.getColorFor(ThemeCode.buttonPrimary)
),
width: 48,
height: 48,
child: Center(child: Text(
"1",
style: TextStyle(
color: theme.getColorFor(ThemeCode.backgroundPrimary),
fontSize: 24
)
))
),
Spacer(),
Container(
decoration: ShapeDecoration(
shape: CircleBorder(),
color: theme.getColorFor(widget.step==1 ? ThemeCode.backgroundSecondary : ThemeCode.buttonPrimary)
),
width: 48,
height: 48,
child: Center(child: Text(
"2",
style: TextStyle(
color: theme.getColorFor(widget.step==1 ? ThemeCode.textPrimary : ThemeCode.backgroundSecondary),
fontSize: 24
)
))
),
],
),
)
],
),
Row(children: [
Spacer(),
Text("Escanea la correa"),
Spacer(),
Text("Escanea el reloj"),
Spacer(),
]),
Container(
padding: EdgeInsets.all(40),
decoration: BoxDecoration(
@@ -36,24 +92,36 @@ class LinkWatchScreenState extends ConsumerState<LinkWatchScreen>{
),
child: SvgPicture.asset("assets/images/ui/qr.svg")
),
if (widget.step == 2)Text("O inserta el código del reloj"),
if (widget.step == 2)Row(
if (widget.step == 2)Column(
spacing: 16,
children: [
Expanded(child: CustomTextField(
hint: "XXXXXXXXXX",
)),
Expanded(child: FilledButton(
style: ButtonStyle(backgroundColor: WidgetStatePropertyAll<Color>(theme.getColorFor(ThemeCode.buttonSecondary))),
onPressed: ()=>{},
child: Expanded(child: Center(child: Text(
"Continuar con código",
style: TextStyle(fontSize: 16, letterSpacing: 0))))
))
Align(
alignment: Alignment.bottomLeft,
child: Text("O inserta el código del reloj"),
),
Row(
spacing: 16,
children: [
Expanded(child: CustomTextField(
hint: "XXXXXXXXXX",
)),
Expanded(child: PrimaryButton(
onPressed: ()=>{},
text: "Continuar con código",
size: 16,
color: theme.getColorFor(ThemeCode.buttonSecondary)
))
],
),
],
),
Text("Si no consigues vincular su correa o reloj"),
TextButton(onPressed: ()=>{}, child: Text("Contáctanos"))
Column(
spacing: 8,
children: [
Text("Si no consigues vincular su correa o reloj"),
CustomTextButton(onPressed: ()=>{}, text: "Contáctanos", weight: FontWeight.w500, size: 18)
],
)
],
);
}

View File

@@ -10,62 +10,69 @@ class LinkPhoneScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final theme = ref.watch(themePortProvider);
// TextEditingController phoneController = TextEditingController();
// String? phone;
return Scaffold(body: SafeArea(
child: Container(
margin: EdgeInsets.symmetric(horizontal: 24),
child: Expanded(
child: Center(
child: Column(
spacing: 48,
children: [
Spacer(flex: 8),
Text(
"¡Nos alegra mucho tenerte por aquí!",
style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
),
Text(
"Para poder entrar de forma segura, te vamos a enviar un código al teléfono",
),
Row(
spacing: 10,
children: [
DropdownMenu(
initialSelection: "es",
dropdownMenuEntries: List<DropdownMenuEntry>.generate(3, (
int index,
) {
return DropdownMenuEntry(
labelWidget: Icon(Icons.outlined_flag),
label: "es",
value: "es",
);
}),
),
Expanded(
child: CustomTextField(
label: "Teléfono móvil",
hint: "Teléfono",
numeric: true
)
),
],
),
SizedBox(
width: double.infinity,
child: FilledButton(
onPressed: () => navigationContract.pushTo('/phone_code'),
child: Text("Siguiente"),
return Scaffold(
backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary),
body: SafeArea(
child: Container(
margin: EdgeInsets.symmetric(horizontal: 24),
child: Expanded(
child: Center(
child: Column(
spacing: 48,
children: [
Spacer(flex: 8),
Text(
"¡Nos alegra mucho tenerte por aquí!",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 30, fontWeight: FontWeight.w500, letterSpacing: 0),
),
),
Spacer(flex: 10)
],
Text(
"Para poder entrar de forma segura, te vamos a enviar un código al teléfono",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 16, letterSpacing: 0),
),
Column(
spacing: 8,
children: [
Align(alignment: Alignment.bottomLeft, child: Text(
"Teléfono móvil",
style: TextStyle(fontSize: 14, letterSpacing: 0),
)),
Row(
spacing: 10,
children: [
CustomDropdown(
value: 0,
items: [Icon(Icons.outlined_flag), Icon(Icons.outlined_flag), Icon(Icons.outlined_flag)],
onChanged: (value)=> {},
width: 80,
),
Expanded(
child: CustomTextField(
hint: "Teléfono",
numeric: true
)
),
],
),
],
),
PrimaryButton(
onPressed: () => navigationContract.pushTo('/phone_code'),
text: "Siguiente",
color: theme.getColorFor(ThemeCode.buttonPrimary),
),
Spacer(flex: 10)
],
),
),
),
),
),
));
}
}

View File

@@ -12,70 +12,140 @@ class LoginScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final theme = ref.watch(themePortProvider);
bool passwordVisible = true;
return Scaffold(
body: Expanded(
child: Center(
child: Container(
margin: EdgeInsets.all(30),
final content = [
Column(
spacing: 8,
children: [
Icon(Icons.check, color: theme.getColorFor(ThemeCode.buttonPrimary), size: 50),
Text(
"¡Te damos la bienvenida!",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
),
],
),
Column(
spacing: 32,
children: [
Column(
spacing: 24,
children: [
CustomTextField(
hint: "Nombre de usuario",
label: "Nombre de usuario",
),
Column(
spacing: 12,
children: [
CustomTextField(
showPassword: passwordVisible,
label: "Contraseña",
hint: "********"
),
Align(
alignment: Alignment.topLeft,
child: CustomTextButton(
text: "¿Has olvidado la contraseña?",
onPressed: () =>
navigationContract.pushTo('/recover_password'),
size: 16,
)),
],
)
],
),
PrimaryButton(
onPressed: () => navigationContract.goTo('/main/home'),
text: "Iniciar sesión",
color: theme.getColorFor(ThemeCode.buttonPrimary)
),
Container(
padding: EdgeInsets.only(top: 24),
child: Column(
spacing: 10,
spacing: 24,
children: [
Icon(Icons.check, color: Color(0xFF329e95), size: 50),
Text(
"¡Te damos la bienvenida!",
style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
),
CustomTextField(
hint: "Nombre de usuario",
label: "Nombre de usuario",
),
CustomTextField(
showPassword: passwordVisible,
label: "Contraseña",
hint: "********"
),
TextButton(
onPressed: () =>
navigationContract.pushTo('/recover_password'),
child: Text("¿Has olvidado la contraseña?"),
),
FilledButton(
onPressed: () => navigationContract.pushTo('/main/home'),
child: Text("Iniciar sesión"),
),
Stack(children: [Divider(), Text("o continúa con")]),
Stack(children: [
Divider(endIndent: 74, indent: 74),
Align(
alignment: Alignment.center,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 14),
color: theme.getColorFor(ThemeCode.backgroundPrimary),
child: Text("o continúa con"),
)
)
]),
Row(
spacing: 20,
children: [
OutlinedButton(
Spacer(),
SecondaryButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => LoadingGoogleScreen(),
),
),
child: Text("Google", semanticsLabel: "Google"),
radius: 16,
padding: 44,
text: "Google",
label: "Google",
),
OutlinedButton(
onPressed: () => {},
child: Icon(Icons.apple, semanticLabel: "Apple"),
SecondaryButton(
onPressed: ()=>{},
radius: 16,
padding: 44,
icon: Icons.apple,
label: "Apple",
),
Spacer(),
],
),
Text("¿No tienes cuenta?"),
TextButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (_) => SignupScreen()),
),
child: Text("Crear una ahora"),
),
],
),
),
),
Column(
spacing: 8,
children: [
Text(
"¿No tienes cuenta?",
style: TextStyle(fontSize: 18, letterSpacing: 0)
),
TextButton(
onPressed: () => navigationContract.goTo('/signup'),
child: Text(
"Crear una ahora",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500, letterSpacing: 0)
)
),
],
)
],
),
];
return Scaffold(
backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary),
body: Expanded(
child: Center(
child: Container(
margin: EdgeInsets.all(30),
child: ListView.separated(
itemBuilder: (BuildContext context, int index) {
return content[index];
},
separatorBuilder: (BuildContext context, int index) {
return Divider(color: Colors.transparent, height: 48);
},
itemCount: content.length,
),
),
)
)
);
}
}

View File

@@ -1,4 +1,6 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:navigation/navigation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
@@ -15,64 +17,87 @@ class PhoneCodeScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final theme = ref.watch(themePortProvider);
return Scaffold(
backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary),
body: Container(
margin: EdgeInsets.all(30),
child: Expanded(
child: Center(
child: Column(
spacing: 15,
spacing: 48,
children: [
Spacer(flex: 8),
Text(
"Conéctate",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30),
),
Text.rich(
TextSpan(
text: "Hemos enviado el código al ",
children: [
Column(
spacing: 24,
children: [
Text(
"Conéctate",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30),
),
Text.rich(
TextSpan(
// text: widget.phone,
style: TextStyle(fontWeight: FontWeight.bold),
text: "Hemos enviado el código al ",
children: [
TextSpan(
// text: widget.phone,
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
],
),
),
Text("Introduce el código aquí"),
Row(
spacing: 8,
children: List<Widget>.generate(6, (int i) {
return Expanded(
child: TextField(
focusNode: focusNodes[i],
keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
textAlign: TextAlign.center,
decoration: InputDecoration(
hintText: "0",
counterText: "",
border: OutlineInputBorder(),
),
maxLength: 1,
onChanged: (String value) => {
value != ""
? focusNodes[i + 1].requestFocus()
: focusNodes[i - 1].requestFocus(),
},
),
);
}),
),
],
),
Text("Introduce el código aquí"),
Row(
spacing: 20,
children: List<Widget>.generate(6, (int i) {
return Expanded(
child: TextField(
focusNode: focusNodes[i],
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: "0",
counterText: "",
border: OutlineInputBorder(),
Column(
spacing: 24,
children: [
PrimaryButton(
onPressed: () => {navigationContract.pushTo('/login')},
text: "Entrar",
color: theme.getColorFor(ThemeCode.buttonPrimary),
),
Column(
spacing: 8,
children: [
Text(
"¿No lo has recibido?",
style: TextStyle(fontSize: 18, letterSpacing: 0, height: 1.5),
),
maxLength: 1,
onChanged: (String value) => {
value != ""
? focusNodes[i + 1].requestFocus()
: focusNodes[i - 1].requestFocus(),
},
),
);
}),
),
FilledButton(
onPressed: () => {navigationContract.pushTo('/login')},
child: Text("Entrar"),
),
Text("¿No lo has recibido?"),
TextButton(
onPressed: () => {},
child: Text(
"Volver a intentarlo",
style: TextStyle(fontWeight: FontWeight.bold),
),
CustomTextButton(
onPressed: () => {},
text: "Volver a intentarlo",
size: 18,
weight: FontWeight.w500,
),
],
)
],
),
Spacer(flex: 10),
],

View File

@@ -31,8 +31,9 @@ class WelcomeScreenState extends ConsumerState{
final theme = ref.watch(themePortProvider);
return Scaffold(
backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary),
body: Container(
padding: EdgeInsets.symmetric(horizontal: 24),
padding: EdgeInsets.only(top: 24),
child: Center(
child: Column(
spacing: 48,
@@ -42,7 +43,11 @@ class WelcomeScreenState extends ConsumerState{
Column(
spacing: 24,
children: [
StepIndicator(max: 3, current: currentStep+1, color: theme.getColorFor(ThemeCode.buttonSecondary)),
StepIndicator(
max: 3,
current: currentStep+1,
color: theme.getColorFor(ThemeCode.buttonSecondary)
),
generateButtons(theme, 3, currentStep+1)
]
),
@@ -56,29 +61,29 @@ class WelcomeScreenState extends ConsumerState{
Widget generateButtons(ThemePort theme, int max, int step){
if (step==max) {
return FilledButton(
style: ButtonStyle(
backgroundColor: WidgetStatePropertyAll<Color>(theme.getColorFor(ThemeCode.buttonPrimary))
),
return PrimaryButton(
onPressed: () => navigationContract.goTo('/link_phone'),
child: Expanded(child: Center(child: Text('Continuar')))
);
text: "Continuar",
color: theme.getColorFor(ThemeCode.buttonPrimary),
width: 324,
);
} else {
return Column(
spacing: 16,
children: [
FilledButton(
style: ButtonStyle(
backgroundColor: WidgetStatePropertyAll<Color>(theme.getColorFor(ThemeCode.buttonSecondary))
),
PrimaryButton(
onPressed: ()=>setState(() {
currentStep++;
}),
child: Expanded(child: Center( child: Text("Siguiente")))
text: "Siguiente",
color: theme.getColorFor(ThemeCode.buttonSecondary),
width: 324,
),
TextButton(
CustomTextButton(
onPressed: ()=>navigationContract.goTo('/link_phone'),
child: Text("Omitir")
text: "Omitir",
size: 18,
weight: FontWeight.w500,
)
],
);
@@ -97,37 +102,57 @@ class WelcomeScreenState extends ConsumerState{
Text(
"Aprende a gestionar su dinero",
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 30)
style: TextStyle(fontSize: 30, fontWeight: FontWeight.w500, letterSpacing: 0)
),
Text(
"Tu peque crea hábitos y se divierte mientras lo hace",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18)
style: TextStyle(fontSize: 18, letterSpacing: 0)
)
]
)
]
),
Column(
spacing: 48,
children: [
SvgPicture.asset("assets/images/ui/bienvenida_paso2.svg"),
Text("Tranquilidad en cada pago que hacen",
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 30)),
Text("Supervisa gastos, fija límites y acompáñalos en cada paso",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18)),
Column(
spacing: 16,
children: [
Text(
"Tranquilidad en cada pago que hace",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 30, fontWeight: FontWeight.w500, letterSpacing: 0)
),
Text(
"Supervisa sus gastos, fija límites y acompáñale en cada paso",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18, letterSpacing: 0)
),
],
)
],
),
Column(
spacing: 48,
children: [
SvgPicture.asset("assets/images/ui/bienvenida_paso3.svg"),
Text("Pagos fáciles y seguros en sus manos",
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 30)),
Text("Podrá pagar desde su reloj.\n Sin móvil ni efectivo",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18)),
Column(
spacing: 16,
children: [
Text(
"Pagos fáciles y seguros, en sus manos",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 30, fontWeight: FontWeight.w500, letterSpacing: 0)
),
Text(
"Podrá pagar desde su reloj.\n Sin móvil ni efectivo",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18, letterSpacing: 0)
),
],
)
],
),
];

View File

@@ -1,84 +0,0 @@
import 'package:auth/src/recover_password/presentation/new_password_screen.dart';
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class EmailSentScreen extends ConsumerWidget {
final String email;
const EmailSentScreen({super.key, required this.email});
@override
Widget build(BuildContext context, WidgetRef ref) {
final theme = ref.watch(themePortProvider);
return Scaffold(
body: Container(
margin: EdgeInsets.all(30),
child: Center(
child: Column(
spacing: 20,
children: [
Spacer(flex: 8),
Text(
"Recuperar contraseña",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30),
),
Spacer(flex: 1),
Row(
spacing: 10,
children: [
Icon(
Icons.check,
color: theme.getColorFor(ThemeCode.buttonPrimary),
),
Text(
"Correo enviado correctamente",
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
Spacer(flex: 1),
Text(
"Revisa tu email y haz clic en el enlace para crear una nueva contraseña",
),
Text(
"Si no recibes el correo en unos minutos, revisa tu carpeta de spam o pulsa \"Reenviar correo\"",
),
Row(
spacing: 10,
children: [
Expanded(
child: OutlinedButton(
onPressed: () => {},
child: Text("Reenviar correo"),
),
),
Expanded(
child: FilledButton(
onPressed: () => {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (_) => NewPasswordScreen(),
// ),
// ),
},
style: ButtonStyle(
backgroundColor: WidgetStatePropertyAll<Color>(
theme.getColorFor(ThemeCode.buttonSecondary),
),
),
child: Text("Continuar"),
),
),
],
),
Spacer(flex: 10),
],
),
),
),
);
}
}

View File

@@ -42,104 +42,137 @@ class NewPasswordScreenState extends ConsumerState<NewPasswordScreen> {
final theme = ref.watch(themePortProvider);
return Scaffold(
backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary),
body: Container(
margin: EdgeInsets.all(30),
padding: EdgeInsets.all(24),
child: Center(
child: Column(
spacing: 10,
spacing: 48,
children: [
Spacer(flex: 4),
Text(
"Recuperar contraseña",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30),
),
CustomTextField(
showPassword: passwordVisible,
label: "Nueva contraseña",
hint: "********",
onChanged: (value) => {
setState(() {
password = value;
securityChecks = checkSecurity(value);
}),
},
),
CustomTextField(
showPassword: passwordVisible,
label: "Repetir contraseña",
hint: "********",
onChanged: (value) => {
setState(() {
equalPasswords = password == value;
}),
},
),
Row(
Spacer(),
Column(
spacing: 32,
children: [
securityChecks["min"]!
? Icon(
Icons.check,
color: theme.getColorFor(ThemeCode.buttonPrimary),
Text(
"Recuperar contraseña",
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 30, letterSpacing: 0),
),
Column(
spacing: 16,
children: [
CustomTextField(
showPassword: passwordVisible,
label: "Nueva contraseña",
hint: "********",
onChanged: (value) => {
setState(() {
password = value;
securityChecks = checkSecurity(value);
}),
},
),
CustomTextField(
showPassword: passwordVisible,
label: "Repetir contraseña",
hint: "********",
onChanged: (value) => {
setState(() {
equalPasswords = password == value;
}),
},
),
Column(
spacing: 4,
children: [
Row(
spacing: 8,
children: [
Icon(
Icons.check,
color: theme.getColorFor(securityChecks["min"]!
? ThemeCode.buttonPrimary
: ThemeCode.buttonSecondary),
),
Text("Al menos 8 caracteres", style: TextStyle(fontSize: 14)),
],
),
Row(
spacing: 8,
children: [
Icon(
Icons.check,
color: theme.getColorFor(securityChecks["capital"]!
? ThemeCode.buttonPrimary
: ThemeCode.buttonSecondary),
),
Text("Una mayúscula", style: TextStyle(fontSize: 14)),
],
),
Row(
spacing: 8,
children: [
Icon(
Icons.check,
color: theme.getColorFor(securityChecks["number"]!
? ThemeCode.buttonPrimary
: ThemeCode.buttonSecondary),
),
Text("Un número", style: TextStyle(fontSize: 14)),
],
),
Row(
spacing: 8,
children: [
Icon(
Icons.check,
color: theme.getColorFor(securityChecks["special"]!
? ThemeCode.buttonPrimary
: ThemeCode.buttonSecondary),
),
Text("Un carácter especial", style: TextStyle(fontSize: 14)),
],
),
],
)
],
),
Column(
spacing: 8,
children: [
Align(
alignment: Alignment.bottomLeft,
child: Text(
"Teléfono móvil",
style: TextStyle(fontSize: 14, letterSpacing: 0),
)
: Icon(
Icons.cancel_outlined,
color: theme.getColorFor(ThemeCode.buttonSecondary),
),
Text("Al menos 8 caracteres"),
),
Row(
spacing: 8,
children: [
CustomDropdown(
value: 0,
items: [Icon(Icons.outlined_flag), Icon(Icons.outlined_flag), Icon(Icons.outlined_flag)],
onChanged: (value)=> {},
width: 80,
),
Expanded(child: CustomTextField(
hint: "Teléfono",
numeric: true
))
]
),
],
)
],
),
Row(
children: [
securityChecks["capital"]!
? Icon(
Icons.check,
color: theme.getColorFor(ThemeCode.buttonPrimary),
)
: Icon(
Icons.cancel_outlined,
color: theme.getColorFor(ThemeCode.buttonSecondary),
),
Text("Una mayúscula"),
],
PrimaryButton(
onPressed: ()=>{navigationContract.goTo('/main/home')},
text: "Aceptar",
color: theme.getColorFor(ThemeCode.buttonPrimary)
),
Row(
children: [
securityChecks["number"]!
? Icon(
Icons.check,
color: theme.getColorFor(ThemeCode.buttonPrimary),
)
: Icon(
Icons.cancel_outlined,
color: theme.getColorFor(ThemeCode.buttonSecondary),
),
Text("Un número"),
],
),
Row(
children: [
securityChecks["special"]!
? Icon(
Icons.check,
color: theme.getColorFor(ThemeCode.buttonPrimary),
)
: Icon(
Icons.cancel_outlined,
color: theme.getColorFor(ThemeCode.buttonSecondary),
),
Text("Un carácter especial"),
],
),
Spacer(flex: 1),
FilledButton(
onPressed: ()=>{navigationContract.pushTo('/main/home')},
child: Container(
width: double.infinity,
padding: EdgeInsets.all(20),
child: Text("Aceptar"),
),
),
Spacer(flex: 4),
Spacer(),
],
),
),

View File

@@ -1,4 +1,4 @@
import 'package:auth/src/recover_password/presentation/email_sent_screen.dart';
import 'package:auth/src/recover_password/presentation/sent_screen.dart';
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:navigation/navigation.dart';
@@ -14,50 +14,85 @@ class RestorePasswordScreen extends ConsumerWidget {
final theme = ref.watch(themePortProvider);
return Scaffold(
backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary),
body: Container(
margin: EdgeInsets.all(30),
child: Center(
child: Column(
spacing: 30,
spacing: 48,
children: [
Spacer(flex: 8),
Text(
"Recuperar contaseña",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30),
),
Text(
"Introduce tu email para enviarte un enlace de recuperación",
),
CustomTextField(
label: "Correo electrónico",
hint: "Correo electrónico",
),
Row(
spacing: 20,
Column(
spacing: 32,
children: [
Expanded(
child: OutlinedButton(
onPressed: () => {Navigator.pop(context)},
child: Text("Volver"),
),
Text(
"Recuperar contaseña",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30),
),
Expanded(
child: FilledButton(
onPressed: () => {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => EmailSentScreen(email: ""),
),
),
},
style: ButtonStyle(
backgroundColor: WidgetStatePropertyAll<Color>(
theme.getColorFor(ThemeCode.buttonSecondary),
),
Text(
"Introduce tu email para enviarte un enlace de recuperación",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18, letterSpacing: 0),
),
],
),
Column(
spacing: 40,
children: [
CustomTextField(
label: "Correo electrónico",
hint: "Correo electrónico",
),
Column(
spacing: 8,
children: [
Align(
alignment: Alignment.bottomLeft,
child: Text(
"Teléfono móvil",
style: TextStyle(fontSize: 14, letterSpacing: 0),
)
),
child: Text("Enviar"),
),
Row(
spacing: 10,
children: [
CustomDropdown(
value: 0,
items: [Icon(Icons.outlined_flag), Icon(Icons.outlined_flag), Icon(Icons.outlined_flag)],
onChanged: (value)=> {},
width: 80,
),
Expanded(
child: CustomTextField(
hint: "Teléfono",
numeric: true
)
),
],
),
],
),
Row(
spacing: 20,
children: [
Expanded( child: SecondaryButton(
onPressed: () => {Navigator.pop(context)},
text: "Volver"
)),
Expanded( child: PrimaryButton(
onPressed: () => {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => SentScreen(format: "email"),
),
),
},
text: "Enviar",
size: 16,
color: theme.getColorFor(ThemeCode.buttonSecondary)
)),
],
),
],
),

View File

@@ -0,0 +1,98 @@
import 'package:auth/src/recover_password/presentation/new_password_screen.dart';
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class SentScreen extends ConsumerWidget {
final String format;
const SentScreen({
super.key,
required this.format
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final theme = ref.watch(themePortProvider);
return Scaffold(
backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary),
body: Container(
margin: EdgeInsets.all(24),
child: Center(
child: Column(
spacing: 48,
children: [
Spacer(flex: 8),
Text(
"Recuperar contraseña",
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 30, letterSpacing: 0),
),
Row(
spacing: 10,
children: [
Spacer(),
Icon(
Icons.check,
color: theme.getColorFor(ThemeCode.buttonPrimary),
),
Text(
format=="email"
?"Correo enviado correctamente"
:"SMS enviado correctamente",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
Spacer(),
],
),
Column(
spacing: 16,
children: [
Text(
format=="email"
?"Revisa tu email y haz clic en el enlace para crear una nueva contraseña."
:"Revisa tu móvil y sigue las instrucciones para crear una nueva contraseña.",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18, letterSpacing: 0),
),
Text(
format=="email"
?"Si no recibes el correo en unos minutos, revisa tu carpeta de spam o pulsa \"Reenviar correo\"."
:"Si no recibes el SMS en unos minutos, asegúrate de tener cobertura o pulsa \"Reenviar SMS \".",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 14, letterSpacing: 0),
),
],
),
Row(
spacing: 10,
children: [
Expanded( child: SecondaryButton(
onPressed: () => {},
text: format=="email"
?"Reenviar correo"
:"Reenviar SMS"
)),
Expanded(
child: PrimaryButton(
onPressed: ()=>Navigator.push(
context,
MaterialPageRoute(
builder: (_) => NewPasswordScreen(),
),
),
text: "Continuar",
color: theme.getColorFor(ThemeCode.buttonSecondary)
),
),
],
),
Spacer(flex: 10),
],
),
),
),
);
}
}

View File

@@ -69,7 +69,7 @@ class AccountCreatedScreen extends ConsumerWidget {
"Crea la cuenta de tu peque e ingresa su \nprimera paga para utilizarla con su reloj",
textAlign: TextAlign.center,
),
FilledButton(
PrimaryButton(
onPressed: () => {
if (kidAccount){
navigationContract.goTo('/main/home')
@@ -77,7 +77,8 @@ class AccountCreatedScreen extends ConsumerWidget {
navigationContract.pushTo('/device_signup')
}
},
child: Text("Continuar"),
text: "Continuar",
color: theme.getColorFor(ThemeCode.buttonPrimary)
),
Spacer(flex: 8),
],

View File

@@ -1,52 +1,100 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class SignupAddressScreen extends StatelessWidget {
class SignupAddressScreen extends ConsumerStatefulWidget {
const SignupAddressScreen({super.key});
@override
ConsumerState<SignupAddressScreen> createState() => SignupAddressScreenState();
}
class SignupAddressScreenState extends ConsumerState<SignupAddressScreen>{
late String country;
late int relation;
@override
void initState() {
relation = 0;
super.initState();
}
@override
Widget build(BuildContext context) {
return Column(
spacing: 24,
children: [
Row(
Column(
spacing: 8,
children: [
Expanded(child: CustomTextField(
label: "Fecha de nacimiento",
hint: "DD",
length: 2,
numeric: true,
Align(alignment: Alignment.bottomLeft, child: Text(
"Fecha de nacimiento",
style: TextStyle(fontSize: 14, letterSpacing: 0),
)),
Expanded(child: CustomTextField(
hint: "MM",
length: 2,
numeric: true,
)),
Expanded(child: CustomTextField(
hint: "AAAA",
length: 4,
numeric: true,
)),
]
Row(
spacing: 8,
children: [
Expanded(child: CustomTextField(
//label: "Fecha de nacimiento",
hint: "DD",
length: 2,
numeric: true,
)),
Expanded(child: CustomTextField(
hint: "MM",
length: 2,
numeric: true,
)),
Expanded(child: CustomTextField(
hint: "AAAA",
length: 4,
numeric: true,
)),
]
),
],
),
DropdownMenu(
width: double.infinity,
label: Text("¿Qué familiar eres?"),
dropdownMenuEntries: [
DropdownMenuEntry(label: "Padre", value: "Padre"),
DropdownMenuEntry(label: "Madre", value: "Madre"),
DropdownMenuEntry(label: "Tutor", value: "Tutor"),
Column(
spacing: 8,
children: [
Align(
alignment: Alignment.bottomLeft,
child: Text(
"¿Qué familiar eres?",
style: TextStyle(fontSize: 14, letterSpacing: 0),
),
),
CustomDropdown(
items: [Text("Padre"), Text("Madre"), Text("Tutor")],
hint: "¿Qué familiar eres?",
onChanged: (value)=>setState(() {
relation = value;
})
),
],
),
CustomTextField(label: "Dirección completa", hint: "Calle Gran Vía 30 6º, 28013"),
CustomTextField(label: "Ciudad", hint: "Ciudad"),
DropdownMenu(
dropdownMenuEntries: List<DropdownMenuEntry>.generate(3, (int index) {
return DropdownMenuEntry(value: "España", label: "España");
}),
hintText: "País",
width: double.infinity,
Column(
spacing: 8,
children: [
Align(
alignment: Alignment.bottomLeft,
child: Text(
"País",
style: TextStyle(fontSize: 14, letterSpacing: 0),
),
),
CustomDropdown(
items: [Text("España"), Text("Francia"), Text("Portugal")],
hint: "País",
onChanged: (value)=>setState(() {
country = value;
})
),
],
),
CustomTextField(label: "Nacionalidad", hint: "España"),
],

View File

@@ -0,0 +1,18 @@
import 'package:auth/src/sign_up/signup_screen.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:get_it/get_it.dart';
import 'package:navigation/navigation.dart';
class SignupBuilder {
const SignupBuilder();
Page<void> buildPage(BuildContext context, GoRouterState state) {
final NavigationContract navigationContract = GetIt.I<NavigationContract>();
return MaterialPage<void>(
key: state.pageKey,
child: SignupScreen(navigationContract: navigationContract),
);
}
}

View File

@@ -12,19 +12,22 @@ class SignupPersonalScreen extends StatelessWidget{
CustomTextField(label: "Nombre", hint: "Nombre"),
CustomTextField(label: "Apellidos", hint: "Apellidos"),
CustomTextField(label: "DNI", hint: "DNI"),
Row(children: [
DropdownMenu(
initialSelection: "es",
dropdownMenuEntries: List<DropdownMenuEntry>.generate(3, (int index){
return DropdownMenuEntry(labelWidget: Icon(Icons.outlined_flag), label: "es", value: "es");
})
),
Expanded(child: CustomTextField(
label: "Teléfono móvil",
hint: "123456789",
numeric: true
))
]),
Row(
spacing: 8,
children: [
/*CustomDropdown(
value: 0,
items: [Icon(Icons.outlined_flag), Icon(Icons.outlined_flag), Icon(Icons.outlined_flag)],
onChanged: (value)=> {},
width: 80,
),*/
Expanded(child: CustomTextField(
label: "Teléfono móvil",
hint: "123456789",
numeric: true
))
]
),
CustomTextField(label: "Correo electrónico", hint: "Correo electrónico"),
],
);

View File

@@ -1,4 +1,5 @@
import 'package:auth/src/widgets/layouts/form_step_layout.dart';
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:auth/src/sign_up/signup_address_screen.dart';
import 'package:auth/src/sign_up/signup_personal_screen.dart';
@@ -7,19 +8,31 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:get_it/get_it.dart';
import 'package:navigation/navigation.dart';
class SignupScreen extends ConsumerStatefulWidget {
SignupScreen({super.key});
import 'account_created_screen.dart';
ConsumerState<SignupScreen> createState() => SignupScreenState();
class SignupScreen extends ConsumerStatefulWidget {
NavigationContract navigationContract;
SignupScreen({
super.key,
required this.navigationContract
});
ConsumerState<SignupScreen> createState() => SignupScreenState(navigationContract);
}
class SignupScreenState extends ConsumerState<SignupScreen> {
late int currentStep;
late bool acceptTerms;
final NavigationContract navigationContract;
SignupScreenState(this.navigationContract);
@override
void initState() {
super.initState();
currentStep = 0;
acceptTerms = false;
}
@override
@@ -28,14 +41,50 @@ class SignupScreenState extends ConsumerState<SignupScreen> {
}
List<Widget> getSteps() {
final theme = ref.watch(themePortProvider);
return [
FormStepLayout(
title: "Crea tu usuario",
subtitle: "Nos aseguraremos de que la cuenta esté a nombre del adulto responsable",
supertitle: "Datos personales",
subtitle: "Con tu email y tu número podremos mantenerte siempre informado",
supertitle: "Usuario y contacto",
currentStep: 1,
numSteps: 3,
body: [SignupPersonalScreen()],
footer: [
Row(
spacing: 16,
children: [
Expanded(child: SecondaryButton(
onPressed: ()=>{},
text: "Atrás",
size: 16,
)),
Expanded(child: PrimaryButton(
onPressed: ()=>{setState(() {
currentStep++;
})},
text: "Siguiente",
size: 16,
color: theme.getColorFor(ThemeCode.buttonSecondary)
))
]
),
CheckboxListTile(
value: acceptTerms,
onChanged: (_) => setState(() {
acceptTerms = !acceptTerms;
}),
title: Text(
"Acepto los términos y condiciones",
style: TextStyle(fontSize: 16, letterSpacing: 0),
),
checkboxScaleFactor: 1.5,
contentPadding: EdgeInsets.zero,
activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
controlAffinity: ListTileControlAffinity.leading,
)
],
nextStep: ()=>{setState(() {
currentStep++;
})},
@@ -57,16 +106,19 @@ class SignupScreenState extends ConsumerState<SignupScreen> {
),
FormStepLayout(
title: "Identifícate",
subtitle: "Con tu email y tu número podremos mantenerte siempre informado",
subtitle: "Contraseña mínima de 8 caracteres, con una mayúscula, un número y un carácter especial",
supertitle: "Usuario y contacto",
currentStep: 3,
numSteps: 3,
body: [SignupUserScreen()],
nextStep: ()=>{GetIt.I<NavigationContract>().pushTo('/device_signup')},
nextStep: ()=>{setState(() {
currentStep++;
})},
previousStep: ()=>{setState(() {
currentStep--;
})},
),
AccountCreatedScreen(navigationContract: navigationContract, kidAccount: false)
];
}
}

View File

@@ -31,6 +31,7 @@ class FormStepLayout extends ConsumerWidget{
final theme = ref.watch(themePortProvider);
return Scaffold(
backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary),
body: SafeArea(child: SingleChildScrollView(child: Container(
color: theme.getColorFor(ThemeCode.backgroundPrimary),
padding: EdgeInsets.only(top: 40, left: 24, right: 24),
@@ -66,23 +67,25 @@ class FormStepLayout extends ConsumerWidget{
Widget navigationButtons(int currentStep, int numSteps, VoidCallback nextStep, VoidCallback previousStep, ThemePort theme) {
if (currentStep == numSteps){
return FilledButton(
return PrimaryButton(
onPressed: nextStep,
style: ButtonStyle(backgroundColor: WidgetStatePropertyAll<Color>(theme.getColorFor(ThemeCode.buttonPrimary))),
child: Expanded(child: Center(child: Text("Continuar")))
text: "Continuar",
color: theme.getColorFor(ThemeCode.buttonPrimary)
);
} else {
return Row(
spacing: 16,
children: [
Expanded(child: OutlinedButton(
Expanded(child: SecondaryButton(
onPressed: previousStep,
child: Expanded(child: Center(child: Text("Atrás")))
text: "Atrás",
size: 16,
)),
Expanded(child: FilledButton(
Expanded(child: PrimaryButton(
onPressed: nextStep,
style: ButtonStyle(backgroundColor: WidgetStatePropertyAll<Color>(theme.getColorFor(ThemeCode.buttonSecondary))),
child: Expanded(child: Center(child: Text("Siguiente")))
text: "Siguiente",
size: 16,
color: theme.getColorFor(ThemeCode.buttonSecondary)
))
]
);

View File

@@ -26,13 +26,10 @@ class DepositScreen extends ConsumerWidget {
padding: EdgeInsets.all(10),
child: Column(
children: [
FilledButton(
onPressed: () => {},
child: Container(
width: double.infinity,
padding: EdgeInsets.all(20),
child: Center(child: Text("Añadir dinero")),
),
PrimaryButton(
onPressed: ()=>{},
text: "Añadir dinero",
color: theme.getColorFor(ThemeCode.buttonPrimary)
),
TextButton(
onPressed: () => Navigator.pop(context),
@@ -82,6 +79,7 @@ class DepositScreen extends ConsumerWidget {
),
Text("Este dato aparecerá en el reloj del peque"),
CheckboxListTile(
contentPadding: EdgeInsets.zero,
title: Text('Paga semanal'),
controlAffinity: ListTileControlAffinity.leading,
value: reason == "weekly",
@@ -93,6 +91,7 @@ class DepositScreen extends ConsumerWidget {
activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
),
CheckboxListTile(
contentPadding: EdgeInsets.zero,
title: Text('Objetivo semanal cumplido'),
controlAffinity: ListTileControlAffinity.leading,
value: reason == "goal",
@@ -104,6 +103,7 @@ class DepositScreen extends ConsumerWidget {
activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
),
CheckboxListTile(
contentPadding: EdgeInsets.zero,
title: Text('Gastos extraordinarios'),
controlAffinity: ListTileControlAffinity.leading,
value: reason == "extraordinary",
@@ -115,6 +115,7 @@ class DepositScreen extends ConsumerWidget {
activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
),
CheckboxListTile(
contentPadding: EdgeInsets.zero,
title: Text('Otro'),
controlAffinity: ListTileControlAffinity.leading,
value: reason == "other",
@@ -153,6 +154,7 @@ class DepositScreen extends ConsumerWidget {
),
Text("Este dato aparecerá en el reloj del peque"),
CheckboxListTile(
contentPadding: EdgeInsets.zero,
title: Text('Ahora'),
controlAffinity: ListTileControlAffinity.leading,
value: program == false,
@@ -164,6 +166,7 @@ class DepositScreen extends ConsumerWidget {
activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
),
CheckboxListTile(
contentPadding: EdgeInsets.zero,
title: Text('Programar'),
controlAffinity: ListTileControlAffinity.leading,
value: program == true,

View File

@@ -0,0 +1,111 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:home/src/presentation/wallet_management_layout.dart';
import 'package:sf_shared/sf_shared.dart';
class ExtractScreen extends ConsumerWidget{
final Kid kid;
@override
ExtractScreen({
super.key,
required this.kid,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final theme = ref.watch(themePortProvider);
return WalletManagementLayout(
kid: kid,
children: [Container(
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(24)),
color: theme.getColorFor(ThemeCode.backgroundPrimary)
),
child: Column(
spacing: 24,
children: [
Column(
spacing: 8,
children: [
Align(alignment: Alignment.topLeft, child: Text(
"Retirar dinero de la cuenta",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500, letterSpacing: 0)
)),
Align(alignment: Alignment.topLeft, child: Text(
"Este dato aparecerá en el reloj del peque",
style: TextStyle(fontSize: 14, letterSpacing: 0)
))
],
),
CustomTextField(
label: "Selecciona la cantidad de dinero",
hint: "2€",
numeric: true,
),
Column(
spacing: 8,
children: [
Align(alignment: Alignment.topLeft, child: Text(
"Este es el mensaje fijado por defecto:",
style: TextStyle(fontSize: 16, letterSpacing: 0)
)),
Align(alignment: Alignment.topLeft, child: Text(
"\"Hemos quitado el dinero del reloj, ya no puedes pagar con él\"",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500, letterSpacing: 0)
))
],
),
Column(
spacing: 8,
children: [
Align(alignment: Alignment.topLeft, child: Text(
"Escribir mensaje a ${kid.name} del motivo de la retirada de su dinero",
style: TextStyle(fontSize: 14, letterSpacing: 0)
)),
CustomTextField(
hint: "Escribe tu mensaje",
lines: 4,
length: 150,
),
Row(
spacing: 4,
children: [
Icon(Icons.info_outline, size: 16),
Text("Máximo 150 caracteres", style: TextStyle(fontSize: 14, letterSpacing: 0))
],
)
],
)
],
),
)],
footer: Container(
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
color: theme.getColorFor(ThemeCode.backgroundPrimary),
borderRadius: BorderRadius.only(topRight: Radius.circular(24), topLeft: Radius.circular(24))
),
child: Column(
spacing: 16,
children: [
PrimaryButton(
onPressed: ()=>{Navigator.pop(context)},
text: "Enviar mensaje y bloquear",
color: theme.getColorFor(ThemeCode.buttonPrimary),
),
TextButton(
style: ButtonStyle(padding: WidgetStatePropertyAll(EdgeInsets.all(0))),
onPressed: ()=>Navigator.pop(context),
child: Text("Cancelar", style: TextStyle(fontSize: 18))
)
],
),
)
);
}
}

View File

@@ -0,0 +1,786 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:home/src/presentation/wallet_management_layout.dart';
import 'package:sf_shared/sf_shared.dart';
class GoalsScreen extends ConsumerStatefulWidget{
final Kid kid;
List<Task> tasks = [Task(rewardAmount: 10, subtasks: [
Subtask(name: "Hacer la cama", completed: false),
Subtask(name: "Terminar los deberes", completed: true),
Subtask(name: "Recoger la mesa", completed: true),
Subtask(name: "Lavarse los dientes", completed: false)
]), Task(rewardAmount: 10.05)];
final List<SavingsGoal> savingsGoals;
@override
GoalsScreen({
super.key,
required this.kid,
this.savingsGoals = const [
SavingsGoal(name: "Cumpleaños de Emma", goal: 24, saved: 12.09),
SavingsGoal(name: "Protecciones nuevas de patines", goal: 10, saved: 0)
]
});
@override
ConsumerState<GoalsScreen> createState() => GoalsScreenState();
}
class GoalsScreenState extends ConsumerState<GoalsScreen>{
late bool fullPlan;
@override
void initState() {
super.initState();
fullPlan = true;
}
@override
Widget build(BuildContext context) {
final theme = ref.watch(themePortProvider);
return WalletManagementLayout(
kid: widget.kid,
children: [
Container(
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
color: theme.getColorFor(ThemeCode.backgroundPrimary),
borderRadius: BorderRadius.all(Radius.circular(24))
),
child: Column(
spacing: 24,
children: [
Row(
spacing: 8,
children: [
Text("Metas", style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500, letterSpacing: 0)),
Icon(Icons.workspace_premium),
Spacer(),
Text("Sólo con Plan Completo", style: TextStyle(fontSize: 14, letterSpacing: 0))
],
),
Text(
"Enséñale a ahorrar y refuerza la importancia de no malgastar su dinero",
style: TextStyle(fontSize: 14, letterSpacing: 0),
),
],
),
),
SavingsBlock(fullPlan: fullPlan, savings: widget.savingsGoals),
TasksBlock(fullPlan: fullPlan, tasks: widget.tasks),
],
footer: Container()
);
}
}
class SavingsBlock extends ConsumerStatefulWidget {
final bool fullPlan;
final List savings;
@override
const SavingsBlock({
super.key,
required this.fullPlan,
required this.savings
});
@override
ConsumerState<SavingsBlock> createState() => SavingsBlockState();
}
class SavingsBlockState extends ConsumerState<SavingsBlock>{
late List<bool> showEdit;
late List<bool> showAdd;
late bool showNew;
@override
void initState() {
super.initState();
showEdit = widget.savings.map((_)=>false).toList();
showAdd = widget.savings.map((_)=>false).toList();
showNew = false;
}
@override
Widget build(BuildContext context) {
final theme = ref.watch(themePortProvider);
var emptyBlock = ({fullPlan}) => Container(
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
color: theme.getColorFor(ThemeCode.backgroundPrimary),
borderRadius: BorderRadius.all(Radius.circular(24)),
border: BoxBorder.all(color: theme.getColorFor(ThemeCode.textPrimary))
),
child: Stack(
children: [
Align(alignment: Alignment.topRight, child: SvgPicture.asset("assets/images/ui/ahorros.svg")),
Column(
spacing: 24,
children: [
Align(alignment: Alignment.topLeft, child: Text(
"Ahorros",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500, letterSpacing: 0),
)),
Align(alignment: Alignment.topLeft, child: SizedBox(
width: 200,
child: Text(
"Enséñale a ahorrar y refuerza la importancia de no malgastar su dinero",
style: TextStyle(fontSize: 14, letterSpacing: 0),
),
)),
if (fullPlan) Column(
spacing: 24,
children: [
Align(
alignment: Alignment.topLeft,
child: SecondaryButton(
onPressed: ()=>setState(() {
showNew = true;
}),
text: "Crear objetivo de ahorro",
radius: 8,
height: 44,
size: 14,
width: 230,
),
),
Align(
alignment: Alignment.topLeft,
child: TextButton(
onPressed: ()=>{},
style: ButtonStyle(padding: WidgetStatePropertyAll(EdgeInsets.zero)),
child: Text(
"Ver estado de ahorros",
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500, letterSpacing: 0)
)
)
)
],
),
if (!fullPlan) TextButton(
onPressed: ()=>{},
child: Row(
spacing: 4,
children: [
Icon(Icons.workspace_premium, size: 16),
Text("Suscribirme al Plan Completo")
],
)
)
],
)
],
)
);
var editBlock = ({create, index}) => Column(
spacing: 24,
children: [
CustomTextField(
hint: create? "Ponle un título para reconocerlo" : widget.savings[index].name,
label: "Motivo del ahorro",
lines: create? 2 : 1,
),
CustomTextField(
hint: "30€",
label: "Seleciona la cantidad a ahorrar",
numeric: true,
),
CheckboxListTile(
value: false,
onChanged: (_) => {},
checkboxScaleFactor: 2,
controlAffinity: ListTileControlAffinity.leading,
activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
contentPadding: EdgeInsets.zero,
title: Text(
"Ahorro automático desde su paga",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500, letterSpacing: 0),
),
),
CustomTextField(
hint: "2€",
label: "Selecciona la cantidad de dinero",
numeric: true,
),
CheckboxListTile(
value: false,
onChanged: (_) => {},
checkboxScaleFactor: 2,
controlAffinity: ListTileControlAffinity.leading,
activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
contentPadding: EdgeInsets.zero,
title: Text(
"Mandar automáticamente el dinero al reloj del peque cuando consiga su objetivo",
style: TextStyle(fontSize: 16, letterSpacing: 0),
),
),
Column(
spacing: 10,
children: [
Text(
"Este es el mensaje fijado por defecto que le llegará a su reloj:",
style: TextStyle(fontSize: 16, letterSpacing: 0),
),
Text(
"\"¡Genial, has conseguido ahorrar lo que querías!\"",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500, letterSpacing: 0),
)
],
),
Column(
spacing: 8,
children: [
CustomTextField(
hint: "Escribe tu mensaje",
label: "Escribir otro mensaje diferente:",
lines: 4,
length: 150,
),
Row(
spacing: 4,
children: [
Icon(Icons.info_outline, size: 16,),
Text(
"Máximo 150 caracteres",
style: TextStyle(fontSize: 14, letterSpacing: 0),
)
],
)
],
),
Column(
spacing: 24,
children: [
PrimaryButton(
onPressed: () => {},
text: "Guardar cambios",
color: theme.getColorFor(
ThemeCode.buttonPrimary)
),
TextButton(
onPressed: () {
if (create){
setState(() {
showNew = false;
});
} else {
setState(() {
showEdit[index] = false;
});
}
},
child: Text(
"Cancelar",
style: TextStyle(fontSize: 16,
fontWeight: FontWeight.w500,
letterSpacing: 0),
)
)
],
)
],
);
if (widget.fullPlan) {
if (showNew){
return Container(
padding: EdgeInsets.fromLTRB(24, 24, 24, 32),
decoration: BoxDecoration(
color: theme.getColorFor(ThemeCode.backgroundSecondary),
border: Border.all(color: theme.getColorFor(ThemeCode.textPrimary)),
borderRadius: BorderRadius.all(Radius.circular(24))
),
child: Column(
spacing: 24,
children: [
Align(alignment: Alignment.topLeft, child: Text(
"Ahorros",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500, letterSpacing: 0),
)),
Text(
"Enséñale a ahorrar y refuerza la importancia de no malgastar su dinero",
style: TextStyle(fontSize: 14, letterSpacing: 0),
),
Container(
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(24)),
color: theme.getColorFor(ThemeCode.backgroundPrimary)
),
child: editBlock(create: true, index: null)
)
],
),
);
} else {
if (widget.savings.isNotEmpty) {
return Container(
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(24)),
color: theme.getColorFor(ThemeCode.backgroundPrimary),
//border: BoxBorder.all(color: theme.getColorFor(ThemeCode.textPrimary))
),
child: Column(
spacing: 24,
children: [
Align(alignment: Alignment.topLeft,
child: Text(
"Ahorros",
style: TextStyle(fontSize: 20,
fontWeight: FontWeight.w500,
letterSpacing: 0),
)
),
...List<Widget>.generate(widget.savings.length, (int index) =>
Container(
decoration: BoxDecoration(
border: BoxBorder.all(
color: theme.getColorFor(ThemeCode.textPrimary)),
color: theme.getColorFor(ThemeCode.backgroundPrimary),
borderRadius: BorderRadius.all(Radius.circular(24)),
),
padding: EdgeInsets.all(16),
child: Column(
spacing: 24,
children: [
Row(
spacing: 16,
children: [
Expanded(child: Column(
spacing: 8,
children: [
Align(
alignment: Alignment.topLeft,
child: Text(
"Ahorro para",
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 16, letterSpacing: 0),
),
),
Text(
widget.savings[index].name,
style: TextStyle(fontSize: 16,
fontWeight: FontWeight.w500,
letterSpacing: 0),
)
],
)),
Container(
decoration: BoxDecoration(
color: theme.getColorFor(
ThemeCode.backgroundTertiary),
borderRadius: BorderRadius.all(
Radius.circular(16)),
),
padding: EdgeInsets.symmetric(
horizontal: 8, vertical: 4),
child: Row(
spacing: 8,
children: [
Icon(Icons.account_balance, size: 24,
color: theme.getColorFor(
ThemeCode.buttonPrimary)),
MoneyText(
text: "${widget.savings[index]
.goal}",
size: 30,
secondarySize: 14,
color: theme.getColorFor(
ThemeCode.buttonPrimary)
)
],
),
)
]
),
if (index == 0)Column(
spacing: 8,
children: [
ProgressBar(
max: widget.savings[index].goal,
value: widget.savings[index].saved,
height: 64,
textSize: 40,
textSecondarySize: 24,
backgroundColor: theme.getColorFor(
ThemeCode.backgroundTertiary),
foregroundColor: theme.getColorFor(
ThemeCode.buttonPrimary),
textColor: theme.getColorFor(
ThemeCode.textSecondary)
),
Center(child: Text("Ahorrado")),
if (!showAdd[index]) TextButton(
style: ButtonStyle(
padding: WidgetStatePropertyAll(
EdgeInsets.zero)),
onPressed: () =>
setState(() {
showAdd[index] = true;
}),
child: Text(
"+ Añadir dinero extra a este ahorro",
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 16, letterSpacing: 0),
)
),
if (showAdd[index]) CustomTextField(
hint: "5€",
numeric: true,
)
],
),
if (!showEdit[index]) Row(
children: [
TextButton(
style: ButtonStyle(
padding: WidgetStatePropertyAll(
EdgeInsets.zero)),
onPressed: () =>
setState(() {
showEdit[index] = true;
}),
child: Row(
spacing: 4,
children: [
Icon(Icons.edit_outlined, size: 24),
Text(
"Editar",
style: TextStyle(fontSize: 16,
fontWeight: FontWeight.w500,
letterSpacing: 0),
),
],
)
),
Spacer(),
TextButton(
style: ButtonStyle(
padding: WidgetStatePropertyAll(
EdgeInsets.zero)),
onPressed: () => {},
child: Row(
spacing: 4,
children: [
Icon(Icons.delete_outline_outlined,
size: 24),
Text(
"Eliminar",
style: TextStyle(fontSize: 16,
fontWeight: FontWeight.w500,
letterSpacing: 0),
)
],
)
),
],
),
if(showEdit[index]) editBlock(
create: false, index: index)
],
),
),
),
TextButton(
onPressed: () =>
setState(() {
showNew = true;
}),
child: Row(
spacing: 4,
children: [
Spacer(),
Icon(Icons.account_balance, size: 24),
Text(
"Crear otro ahorro",
style: TextStyle(fontSize: 18,
fontWeight: FontWeight.w500,
letterSpacing: 0),
),
Spacer()
],
)
),
],
),
);
} else {
return emptyBlock(fullPlan: true);
}
}
} else {
return emptyBlock(fullPlan: false);
}
}
}
class TasksBlock extends ConsumerStatefulWidget {
final bool fullPlan;
final List<Task> tasks;
@override
const TasksBlock({
super.key,
required this.fullPlan,
required this.tasks
});
@override
ConsumerState<ConsumerStatefulWidget> createState() => TasksBlockState();
}
class TasksBlockState extends ConsumerState<TasksBlock>{
@override
Widget build(BuildContext context) {
final theme = ref.watch(themePortProvider);
final emptyBlock = ({fullPlan})=>Container(
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
color: theme.getColorFor(ThemeCode.backgroundPrimary),
borderRadius: BorderRadius.all(Radius.circular(24)),
border: BoxBorder.all(color: theme.getColorFor(ThemeCode.textPrimary))
),
child: Stack(
children: [
Align(alignment: Alignment.topRight, child: SvgPicture.asset("assets/images/ui/tareas.svg")),
Column(
spacing: 24,
children: [
Align(alignment: Alignment.topLeft, child: Text(
"Tareas",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500, letterSpacing: 0),
)),
Align(alignment: Alignment.topLeft, child: SizedBox(
width: 200,
child: Text(
"Refuerza su sentido de la responsabilidad con pequeñas tareas que cumplir",
style: TextStyle(fontSize: 14, letterSpacing: 0),
),
)),
if (fullPlan) Align(
alignment: Alignment.topLeft,
child: SecondaryButton(
onPressed: ()=>{},
text: "Crear lista de tareas",
size: 14,
width: 190,
height: 44,
)
),
if (!fullPlan) TextButton(
onPressed: ()=>{},
child: Row(
spacing: 4,
children: [
Icon(Icons.workspace_premium, size: 16),
Text("Suscribirme al Plan Completo")
],
)
)
],
)
],
)
);
if (widget.fullPlan) {
if (widget.tasks.isNotEmpty) {
return Container(
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(24)),
border: BoxBorder.all(
color: theme.getColorFor(ThemeCode.textPrimary)),
color: theme.getColorFor(ThemeCode.backgroundSecondary)
),
child: Column(
spacing: 24,
children: [
Column(
spacing: 8,
children: [
Align(alignment: Alignment.topLeft, child: Text(
"Tareas",
style: TextStyle(fontSize: 20,
fontWeight: FontWeight.w500,
letterSpacing: 0),
)),
Text(
"Refuerza su sentido de la responsabilidad con pequeñas tareas que cumplir",
style: TextStyle(fontSize: 14, letterSpacing: 0),
)
],
),
...List<Widget>.generate(widget.tasks.length, (int i) =>
Container(
decoration: BoxDecoration(
border: BoxBorder.fromLTRB(top: BorderSide(
color: theme.getColorFor(ThemeCode.buttonPrimary),
width: 8)),
borderRadius: BorderRadius.all(Radius.circular(24)),
color: theme.getColorFor(ThemeCode.backgroundPrimary)
),
padding: EdgeInsets.all(24),
child: Column(
spacing: 16,
children: [
Row(children: [
Text(
"Lista de tareas",
style: TextStyle(fontSize: 20,
fontWeight: FontWeight.w500,
letterSpacing: 0),
),
Spacer(),
Text(
"10 oct - 17 oct",
style: TextStyle(fontSize: 14, letterSpacing: 0),
)
]),
...List<CheckboxListTile>.generate(
widget.tasks[i].subtasks.length, (int j) =>
CheckboxListTile(
contentPadding: EdgeInsets.zero,
checkboxScaleFactor: 2,
value: widget.tasks[i].subtasks[j].completed,
title: Text(widget.tasks[i].subtasks[j].name),
controlAffinity: ListTileControlAffinity
.leading,
activeColor: theme.getColorFor(
ThemeCode.buttonPrimary),
onChanged: (_) =>
setState(() {
widget.tasks[i].subtasks[j] = Subtask(
name: widget.tasks[i].subtasks[j]
.name,
completed: !widget.tasks[i]
.subtasks[j].completed);
}),
)
),
TextButton(
style: ButtonStyle(
padding: WidgetStatePropertyAll(EdgeInsets
.zero)),
onPressed: () => {},
child: Align(
alignment: Alignment.topLeft,
child: Text(
"+ Añadir tarea",
style: TextStyle(fontSize: 18,
fontWeight: FontWeight.w500,
letterSpacing: 0),
)
)
),
Container(
decoration: BoxDecoration(
color: theme.getColorFor(ThemeCode
.backgroundTertiary),
borderRadius: BorderRadius.all(Radius.circular(
24))
),
padding: EdgeInsets.symmetric(
horizontal: 20, vertical: 16),
child: Row(
spacing: 16,
children: [
Expanded(child: Text(
"Recompensa por cumplimiento",
style: TextStyle(
fontSize: 16, letterSpacing: 0),
)),
Row(
spacing: 8,
children: [
Icon(Icons.emoji_events_outlined, size: 16,
color: theme.getColorFor(
ThemeCode.buttonPrimary)),
MoneyText(
text: "${widget.tasks[i]
.rewardAmount}",
size: 40,
secondarySize: 24,
color: theme.getColorFor(
ThemeCode.buttonPrimary)
)
],
)
],
),
),
Column(
spacing: 8,
children: [
Align(
alignment: Alignment.topLeft,
child: Text(
"Este es el mensaje que se enviará al cumplir con todas las tareas:",
style: TextStyle(
fontSize: 14, letterSpacing: 0),
),
),
Align(
alignment: Alignment.topLeft,
child: Text(
"¡Enhorabuena, has cumplido todas las tareas de esta semana!",
style: TextStyle(fontSize: 14,
fontWeight: FontWeight.w500,
letterSpacing: 0),
),
),
],
),
Align(
alignment: Alignment.topLeft,
child: TextButton(
onPressed: () => {},
child: Row(
spacing: 4,
children: [
Icon(Icons.delete_outline_outlined,
size: 24),
Text(
"Eliminar lista de tareas",
style: TextStyle(fontSize: 16,
fontWeight: FontWeight.w500,
letterSpacing: 0),
)
],
)
),
)
],
),
)
),
SecondaryButton(
onPressed: () => {},
text: "Crear una lista de tareas nueva",
size: 14,
),
],
)
);
} else {
return emptyBlock(fullPlan: true);
}
} else {
return emptyBlock(fullPlan: false);
}
}
}

View File

@@ -43,7 +43,7 @@ class HomeScreen extends ConsumerWidget {
children: <TextSpan>[
TextSpan(
text: name,
style: TextStyle(fontWeight: FontWeight.bold),
style: TextStyle(fontWeight: FontWeight.w500),
),
],
),

View File

@@ -2,6 +2,9 @@ import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:home/src/presentation/deposit_screen.dart';
import 'package:home/src/presentation/extract_screen.dart';
import 'package:home/src/presentation/goals_screen.dart';
import 'package:home/src/presentation/lock_card_screen.dart';
import 'package:sf_shared/sf_shared.dart';
import 'package:home/src/presentation/limits_screen.dart';
import 'package:home/src/presentation/wage_screen.dart';
@@ -93,7 +96,12 @@ class KidWalletScreen extends ConsumerWidget {
),
TextButton(
style: ButtonStyle(padding: WidgetStatePropertyAll(EdgeInsets.all(0))),
onPressed: ()=>{},
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => LockCardScreen(kid: kid)
)
),
child: Row(
spacing: 10,
children: [
@@ -110,7 +118,7 @@ class KidWalletScreen extends ConsumerWidget {
spacing: 16,
children: [
Container(
padding: EdgeInsets.all(10),
padding: EdgeInsets.all(16),
margin: EdgeInsets.only(top: 30),
decoration: BoxDecoration(
color: theme.getColorFor(ThemeCode.backgroundPrimary),
@@ -121,6 +129,7 @@ class KidWalletScreen extends ConsumerWidget {
child: Row(
children: [
TextButton(
style: ButtonStyle(padding: WidgetStatePropertyAll(EdgeInsets.all(0))),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
@@ -128,7 +137,7 @@ class KidWalletScreen extends ConsumerWidget {
)
),
child: Column(
spacing: 10,
spacing: 8,
children: [
Icon(
Icons.add_circle_outline,
@@ -149,6 +158,7 @@ class KidWalletScreen extends ConsumerWidget {
),
Spacer(),
TextButton(
style: ButtonStyle(padding: WidgetStatePropertyAll(EdgeInsets.all(0))),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
@@ -177,6 +187,7 @@ class KidWalletScreen extends ConsumerWidget {
),
Spacer(),
TextButton(
style: ButtonStyle(padding: WidgetStatePropertyAll(EdgeInsets.all(0))),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
@@ -205,7 +216,13 @@ class KidWalletScreen extends ConsumerWidget {
),
Spacer(),
TextButton(
onPressed: () => {},
style: ButtonStyle(padding: WidgetStatePropertyAll(EdgeInsets.all(0))),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => GoalsScreen(kid: kid)
)
),
child: Column(
spacing: 10,
children: [
@@ -228,7 +245,13 @@ class KidWalletScreen extends ConsumerWidget {
),
Spacer(),
TextButton(
onPressed: () => {},
style: ButtonStyle(padding: WidgetStatePropertyAll(EdgeInsets.all(0))),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => ExtractScreen(kid: kid)
)
),
child: Column(
spacing: 10,
children: [
@@ -256,13 +279,13 @@ class KidWalletScreen extends ConsumerWidget {
),
Container(
padding: EdgeInsets.all(15),
height: 400,
height: 300,
decoration: BoxDecoration(
color: theme.getColorFor(ThemeCode.backgroundPrimary),
borderRadius: BorderRadius.all(Radius.circular(20))
),
child: Expanded(child: Column(
spacing: 24,
//spacing: 24,
children: [
Text("Últimos movimientos", style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500)),
activityList(context, theme)
@@ -297,13 +320,14 @@ class KidWalletScreen extends ConsumerWidget {
return Expanded(
child: ListView(
padding: EdgeInsets.symmetric(vertical: 0),
padding: EdgeInsets.symmetric(vertical: 0),
children: [
...List<Widget>.generate(activity.length, (int index) {
return Column(
spacing: 16,
return Container(padding: EdgeInsets.only(top: 24),
child: Column(
spacing: 8,
children: [
Text(activity[index]["date"].toString(), style: TextStyle(fontSize: 18)),
Align(alignment: Alignment.bottomLeft, child: Text(activity[index]["date"].toString(), style: TextStyle(fontSize: 18, height: 1.5))),
Column(
spacing: 16,
children: List<Widget>.generate(
@@ -347,9 +371,9 @@ class KidWalletScreen extends ConsumerWidget {
)
)
]
);
));
}),
TextButton(onPressed: () => {}, child: Text("Ver todos")),
TextButton(onPressed: () => {}, child: Align(alignment: Alignment.bottomLeft, child: Text("Ver todos"))),
]
)
);

View File

@@ -22,7 +22,7 @@ class LimitsScreenState extends ConsumerState<LimitsScreen> {
@override
void initState() {
super.initState();
dailyLimits = [
dailyLimits = [ //dey, week, month, year
{"title": "Diario L-V", "limit": "5", "edit": false},
{"title": "Fines de semana", "limit": "8", "edit": false},
{"title": "Semanal", "limit": "30", "edit": false},
@@ -41,14 +41,27 @@ class LimitsScreenState extends ConsumerState<LimitsScreen> {
"end": "21:00",
"edit": false,
},
{"title": "Vacaciones", "start": "09:00", "end": "22:00", "edit": false},
{
"title": "Vacaciones",
"start": "09:00",
"end": "22:00",
"edit": false
},
];
conditions = [
{"title": "Alimentación", "limit": "10", "edit": false},
{"title": "Transporte", "limit": "10", "edit": false},
{"title": "Alimentación", "limit": "10", "edit": false},
{"title": "Alimentación", "limit": "10", "active": true, "edit": false},
{"title": "Transporte", "limit": "10", "active": false, "edit": false},
{"title": "Alimentación", "limit": "10", "active": false, "edit": false},
];
blocks = [
{"title": "Alojamiento y Hoteles", "active": true},
{"title": "Supermercados", "active": true},
{"title": "Gasolineras", "active": true},
{"title": "Restaurantes", "active": true},
{"title": "Bares y discotecas", "active": true},
{"title": "Licorerías", "active": true},
{"title": "Estancos", "active": true},
];
blocks = [];
}
@override
@@ -57,16 +70,32 @@ class LimitsScreenState extends ConsumerState<LimitsScreen> {
return WalletManagementLayout(
kid: widget.kid,
footer: Column(
children: [
FilledButton(
onPressed: () => {},
child: SizedBox(
width: double.infinity,
child: Center(child: Text("Guardar límites")),
footer: Container(
decoration: BoxDecoration(
color: theme.getColorFor(ThemeCode.backgroundPrimary),
borderRadius: BorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24))
),
padding: EdgeInsets.all(24),
child: Column(
children: [
PrimaryButton(
onPressed: () => {},
text: "Guardar límites",
color: theme.getColorFor(ThemeCode.buttonPrimary)
),
),
],
TextButton(
onPressed: ()=>Navigator.pop(context),
child: Text(
"Cancelar",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: theme.getColorFor(ThemeCode.textPrimary)
)
)
)
],
),
),
children: [
Container(
@@ -78,9 +107,12 @@ class LimitsScreenState extends ConsumerState<LimitsScreen> {
child: Column(
spacing: 10,
children: [
Text(
"Pon límite de gastos",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
Align(
alignment: Alignment.topLeft,
child: Text(
"Pon límite de gastos",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
)
),
Text("Libertad para ellos, tranquilidad para ti"),
...List<Widget>.generate(dailyLimits.length, (int index) {
@@ -103,7 +135,9 @@ class LimitsScreenState extends ConsumerState<LimitsScreen> {
),
],
),
if (dailyLimits[index]["edit"]) CustomTextField(),
if (dailyLimits[index]["edit"]) CustomTextField(
hint: "5€",
),
],
);
}),
@@ -136,22 +170,113 @@ class LimitsScreenState extends ConsumerState<LimitsScreen> {
TextButton(
onPressed: () => {
setState(() {
timeLimits[index]["edit"] =
!timeLimits[index]["edit"];
timeLimits[index]["edit"] = !timeLimits[index]["edit"];
}),
},
child: Text("Editar"),
),
],
),
if (timeLimits[index]["edit"]) CustomTextField(),
if (timeLimits[index]["edit"]) CustomTextField(
hint: "5€",
),
],
);
}),
],
),
),
Container(
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(24)),
color: theme.getColorFor(ThemeCode.backgroundPrimary),
),
child: Column(
spacing: 24,
children: [
Text(
"Condiciones",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500, letterSpacing: 0),
),
Column(
spacing: 8,
children: List<Widget>.generate(conditions.length, (int index)=>
Column(
spacing: 8,
children: [
Row(children: [
Expanded(child: CheckboxListTile(
value: conditions[index]["active"],
onChanged: (_)=>setState(() {
conditions[index]["active"] = !conditions[index]["active"];
}),
title: Text(
"${conditions[index]["title"]}: ${conditions[index]["limit"]}€/sem",
style: TextStyle(fontSize: 16, letterSpacing: 0),
),
checkboxScaleFactor: 2,
controlAffinity: ListTileControlAffinity.leading,
activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
contentPadding: EdgeInsets.zero,
)),
TextButton(
onPressed: ()=>setState(() {
conditions[index]["edit"] = ! conditions[index]["edit"];
}),
child: Text(
"Editar",
style: TextStyle(fontSize: 16, letterSpacing: 0),
)
)
]),
if (conditions[index]["edit"]) CustomTextField(
hint: "5€",
numeric: true,
)
]
)
),
)
],
)
),
Container(
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
color: theme.getColorFor(ThemeCode.backgroundPrimary),
borderRadius: BorderRadius.all(Radius.circular(24))
),
child: Column(
spacing: 24,
children: [
Text(
"Comercios bloqueados",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500, letterSpacing: 0),
),
Column(
spacing: 8,
children: List<Widget>.generate(blocks.length, (int index) =>
CheckboxListTile(
value: blocks[index]["active"],
onChanged: (_) => setState(() {
blocks[index]["active"] = !blocks[index]["active"];
}),
title: Text(
blocks[index]["title"],
style: TextStyle(fontSize: 16, letterSpacing: 0),
),
checkboxScaleFactor: 2,
controlAffinity: ListTileControlAffinity.leading,
activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
contentPadding: EdgeInsets.zero,
)
)
)
],
),
)
],
);
}
}
}

View File

@@ -0,0 +1,105 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:home/src/presentation/wallet_management_layout.dart';
import 'package:sf_shared/sf_shared.dart';
class LockCardScreen extends ConsumerWidget{
final Kid kid;
@override
LockCardScreen({
super.key,
required this.kid,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final theme = ref.watch(themePortProvider);
return WalletManagementLayout(
kid: kid,
children: [Container(
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(24)),
color: theme.getColorFor(ThemeCode.backgroundPrimary)
),
child: Column(
spacing: 24,
children: [
Column(
spacing: 8,
children: [
Align(alignment: Alignment.topLeft, child: Text(
"Bloqueo de tarjeta",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500, letterSpacing: 0)
)),
Align(alignment: Alignment.topLeft, child: Text(
"Este dato aparecerá en el reloj del peque",
style: TextStyle(fontSize: 14, letterSpacing: 0)
))
],
),
Column(
spacing: 8,
children: [
Align(alignment: Alignment.topLeft, child: Text(
"Este es el mensaje fijado por defecto:",
style: TextStyle(fontSize: 16, letterSpacing: 0)
)),
Align(alignment: Alignment.topLeft, child: Text(
"\"De momento hemos bloqueado el dinero del reloj\"",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500, letterSpacing: 0)
))
],
),
Column(
spacing: 8,
children: [
Text(
"Escribir mensaje a ${kid.name} del motivo del bloqueo",
style: TextStyle(fontSize: 14, letterSpacing: 0),
),
CustomTextField(
hint: "Escribe tu mensaje",
lines: 4,
length: 150,
),
Row(
spacing: 4,
children: [
Icon(Icons.info_outline, size: 16),
Text("Máximo 150 caracteres", style: TextStyle(fontSize: 14, letterSpacing: 0))
],
)
],
)
],
),
)],
footer: Container(
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
color: theme.getColorFor(ThemeCode.backgroundPrimary),
borderRadius: BorderRadius.only(topRight: Radius.circular(24), topLeft: Radius.circular(24))
),
child: Column(
spacing: 16,
children: [
PrimaryButton(
onPressed: ()=>{Navigator.pop(context)},
text: "Enviar mensaje y bloquear",
color: theme.getColorFor(ThemeCode.buttonPrimary),
),
TextButton(
style: ButtonStyle(padding: WidgetStatePropertyAll(EdgeInsets.all(0))),
onPressed: ()=>Navigator.pop(context),
child: Text("Cancelar", style: TextStyle(fontSize: 18))
)
],
),
)
);
}
}

View File

@@ -34,13 +34,10 @@ class WageScreen extends ConsumerWidget {
child: Column(
spacing: 10,
children: [
FilledButton(
PrimaryButton(
onPressed: () => {},
child: Container(
width: double.infinity,
padding: EdgeInsets.all(20),
child: Center(child: Text("Activar paga automática")),
),
text: "Activar paga automática",
color: theme.getColorFor(ThemeCode.buttonPrimary)
),
TextButton(onPressed: () => {}, child: Text("Cancelar")),
],
@@ -56,9 +53,11 @@ class WageScreen extends ConsumerWidget {
child: Column(
spacing: 10,
children: [
Text(
"Paga automática",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
Align(alignment: Alignment.topLeft,
child: Text(
"Paga automática",
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 20),
),
),
CustomTextField(
numeric: true,
@@ -74,16 +73,21 @@ class WageScreen extends ConsumerWidget {
color: theme.getColorFor(ThemeCode.backgroundPrimary),
borderRadius: BorderRadius.all(Radius.circular(20)),
),
padding: EdgeInsets.all(10),
padding: EdgeInsets.all(24),
child: Column(
spacing: 10,
children: [
Text(
"Frecuencia",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
Align(alignment: Alignment.topLeft,
child: Text(
"Frecuencia",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
)
),
Align(alignment: Alignment.topLeft,
child: Text("Cuándo se envía el dinero"),
),
Text("Cuándo se envía el dinero"),
CheckboxListTile(
contentPadding: EdgeInsets.zero,
title: Text('Semanal'),
controlAffinity: ListTileControlAffinity.leading,
value: frequence == "weekly",
@@ -95,6 +99,7 @@ class WageScreen extends ConsumerWidget {
activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
),
CheckboxListTile(
contentPadding: EdgeInsets.zero,
title: Text('Cada dos semanas'),
controlAffinity: ListTileControlAffinity.leading,
value: frequence == "biweekly",
@@ -106,6 +111,7 @@ class WageScreen extends ConsumerWidget {
activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
),
CheckboxListTile(
contentPadding: EdgeInsets.zero,
title: Text('Mensual'),
controlAffinity: ListTileControlAffinity.leading,
value: frequence == "monthly",
@@ -116,38 +122,26 @@ class WageScreen extends ConsumerWidget {
},
activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
),
Container(
width: double.infinity,
child: DropdownMenu(
label: Text("Día de la semana"),
initialSelection: "Domingo",
dropdownMenuEntries: List<DropdownMenuEntry>.generate(7, (
int index,
) {
final days = [
"Lunes",
"Martes",
"Miércoles",
"Jueves",
"Viernes",
"Sábado",
"Domingo",
];
return DropdownMenuEntry(
value: days[index],
label: days[index],
);
}),
),
CustomDropdown(
items: [
Text("Lunes"),
Text("Martes"),
Text("Miércoles"),
Text("Jueves"),
Text("Viernes"),
Text("Sábado"),
Text("Domingo"),
],
values: ["Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado", "Domingo"],
onChanged: (value)=> {},
hint: "Día de la semana",
),
DropdownMenu(
label: Text("Hora del día"),
initialSelection: 9,
dropdownMenuEntries: List<DropdownMenuEntry>.generate(24, (
int index,
) {
return DropdownMenuEntry(value: index, label: "$index:00");
CustomDropdown(
hint: "Hora del día",
items: List<Widget>.generate(24,(int index){
return Text("$index:00");
}),
onChanged: (value)=> {},
),
CustomTextField(
lines: 3,
@@ -168,16 +162,21 @@ class WageScreen extends ConsumerWidget {
color: theme.getColorFor(ThemeCode.backgroundPrimary),
borderRadius: BorderRadius.all(Radius.circular(20)),
),
padding: EdgeInsets.all(10),
padding: EdgeInsets.all(24),
child: Column(
spacing: 10,
children: [
Text(
"Condiciones",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
Align(alignment: Alignment.topLeft,
child: Text(
"Condiciones",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
),
),
Align(alignment: Alignment.topLeft,
child: Text("Este dato aparecerá en el reloj del peque"),
),
Text("Este dato aparecerá en el reloj del peque"),
CheckboxListTile(
contentPadding: EdgeInsets.zero,
title: Text('Sólo si cumple límites semanales'),
controlAffinity: ListTileControlAffinity.leading,
value: conditions["weeklyLimits"],
@@ -189,6 +188,7 @@ class WageScreen extends ConsumerWidget {
activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
),
CheckboxListTile(
contentPadding: EdgeInsets.zero,
title: Text('Sólo si no ha tenido incidencias'),
controlAffinity: ListTileControlAffinity.leading,
value: conditions["incidences"],
@@ -200,6 +200,7 @@ class WageScreen extends ConsumerWidget {
activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
),
CheckboxListTile(
contentPadding: EdgeInsets.zero,
title: Text('Pausar durante vacaciones'),
controlAffinity: ListTileControlAffinity.leading,
value: conditions["holidays"],

View File

@@ -93,7 +93,13 @@ class WalletItem extends ConsumerWidget{
SizedBox(
width: 169,
height: 60,
child: FilledButton(
child: PrimaryButton(
onPressed: ()=>Navigator.push(context, MaterialPageRoute(builder: (_)=>DepositScreen(kid: kid))),
text: "+ Añadir dinero",
color: theme.getColorFor(ThemeCode.buttonSecondary),
radius: 12,
)
/*FilledButton(
onPressed: ()=>Navigator.push(context, MaterialPageRoute(builder: (_)=>DepositScreen(kid: kid))),
style: ButtonStyle(
shape: WidgetStateProperty.all<RoundedRectangleBorder>(
@@ -113,7 +119,7 @@ class WalletItem extends ConsumerWidget{
)
)
)
)
)*/
)
])
]
@@ -138,7 +144,8 @@ class PhotoDialog extends ConsumerWidget{
decoration: BoxDecoration(
color: theme.getColorFor(ThemeCode.backgroundPrimary),
borderRadius: BorderRadius.only(
topRight: Radius.circular(16), topLeft: Radius.circular(16))
topRight: Radius.circular(16), topLeft: Radius.circular(16)
)
),
child: Column(
spacing: 24,
@@ -146,21 +153,10 @@ class PhotoDialog extends ConsumerWidget{
Column(
spacing: 16,
children: [
FilledButton(
onPressed: () => {},
child: Expanded(
child: Center(
child: Text(
"Cámara",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
color: theme.getColorFor(
ThemeCode.textSecondary)
)
)
)
)
PrimaryButton(
onPressed: ()=>{},
text: "Cámara",
color: theme.getColorFor(ThemeCode.buttonPrimary)
),
OutlinedButton(
onPressed: () => {},

View File

@@ -21,7 +21,7 @@ class ActivityScreen extends ConsumerWidget {
final content = [
Text(
"Movimientos recientes",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30),
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 24),
),
Row(
spacing: 20,
@@ -54,4 +54,4 @@ class ActivityScreen extends ConsumerWidget {
),
);
}
}
}

View File

@@ -29,21 +29,29 @@ class AlertScreenState extends ConsumerState<AlertScreen> {
Widget build(BuildContext context) {
final theme = ref.watch(themePortProvider);
return Scaffold(
backgroundColor: theme.getColorFor(ThemeCode.backgroundSecondary),
body: Container(
margin: EdgeInsets.all(30),
return SafeArea(
child: Container(
color: theme.getColorFor(ThemeCode.backgroundSecondary),
margin: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Column(
spacing: 32,
children: [
Row(
children: [
Text("Alertas"),
Text(
"Alertas",
style: TextStyle(
fontSize: 24,
letterSpacing: 0,
fontWeight: FontWeight.w500
)
),
Spacer(),
TextButton(
onPressed: () => setState(() {
edit = !edit;
}),
child: Text("Editar"),
child: Text("Editar", style: TextStyle(fontSize: 16, letterSpacing: 0)),
),
],
),

View File

@@ -20,9 +20,16 @@ class ProfileScreen extends ConsumerWidget {
{"type": "lock"},
];
final kids = [
Kid(name: "Ana", balance: 15, savings: 5),
Kid(name: "Carlos", balance: 15, savings: 5)
];
final name = "Juan";
final total = 95.03;
final available = 44.09;
final savings = 4.16;
final savingsPlan = 30.0;
final content = [
Row(
@@ -54,10 +61,10 @@ class ProfileScreen extends ConsumerWidget {
LineGraph(),
DepositBlock(max: 150 - total),
Container(
padding: EdgeInsets.all(20),
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)),
color: theme.getColorFor(ThemeCode.backgroundPrimary),
borderRadius: BorderRadius.all(Radius.circular(20)),
),
child: TextButton(
onPressed: ()=>{},
@@ -98,7 +105,7 @@ class ProfileScreen extends ConsumerWidget {
children: [
DecoratedBox(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(30)),
borderRadius: const BorderRadius.only(bottomRight: Radius.circular(24), bottomLeft: Radius.circular(24)),
color: Color(0xFF4B4B4B),
),
child: SizedBox(width: double.infinity, height: 200),

View File

@@ -41,7 +41,7 @@ class SettingsScreen extends ConsumerWidget {
),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
color: theme.getColorFor(ThemeCode.backgroundPrimary),
@@ -57,15 +57,15 @@ class SettingsScreen extends ConsumerWidget {
),
Spacer(),
TextButton(onPressed: () => {}, child: Text("Editar wallet")),
Icon(Icons.attach_money),
Icon(Icons.account_balance, size: 24),
],
),
Text(relation),
Align(alignment: Alignment.centerLeft, child: Text(relation)),
],
),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
color: theme.getColorFor(ThemeCode.backgroundPrimary),
@@ -73,7 +73,6 @@ class SettingsScreen extends ConsumerWidget {
child: Column(
children: [
Row(
spacing: 10,
children: [
Text(
"Datos personales",
@@ -83,47 +82,56 @@ class SettingsScreen extends ConsumerWidget {
TextButton(onPressed: () => {}, child: Text("Editar")),
],
),
Text.rich(
TextSpan(
text: "Nombre: ",
style: TextStyle(fontWeight: FontWeight.bold),
children: [
TextSpan(
text: fullName,
style: TextStyle(fontWeight: FontWeight.normal),
),
],
),
Align(
alignment: Alignment.centerLeft,
child: Text.rich(
TextSpan(
text: "Nombre: ",
style: TextStyle(fontWeight: FontWeight.bold),
children: [
TextSpan(
text: fullName,
style: TextStyle(fontWeight: FontWeight.normal),
),
],
),
)
),
Text.rich(
TextSpan(
text: "Fecha de nacimiento: ",
style: TextStyle(fontWeight: FontWeight.bold),
children: [
TextSpan(
text: birthDate,
style: TextStyle(fontWeight: FontWeight.normal),
),
],
),
Align(
alignment: Alignment.centerLeft,
child: Text.rich(
TextSpan(
text: "Fecha de nacimiento: ",
style: TextStyle(fontWeight: FontWeight.bold),
children: [
TextSpan(
text: birthDate,
style: TextStyle(fontWeight: FontWeight.normal),
),
],
),
)
),
Text.rich(
TextSpan(
text: "Familiar: ",
style: TextStyle(fontWeight: FontWeight.bold),
children: [
TextSpan(
text: relation,
style: TextStyle(fontWeight: FontWeight.normal),
),
],
),
Align(
alignment: Alignment.centerLeft,
child: Text.rich(
TextSpan(
text: "Familiar: ",
style: TextStyle(fontWeight: FontWeight.bold),
children: [
TextSpan(
text: relation,
style: TextStyle(fontWeight: FontWeight.normal),
),
],
),
)
),
],
),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
color: theme.getColorFor(ThemeCode.backgroundPrimary),
@@ -131,7 +139,6 @@ class SettingsScreen extends ConsumerWidget {
child: Column(
children: [
Row(
spacing: 10,
children: [
Text(
"Dirección",
@@ -141,47 +148,56 @@ class SettingsScreen extends ConsumerWidget {
TextButton(onPressed: () => {}, child: Text("Editar")),
],
),
Text.rich(
TextSpan(
text: "Dirección: ",
style: TextStyle(fontWeight: FontWeight.bold),
children: [
TextSpan(
text: address,
style: TextStyle(fontWeight: FontWeight.normal),
),
],
Align(
alignment: Alignment.centerLeft,
child: Text.rich(
TextSpan(
text: "Dirección: ",
style: TextStyle(fontWeight: FontWeight.bold),
children: [
TextSpan(
text: address,
style: TextStyle(fontWeight: FontWeight.normal),
),
],
),
),
),
Text.rich(
TextSpan(
text: "País: ",
style: TextStyle(fontWeight: FontWeight.bold),
children: [
TextSpan(
text: country,
style: TextStyle(fontWeight: FontWeight.normal),
),
],
Align(
alignment: Alignment.centerLeft,
child: Text.rich(
TextSpan(
text: "País: ",
style: TextStyle(fontWeight: FontWeight.bold),
children: [
TextSpan(
text: country,
style: TextStyle(fontWeight: FontWeight.normal),
),
],
),
),
),
Text.rich(
TextSpan(
text: "Nacionalidad: ",
style: TextStyle(fontWeight: FontWeight.bold),
children: [
TextSpan(
text: nationality,
style: TextStyle(fontWeight: FontWeight.normal),
),
],
Align(
alignment: Alignment.centerLeft,
child: Text.rich(
TextSpan(
text: "Nacionalidad: ",
style: TextStyle(fontWeight: FontWeight.bold),
children: [
TextSpan(
text: nationality,
style: TextStyle(fontWeight: FontWeight.normal),
),
],
),
),
),
)
],
),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
color: theme.getColorFor(ThemeCode.backgroundPrimary),
@@ -189,7 +205,6 @@ class SettingsScreen extends ConsumerWidget {
child: Column(
children: [
Row(
spacing: 10,
children: [
Text(
"Usuario",
@@ -199,42 +214,46 @@ class SettingsScreen extends ConsumerWidget {
TextButton(onPressed: () => {}, child: Text("Editar")),
],
),
Text.rich(
TextSpan(
text: "Correo: ",
style: TextStyle(fontWeight: FontWeight.bold),
children: [
TextSpan(
text: email,
style: TextStyle(fontWeight: FontWeight.normal),
),
],
Align(
alignment: Alignment.centerLeft,
child: Text.rich(
TextSpan(
text: "Correo: ",
style: TextStyle(fontWeight: FontWeight.bold),
children: [
TextSpan(
text: email,
style: TextStyle(fontWeight: FontWeight.normal),
),
],
),
),
),
Text.rich(
TextSpan(
text: "Teléfono: ",
style: TextStyle(fontWeight: FontWeight.bold),
children: [
TextSpan(
text: phone,
style: TextStyle(fontWeight: FontWeight.normal),
),
],
Align(
alignment: Alignment.centerLeft,
child: Text.rich(
TextSpan(
text: "Teléfono: ",
style: TextStyle(fontWeight: FontWeight.bold),
children: [
TextSpan(
text: phone,
style: TextStyle(fontWeight: FontWeight.normal),
),
],
),
),
),
)
],
),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
color: theme.getColorFor(ThemeCode.backgroundPrimary),
),
child: Row(
spacing: 10,
children: [
Text(
"Cambio de contraseña",
@@ -246,7 +265,7 @@ class SettingsScreen extends ConsumerWidget {
),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
color: theme.getColorFor(ThemeCode.backgroundPrimary),
@@ -254,7 +273,6 @@ class SettingsScreen extends ConsumerWidget {
child: Column(
children: [
Row(
spacing: 10,
children: [
Text(
"Método de pago",
@@ -269,7 +287,26 @@ class SettingsScreen extends ConsumerWidget {
),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
color: theme.getColorFor(ThemeCode.backgroundPrimary),
),
child: Column(
spacing: 24,
children: [
Text(
"Retirar y reembolsar dinero del wallet",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
),
Text("Para transferirte el saldo a tu cuenta necesitamos tu IBAN y algunos datos básics. Así nos aseguramos de que la transferencia sea segura y rápida."),
CustomTextField(label: "Nombre y Apellidos", hint: "******"),
CustomTextField(label: "IBAN con número español", hint: "******")
],
),
),
Container(
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
color: theme.getColorFor(ThemeCode.backgroundTertiary),
@@ -277,7 +314,6 @@ class SettingsScreen extends ConsumerWidget {
child: Column(
children: [
Row(
spacing: 10,
children: [
Text(
"Plan anual",
@@ -287,15 +323,81 @@ class SettingsScreen extends ConsumerWidget {
TextButton(onPressed: () => {}, child: Text("Cambiar Plan")),
],
),
Text("Sin permanencia"),
Text("Llamadas y datos ilimitados"),
Text("2 meses gratis"),
Align(
alignment: Alignment.centerLeft,
child: Row(
spacing: 8,
children: [
Icon(Icons.check, size: 24),
Text(
"Sin permanencia",
style: TextStyle(fontSize: 16, letterSpacing: 0),
),
],
)
),
Align(
alignment: Alignment.centerLeft,
child: Row(
spacing: 8,
children: [
Icon(Icons.check, size: 24),
Text(
"Llamadas y datos ilimitados",
style: TextStyle(fontSize: 16, letterSpacing: 0),
),
],
)
),
Align(
alignment: Alignment.centerLeft,
child: Row(
spacing: 8,
children: [
Icon(Icons.check, size: 24),
Text(
"2 meses gratis",
style: TextStyle(fontSize: 16, letterSpacing: 0),
),
],
)
),
],
),
),
TextButton(onPressed: () => {}, child: Text("Contáctanos")),
TextButton(onPressed: () => {}, child: Text("Preguntas frecuentes")),
Column(
spacing: 16,
children: [
Align(
alignment: Alignment.topLeft,
child: TextButton(
style: ButtonStyle(padding: WidgetStatePropertyAll(EdgeInsets.all(0))),
onPressed: () => {},
child: Row(
spacing: 4,
children: [
Icon(Icons.contact_support_outlined, size: 24),
Text("Contáctanos")
],
)
)
),
Align(
alignment: Alignment.topLeft,
child: TextButton(
style: ButtonStyle(padding: WidgetStatePropertyAll(EdgeInsets.all(0))),
onPressed: () => {},
child: Row(
spacing: 4,
children: [
Icon(Icons.contact_support_outlined, size: 24),
Text("Preguntas frecuentes")
],
)
)
),
],
)
];
return Scaffold(
@@ -304,7 +406,7 @@ class SettingsScreen extends ConsumerWidget {
children: [
DecoratedBox(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(30)),
borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
color: Color(0xFF4B4B4B),
),
child: SizedBox(width: double.infinity, height: 200),
@@ -336,13 +438,10 @@ class SettingsScreen extends ConsumerWidget {
),
child: Column(
children: [
FilledButton(
PrimaryButton(
onPressed: () => {},
child: Container(
width: double.infinity,
padding: EdgeInsets.all(20),
child: Center(child: Text("Guardar cambios")),
),
text: "Guardar cambios",
color: theme.getColorFor(ThemeCode.buttonPrimary)
),
TextButton(
onPressed: () => Navigator.pop(context),