components #2
@@ -24,6 +24,11 @@ void configureAppRouter() {
|
||||
name: 'login',
|
||||
pageBuilder: LoginBuilder().buildPage,
|
||||
),
|
||||
GoRoute(
|
||||
path: '/signup',
|
||||
name: 'signup',
|
||||
pageBuilder: SignupBuilder().buildPage,
|
||||
),
|
||||
GoRoute(
|
||||
path: '/onboarding',
|
||||
name: 'onboarding',
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
// This is a basic Flutter widget test.
|
||||
//
|
||||
// To perform an interaction with a widget in your test, use the WidgetTester
|
||||
// utility in the flutter_test package. For example, you can send tap and scroll
|
||||
// gestures. You can also use WidgetTester to find child widgets in the widget
|
||||
// tree, read text, and verify that the values of widget properties are correct.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||
// Build our app and trigger a frame.
|
||||
//await tester.pumpWidget(const PaymentsApp(di: di));
|
||||
|
||||
// Verify that our counter starts at 0.
|
||||
expect(find.text('0'), findsOneWidget);
|
||||
expect(find.text('1'), findsNothing);
|
||||
|
||||
// Tap the '+' icon and trigger a frame.
|
||||
await tester.tap(find.byIcon(Icons.add));
|
||||
await tester.pump();
|
||||
|
||||
// Verify that our counter has incremented.
|
||||
expect(find.text('0'), findsNothing);
|
||||
expect(find.text('1'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
@@ -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';
|
||||
@@ -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)
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
],
|
||||
|
||||
@@ -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)
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
];
|
||||
|
||||
@@ -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),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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(),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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)
|
||||
)),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -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),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
],
|
||||
|
||||
@@ -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"),
|
||||
],
|
||||
|
||||
18
modules/auth/lib/src/sign_up/signup_builder.dart
Normal file
18
modules/auth/lib/src/sign_up/signup_builder.dart
Normal 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),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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"),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -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)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
))
|
||||
]
|
||||
);
|
||||
|
||||
@@ -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,
|
||||
|
||||
111
modules/home/lib/src/presentation/extract_screen.dart
Normal file
111
modules/home/lib/src/presentation/extract_screen.dart
Normal 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))
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
786
modules/home/lib/src/presentation/goals_screen.dart
Normal file
786
modules/home/lib/src/presentation/goals_screen.dart
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ class HomeScreen extends ConsumerWidget {
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: name,
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
style: TextStyle(fontWeight: FontWeight.w500),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -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"))),
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
105
modules/home/lib/src/presentation/lock_card_screen.dart
Normal file
105
modules/home/lib/src/presentation/lock_card_screen.dart
Normal 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))
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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"],
|
||||
|
||||
@@ -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: () => {},
|
||||
|
||||
@@ -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 {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -4,4 +4,8 @@ export 'src/steps/step_indicator.dart';
|
||||
export 'src/texts/money_text.dart';
|
||||
export 'src/progress_bars/progress_bar.dart';
|
||||
export 'src/inputs/textfields.dart';
|
||||
export 'src/snackbars/snackbar.dart';
|
||||
export 'src/snackbars/snackbar.dart';
|
||||
export 'src/buttons/primary_button.dart';
|
||||
export 'src/buttons/secondary_button.dart';
|
||||
export 'src/buttons/custom_text_button.dart';
|
||||
export 'src/dropdowns/dropdown.dart';
|
||||
@@ -0,0 +1,39 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CustomTextButton extends StatelessWidget{
|
||||
|
||||
final onPressed;
|
||||
final String text;
|
||||
final double size;
|
||||
final FontWeight weight;
|
||||
final Color? color;
|
||||
|
||||
@override
|
||||
const CustomTextButton({
|
||||
super.key,
|
||||
required this.onPressed,
|
||||
required this.text,
|
||||
this.size = 14,
|
||||
this.weight = FontWeight.normal,
|
||||
this.color
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
return TextButton(
|
||||
style: ButtonStyle(padding: WidgetStatePropertyAll(EdgeInsets.zero)),
|
||||
onPressed: onPressed,
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontSize: size,
|
||||
fontWeight: weight,
|
||||
letterSpacing: 0,
|
||||
color: color?? Color(0xFF4B4B4B),
|
||||
decoration: TextDecoration.underline
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
54
packages/design_system/lib/src/buttons/primary_button.dart
Normal file
54
packages/design_system/lib/src/buttons/primary_button.dart
Normal file
@@ -0,0 +1,54 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
class PrimaryButton extends StatelessWidget{
|
||||
final onPressed;
|
||||
final String text;
|
||||
final Color color;
|
||||
final double height;
|
||||
final double? width;
|
||||
final double size;
|
||||
final double radius;
|
||||
final double padding;
|
||||
|
||||
PrimaryButton({
|
||||
required this.onPressed,
|
||||
required this.text,
|
||||
required this.color,
|
||||
this.height = 60,
|
||||
this.width,
|
||||
this.size = 18,
|
||||
this.radius = 18,
|
||||
this.padding = 0,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
return FilledButton(
|
||||
style: ButtonStyle(
|
||||
backgroundColor: WidgetStatePropertyAll<Color>(color),
|
||||
padding: WidgetStatePropertyAll(EdgeInsets.symmetric(horizontal: padding)),
|
||||
shape: WidgetStatePropertyAll(RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(radius)),
|
||||
)),
|
||||
),
|
||||
onPressed: onPressed,
|
||||
child: SizedBox(
|
||||
width: width,
|
||||
height: height,
|
||||
child: Center(child: Text(
|
||||
text,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: size,
|
||||
fontWeight: FontWeight.w500,
|
||||
letterSpacing: 0,
|
||||
color: Colors.white//theme.getColorFor(ThemeCode.textSecondary)
|
||||
)
|
||||
))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
67
packages/design_system/lib/src/buttons/secondary_button.dart
Normal file
67
packages/design_system/lib/src/buttons/secondary_button.dart
Normal file
@@ -0,0 +1,67 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
class SecondaryButton extends StatelessWidget {
|
||||
|
||||
final onPressed;
|
||||
final String? text;
|
||||
final IconData? icon;
|
||||
final String? label;
|
||||
final Color? color;
|
||||
final double radius;
|
||||
final double padding;
|
||||
final double height;
|
||||
final double? width;
|
||||
final double? size;
|
||||
|
||||
@override
|
||||
SecondaryButton({
|
||||
required this.onPressed,
|
||||
this.text,
|
||||
this.icon,
|
||||
this.label,
|
||||
this.color,
|
||||
this.radius = 18,
|
||||
this.padding = 0,
|
||||
this.height = 60,
|
||||
this.width,
|
||||
this.size,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
return OutlinedButton(
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStatePropertyAll(EdgeInsets.symmetric(horizontal: padding)),
|
||||
shape: WidgetStatePropertyAll(RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(radius)),
|
||||
side: BorderSide(color: Color(0xFF4B4B4B))
|
||||
)),
|
||||
),
|
||||
onPressed: onPressed,
|
||||
child: SizedBox(
|
||||
width: width,
|
||||
height: height,
|
||||
child: Center(child: text!=null ? Text(
|
||||
text!,
|
||||
textAlign: TextAlign.center,
|
||||
semanticsLabel: label,
|
||||
style: TextStyle(
|
||||
fontSize: size ?? 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
letterSpacing: 0,
|
||||
color: Color(0xFF4B4B4B)
|
||||
)
|
||||
) : Icon(
|
||||
icon,
|
||||
semanticLabel: label,
|
||||
size: size ?? 24,
|
||||
color: color ?? Color(0xFF4B4B4B)
|
||||
))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
67
packages/design_system/lib/src/dropdowns/dropdown.dart
Normal file
67
packages/design_system/lib/src/dropdowns/dropdown.dart
Normal file
@@ -0,0 +1,67 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
class CustomDropdown extends StatelessWidget{
|
||||
final List<Widget> items;
|
||||
final values;
|
||||
final onChanged;
|
||||
final value;
|
||||
final String? hint;
|
||||
final String? label;
|
||||
final double radius;
|
||||
final double height;
|
||||
final double width;
|
||||
final Color? color;
|
||||
|
||||
const CustomDropdown({
|
||||
super.key,
|
||||
required this.items,
|
||||
this.values,
|
||||
required this.onChanged,
|
||||
this.value,
|
||||
this.hint,
|
||||
this.label,
|
||||
this.radius = 12,
|
||||
this.width = double.infinity,
|
||||
this.height = 70,
|
||||
this.color
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
return Column(
|
||||
spacing: 8,
|
||||
children: [
|
||||
if (label != null) Align(
|
||||
alignment: Alignment.bottomLeft,
|
||||
child: Text(
|
||||
label!,
|
||||
style: TextStyle(fontSize: 14, letterSpacing: 0),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: width,
|
||||
height: height,
|
||||
child: Center(child: DropdownButtonFormField(
|
||||
dropdownColor: Colors.white,
|
||||
decoration: InputDecoration(
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(radius)),
|
||||
borderSide: BorderSide(color: color??Color(0xFF4B4B4B))
|
||||
)
|
||||
),
|
||||
//underline: Container(),
|
||||
initialValue: value,
|
||||
onChanged: onChanged,
|
||||
hint: Text(hint??""),
|
||||
items: List<DropdownMenuItem>.generate(items.length, (int index){
|
||||
return DropdownMenuItem(value: (values!=null)?values[index]:index, child: items[index]);
|
||||
})
|
||||
)),
|
||||
)
|
||||
],
|
||||
) ;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
class CustomTextField extends ConsumerStatefulWidget{
|
||||
class CustomTextField extends StatefulWidget{
|
||||
bool? showPassword;
|
||||
final bool numeric;
|
||||
final String hint;
|
||||
@@ -24,49 +24,60 @@ class CustomTextField extends ConsumerStatefulWidget{
|
||||
});
|
||||
|
||||
@override
|
||||
ConsumerState<CustomTextField> createState() => CustomTextFieldState();
|
||||
State<CustomTextField> createState() => CustomTextFieldState();
|
||||
}
|
||||
|
||||
class CustomTextFieldState extends ConsumerState<CustomTextField>{
|
||||
class CustomTextFieldState extends State<CustomTextField>{
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = ref.watch(themePortProvider);
|
||||
|
||||
return TextFormField(
|
||||
keyboardType: widget.numeric? TextInputType.number : TextInputType.text,
|
||||
obscureText: !(widget.showPassword ?? true),
|
||||
enableSuggestions: widget.showPassword ?? true,
|
||||
autocorrect: !(widget.showPassword ?? false),
|
||||
style: TextStyle(color: theme.getColorFor(ThemeCode.buttonSecondary)),
|
||||
inputFormatters: widget.numeric? [
|
||||
FilteringTextInputFormatter.digitsOnly
|
||||
] : [],
|
||||
decoration: InputDecoration(
|
||||
counterText: "",
|
||||
hintText: widget.hint,
|
||||
labelText: widget.label,
|
||||
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
borderSide: BorderSide(color: theme.getColorFor(ThemeCode.textPrimary)),
|
||||
gapPadding: 16
|
||||
return Column(
|
||||
spacing: 8,
|
||||
children: [
|
||||
?widget.label == '' ? null : Align(
|
||||
alignment: Alignment.bottomLeft,
|
||||
child: Text(
|
||||
widget.label,
|
||||
style: TextStyle(fontSize: 14, letterSpacing: 0),
|
||||
)
|
||||
),
|
||||
suffixIcon: widget.showPassword!=null ? IconButton(
|
||||
icon: Icon(widget.showPassword!
|
||||
? Icons.visibility_off
|
||||
: Icons.visibility),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
widget.showPassword = !widget.showPassword!;
|
||||
});
|
||||
},
|
||||
) : null,
|
||||
),
|
||||
minLines: widget.lines ?? 1,
|
||||
maxLines: widget.lines ?? 1,
|
||||
maxLength: widget.length,
|
||||
onChanged: widget.onChanged ?? (_)=>{},
|
||||
TextFormField(
|
||||
keyboardType: widget.numeric? TextInputType.number : TextInputType.text,
|
||||
obscureText: !(widget.showPassword ?? true),
|
||||
enableSuggestions: widget.showPassword ?? true,
|
||||
autocorrect: !(widget.showPassword ?? false),
|
||||
style: TextStyle(color: Color(0xFF4B4B4B)),
|
||||
inputFormatters: widget.numeric? [
|
||||
FilteringTextInputFormatter.digitsOnly
|
||||
] : [],
|
||||
decoration: InputDecoration(
|
||||
counterText: "",
|
||||
hintText: widget.hint,
|
||||
//labelText: widget.label,
|
||||
//floatingLabelBehavior: FloatingLabelBehavior.always,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
borderSide: BorderSide(color: Color(0xFF4B4B4B)),
|
||||
gapPadding: 16
|
||||
),
|
||||
suffixIcon: widget.showPassword!=null ? IconButton(
|
||||
icon: Icon(widget.showPassword!
|
||||
? Icons.visibility_off
|
||||
: Icons.visibility),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
widget.showPassword = !widget.showPassword!;
|
||||
});
|
||||
},
|
||||
) : null,
|
||||
),
|
||||
minLines: widget.lines ?? 1,
|
||||
maxLines: widget.lines ?? 1,
|
||||
maxLength: widget.length,
|
||||
onChanged: widget.onChanged ?? (_)=>{},
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -12,15 +12,15 @@ class ProgressBar extends ConsumerWidget{
|
||||
final Color foregroundColor;
|
||||
final Color textColor;
|
||||
|
||||
const ProgressBar(
|
||||
this.max,
|
||||
this.value,
|
||||
this.height,
|
||||
this.textSize,
|
||||
this.textSecondarySize,
|
||||
this.backgroundColor,
|
||||
this.foregroundColor,
|
||||
this.textColor,
|
||||
const ProgressBar({
|
||||
required this.max,
|
||||
required this.value,
|
||||
required this.height,
|
||||
required this.textSize,
|
||||
required this.textSecondarySize,
|
||||
required this.backgroundColor,
|
||||
required this.foregroundColor,
|
||||
required this.textColor,}
|
||||
);
|
||||
|
||||
@override
|
||||
|
||||
@@ -9,25 +9,24 @@ enum MessageType {
|
||||
success
|
||||
}
|
||||
|
||||
class CustomSnackBar extends ConsumerWidget{
|
||||
final MessageType type;
|
||||
class CustomSnackBar extends StatelessWidget{
|
||||
final MessageType? type;
|
||||
final String message;
|
||||
|
||||
CustomSnackBar({
|
||||
const CustomSnackBar({
|
||||
super.key,
|
||||
this.type = MessageType.info,
|
||||
this.type,
|
||||
required this.message,
|
||||
});
|
||||
|
||||
@override
|
||||
SnackBar build(BuildContext context, WidgetRef ref) {
|
||||
final theme = ref.watch(themePortProvider);
|
||||
SnackBar build(BuildContext context) {
|
||||
|
||||
late final Color foregroundColor;
|
||||
late final Color backgroundColor;
|
||||
late final IconData icon;
|
||||
|
||||
switch (type){
|
||||
switch (type??MessageType.info){
|
||||
case MessageType.info:
|
||||
backgroundColor = Color(0xFFE3EFFD);
|
||||
foregroundColor = Color(0xFF1F4ECF);
|
||||
@@ -57,7 +56,7 @@ class CustomSnackBar extends ConsumerWidget{
|
||||
spacing: 8,
|
||||
children: [
|
||||
Icon(icon, color: foregroundColor),
|
||||
Expanded(child: Text(message, style: TextStyle(color: theme.getColorFor(ThemeCode.textPrimary), fontSize: 14)))
|
||||
Expanded(child: Text(message, style: TextStyle(color: Color(0xFF4B4B4B), fontSize: 14)))
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -18,11 +18,12 @@ class MoneyText extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final units = text.split(".")[0];
|
||||
final cents = ",${text.split(".")[1]}";
|
||||
final split = text.contains(".") ? text.split(".") : text.split("€");
|
||||
final mainText = split[0];
|
||||
var secondaryText = text.contains(".") ? ",${split[1]}" : "€${split[1]}";
|
||||
|
||||
return Text.rich(TextSpan(
|
||||
text: units,
|
||||
text: mainText,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: size,
|
||||
@@ -31,7 +32,7 @@ class MoneyText extends StatelessWidget {
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: cents,
|
||||
text: secondaryText,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: secondarySize ?? size,
|
||||
|
||||
@@ -20,12 +20,14 @@ dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^5.0.0
|
||||
golden_toolkit: ^0.15.0
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
||||
# The following section is specific to Flutter packages.
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
|
||||
# To add assets to your package, add an assets section, like this:
|
||||
# assets:
|
||||
|
||||
201
packages/design_system/test/widget_test.dart
Normal file
201
packages/design_system/test/widget_test.dart
Normal file
@@ -0,0 +1,201 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:golden_toolkit/golden_toolkit.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
|
||||
void main() {
|
||||
themePackages();
|
||||
|
||||
testGoldens('Step Indicator', (tester) async {
|
||||
final widget = (int step)=>StepIndicator(max: 3, current: step, color: Colors.blueAccent);
|
||||
final builder = GoldenBuilder.column()
|
||||
..addScenario('step -1', widget(-1))
|
||||
..addScenario('step 0', widget(0))
|
||||
..addScenario('step 1', widget(1))
|
||||
..addScenario('step 2', widget(2))
|
||||
..addScenario('step 3', widget(3))
|
||||
..addScenario('step 4', widget(4));
|
||||
await tester.pumpWidgetBuilder(builder.build());
|
||||
await screenMatchesGolden(tester, 'step_indicator');
|
||||
});
|
||||
|
||||
testGoldens('Progress Bar - Small', (tester) async {
|
||||
final widget = (double value, double max) => ProgressBar(max: max, value: value, height: 24, textSize: 16, textSecondarySize: 12, backgroundColor: Colors.blueGrey, foregroundColor: Colors.blueAccent, textColor: Colors.black87);
|
||||
|
||||
final builder = GoldenBuilder.column()
|
||||
..addScenario('full', widget(100, 100))
|
||||
..addScenario('empty', widget(0, 100))
|
||||
..addScenario('half', widget(75, 150))
|
||||
..addScenario('overflowing', widget(200, 150))
|
||||
//..addScenario('negative', widget(-20, 83))
|
||||
..addScenario('tiny value', widget(2.15, 150));
|
||||
await tester.pumpWidgetBuilder(builder.build());
|
||||
await screenMatchesGolden(tester, 'progress_bar_small');
|
||||
});
|
||||
|
||||
testGoldens('Progress Bar - Large', (tester) async {
|
||||
final widget = (double value, double max) => ProgressBar(max: max, value: value, height: 83, textSize: 40, textSecondarySize: 24, backgroundColor: Colors.blueGrey, foregroundColor: Colors.blueAccent, textColor: Colors.black87);
|
||||
|
||||
final builder = GoldenBuilder.grid(columns: 3, widthToHeightRatio: 1)
|
||||
..addScenario('full', widget(100, 100))
|
||||
..addScenario('empty', widget(0, 100))
|
||||
..addScenario('half', widget(75, 150))
|
||||
..addScenario('overflowing', widget(200, 150))
|
||||
..addScenario('tiny value', widget(2.15, 150));
|
||||
await tester.pumpWidgetBuilder(builder.build());
|
||||
await screenMatchesGolden(tester, 'progress_bar_large');
|
||||
});
|
||||
|
||||
testGoldens('Text Field', (tester) async {
|
||||
|
||||
final builder = GoldenBuilder.grid(columns: 3, widthToHeightRatio: 1)
|
||||
..addScenario('basic', SizedBox(height: 70, width: 250, child: CustomTextField()))
|
||||
..addScenario('hint', SizedBox(height: 70, width: 250, child: CustomTextField(hint: "type something")))
|
||||
..addScenario('label', SizedBox(height: 100, width: 250, child: CustomTextField(hint: "type something", label: "text input")))
|
||||
..addScenario('numeric', SizedBox(height: 70, width: 250, child: CustomTextField(numeric: true)))
|
||||
..addScenario('password', SizedBox(height: 70, width: 250, child: CustomTextField(showPassword: false)))
|
||||
..addScenario('multiline', SizedBox(height: 200, width: 250, child: CustomTextField(lines: 4)));
|
||||
|
||||
await tester.pumpWidgetBuilder(builder.build());
|
||||
await screenMatchesGolden(tester, 'textfield');
|
||||
});
|
||||
|
||||
testGoldens('Primary Button', (tester) async {
|
||||
final widget = ({onPressed, text}) => SizedBox(
|
||||
height: 70, width: 250,
|
||||
child:PrimaryButton(onPressed: onPressed, text: text, color: Colors.blueAccent)
|
||||
);
|
||||
|
||||
final builder = GoldenBuilder.grid(columns: 2, widthToHeightRatio: 1)
|
||||
..addScenario('empty', SizedBox(height: 70, width: 250, child: PrimaryButton(onPressed: ()=>{}, text: "", color: Colors.blueAccent)))
|
||||
..addScenario('basic', SizedBox(height: 70, width: 250, child: PrimaryButton(onPressed: ()=>{}, text: "press me", color: Colors.blueAccent)))
|
||||
..addScenario('round', SizedBox(height: 70, width: 250, child: PrimaryButton(onPressed: ()=>{}, radius: 100, text: "press me", color: Colors.blueAccent)))
|
||||
..addScenario('small', SizedBox(height: 70, width: 250, child: PrimaryButton(onPressed: ()=>{}, width: 100, text: "press me", color: Colors.blueAccent)));
|
||||
|
||||
await tester.pumpWidgetBuilder(builder.build());
|
||||
|
||||
await screenMatchesGolden(tester, 'primary_button');
|
||||
});
|
||||
|
||||
testGoldens('Text Button', (tester) async {
|
||||
final tapTarget = Key("tap-target");
|
||||
|
||||
final builder = GoldenBuilder.column()
|
||||
..addScenario('empty', CustomTextButton(onPressed: ()=>{}, text: ""))
|
||||
..addScenario('basic', CustomTextButton(onPressed: ()=>{}, text: "press me"))
|
||||
..addScenario('tapped', CustomTextButton(onPressed: ()=>{}, text: "press me", key: tapTarget))
|
||||
..addScenario('large text', CustomTextButton(onPressed: ()=>{}, text: "press me", size: 40, weight: FontWeight.w500))
|
||||
..addScenario('small text', CustomTextButton(onPressed: ()=>{}, text: "press me", size: 10))
|
||||
..addScenario('colored', CustomTextButton(onPressed: ()=>{}, text: "press me", color: Colors.blueAccent));
|
||||
await tester.pumpWidgetBuilder(builder.build());
|
||||
await tester.tap(find.byKey(tapTarget));
|
||||
await tester.pump();
|
||||
await screenMatchesGolden(tester, 'text_button');
|
||||
});
|
||||
|
||||
testGoldens('Money Text', (tester) async {
|
||||
final builder = GoldenBuilder.column()
|
||||
..addScenario('basic', MoneyText(text: "29.13€", size: 20, color: Colors.blueAccent))
|
||||
..addScenario('without cents', MoneyText(text: "50€", size: 20, color: Colors.blueAccent))
|
||||
..addScenario('different sizes', MoneyText(text: "29.13€", size: 30, secondarySize: 15, color: Colors.blueAccent))
|
||||
..addScenario('different sizes without cents', MoneyText(text: "50€", size: 30, secondarySize: 15, color: Colors.blueAccent));
|
||||
|
||||
await tester.pumpWidgetBuilder(builder.build());
|
||||
|
||||
await screenMatchesGolden(tester, 'money_text');
|
||||
});
|
||||
|
||||
testGoldens('Secondary Button', (tester) async {
|
||||
final widget = ({onPressed, text}) => SizedBox(
|
||||
height: 70, width: 250,
|
||||
child:SecondaryButton(onPressed: onPressed, text: text)
|
||||
);
|
||||
|
||||
final builder = GoldenBuilder.grid(columns: 3, widthToHeightRatio: 1)
|
||||
..addScenario('empty', SizedBox(height: 70, width: 250, child:SecondaryButton(onPressed: ()=>{}, text: "")))
|
||||
..addScenario('text', SizedBox(height: 70, width: 250, child:SecondaryButton(onPressed: ()=>{}, text: "press me")))
|
||||
..addScenario('icon', SizedBox(height: 70, width: 250, child:SecondaryButton(onPressed: ()=>{}, icon: Icons.account_circle_outlined)))
|
||||
..addScenario('colored', SizedBox(height: 70, width: 250, child:SecondaryButton(onPressed: ()=>{}, text: "press me", color: Colors.blueAccent,)))
|
||||
..addScenario('small', SizedBox(height: 70, width: 250, child:SecondaryButton(onPressed: ()=>{}, width: 100, text: "press me")))
|
||||
..addScenario('round', SizedBox(height: 70, width: 250, child:SecondaryButton(onPressed: ()=>{}, radius: 100, text: "press me", color: Colors.blueAccent,)));
|
||||
|
||||
await tester.pumpWidgetBuilder(builder.build());
|
||||
|
||||
await screenMatchesGolden(tester, 'secondary_button');
|
||||
});
|
||||
|
||||
final snackbarTest = ({message, type, testName}) {
|
||||
testGoldens('Snackbar $testName', (tester) async {
|
||||
const Key tapTarget = Key('tap-target');
|
||||
|
||||
final widget = () =>
|
||||
SizedBox(
|
||||
width: 800,
|
||||
height: 600,
|
||||
child: MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
CustomSnackBar(
|
||||
message: message,
|
||||
type: type,
|
||||
).build(context)
|
||||
);
|
||||
},
|
||||
behavior: HitTestBehavior.opaque,
|
||||
key: tapTarget,
|
||||
);
|
||||
}
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final builder = DeviceBuilder()
|
||||
..overrideDevicesForAllScenarios(devices: [
|
||||
Device(size: Size(750, 550), name: 'base')
|
||||
])
|
||||
..addScenario(name: testName, widget: widget());
|
||||
|
||||
await tester.pumpWidgetBuilder(builder.build());
|
||||
await tester.tap(find.byKey(tapTarget));
|
||||
|
||||
await screenMatchesGolden(tester, 'snackbar/$testName');
|
||||
});
|
||||
};
|
||||
|
||||
final shortText = "Mensaje de prueba";
|
||||
final longText = "Mensaje de prueba largo para comprobar los casos en los que el texto ocupa varias líneas";
|
||||
|
||||
snackbarTest(message: "", type: null, testName: "default_empty");
|
||||
snackbarTest(message: shortText, type: null, testName: "default");
|
||||
snackbarTest(message: longText, type: null, testName: "default_long_text");
|
||||
snackbarTest(message: "", type: MessageType.info, testName: "info_empty");
|
||||
snackbarTest(message: shortText, type: MessageType.info, testName: "info");
|
||||
snackbarTest(message: longText, type: MessageType.info, testName: "info_long_text");
|
||||
snackbarTest(message: "", type: MessageType.success, testName: "success_empty");
|
||||
snackbarTest(message: shortText, type: MessageType.success, testName: "success");
|
||||
snackbarTest(message: longText, type: MessageType.success, testName: "success_long_text");
|
||||
snackbarTest(message: "", type: MessageType.warning, testName: "warning_empty");
|
||||
snackbarTest(message: shortText, type: MessageType.warning, testName: "warning");
|
||||
snackbarTest(message: longText, type: MessageType.warning, testName: "warning_long_text");
|
||||
snackbarTest(message: "", type: MessageType.error, testName: "error_empty");
|
||||
snackbarTest(message: shortText, type: MessageType.error, testName: "error");
|
||||
snackbarTest(message: longText, type: MessageType.error, testName: "error_long_text");
|
||||
|
||||
testGoldens('Dropdown', (tester) async {
|
||||
final List<Widget> emptyList = [];
|
||||
final List<Widget> shortList = [Text("A"), Text("B"), Text("C")];
|
||||
|
||||
final builder = GoldenBuilder.column()
|
||||
..addScenario('empty', CustomDropdown(items: emptyList, onChanged: (_)=>{}, width: 200))
|
||||
..addScenario('initial value', CustomDropdown(items: shortList, value: 1, onChanged: (_)=>{}, width: 300))
|
||||
..addScenario('hint', CustomDropdown(items: shortList, hint: "choose an option", onChanged: (_)=>{}))
|
||||
..addScenario('label', CustomDropdown(items: shortList, label: "select", onChanged: (_)=>{}, width: 200));
|
||||
await tester.pumpWidgetBuilder(builder.build());
|
||||
await screenMatchesGolden(tester, 'dropdown');
|
||||
});
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
export 'src/models/kid.dart';
|
||||
export 'src/models/task.dart';
|
||||
export 'src/models/savings_goal.dart';
|
||||
export 'src/widgets/line_graph.dart';
|
||||
export 'src/widgets/deposit_block.dart';
|
||||
export 'src/screens/connection_error_screen.dart';
|
||||
export 'src/screens/server_error_screen.dart';
|
||||
export 'src/screens/no_plan_error_screen.dart';
|
||||
export 'src/widgets/wallet_balance_block.dart';
|
||||
export 'src/widgets/wallet_balance_block.dart';
|
||||
12
packages/sf_shared/lib/src/models/savings_goal.dart
Normal file
12
packages/sf_shared/lib/src/models/savings_goal.dart
Normal file
@@ -0,0 +1,12 @@
|
||||
class SavingsGoal{
|
||||
|
||||
final String name;
|
||||
final double goal;
|
||||
final double saved;
|
||||
|
||||
const SavingsGoal({
|
||||
required this.name,
|
||||
required this.goal,
|
||||
required this.saved
|
||||
});
|
||||
}
|
||||
21
packages/sf_shared/lib/src/models/task.dart
Normal file
21
packages/sf_shared/lib/src/models/task.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
class Task{
|
||||
|
||||
final double rewardAmount;
|
||||
final List<Subtask> subtasks;
|
||||
|
||||
const Task({
|
||||
required this.rewardAmount,
|
||||
this.subtasks = const []
|
||||
});
|
||||
}
|
||||
|
||||
class Subtask{
|
||||
|
||||
final String name;
|
||||
final bool completed;
|
||||
|
||||
const Subtask({
|
||||
required this.name,
|
||||
required this.completed
|
||||
});
|
||||
}
|
||||
@@ -32,7 +32,7 @@ class DepositBlock extends ConsumerWidget {
|
||||
spacing: 16,
|
||||
children: [
|
||||
Row(
|
||||
spacing: 10,
|
||||
spacing: 16,
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomTextField(
|
||||
@@ -41,20 +41,15 @@ class DepositBlock extends ConsumerWidget {
|
||||
numeric: true,
|
||||
),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () => {},
|
||||
style: ButtonStyle(
|
||||
backgroundColor: WidgetStatePropertyAll<Color>(
|
||||
theme.getColorFor(ThemeCode.buttonPrimary),
|
||||
),
|
||||
shape: WidgetStatePropertyAll(RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(18))
|
||||
))
|
||||
Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: PrimaryButton(
|
||||
onPressed: () => {},
|
||||
text: "Ingresar",
|
||||
color: theme.getColorFor(ThemeCode.buttonPrimary),
|
||||
padding: 24,
|
||||
),
|
||||
child: SizedBox(
|
||||
height: 60,
|
||||
child: Center(child: Text("Ingresar", style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500)))),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
Align(
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
class LineGraph extends ConsumerStatefulWidget {
|
||||
final lines = [[0,1,0,1,0,1,0],[1,0,1,0,1,0,1]];
|
||||
final lines = [[0,1,0,3,0,1,0],[1,0,1,0,4,0,1]];
|
||||
late final maxValue = lines.map((x)=>x.reduce(max)).reduce(max);
|
||||
|
||||
LineGraph({super.key});
|
||||
|
||||
@@ -42,25 +45,22 @@ class LineGraphState extends ConsumerState<LineGraph> {
|
||||
Text("Gastos", style: TextStyle(fontWeight: FontWeight.w500, fontSize: 18)),
|
||||
Spacer(),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 0),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
color: theme.getColorFor(ThemeCode.backgroundSecondary),
|
||||
),
|
||||
child: DropdownButton(
|
||||
underline: Container(),
|
||||
child:
|
||||
CustomDropdown(
|
||||
value: timeSpan,
|
||||
onChanged: (String? value) {
|
||||
setState(() {
|
||||
timeSpan = value;
|
||||
});
|
||||
},
|
||||
dropdownColor: theme.getColorFor(ThemeCode.backgroundPrimary),
|
||||
items: [
|
||||
DropdownMenuItem(value: "day", child: Text("Hoy", style: TextStyle(fontSize: 14, letterSpacing: 0))),
|
||||
DropdownMenuItem(value: "week", child: Text("Esta semana", style: TextStyle(fontSize: 14, letterSpacing: 0))),
|
||||
DropdownMenuItem(value: "month", child: Text("Este mes", style: TextStyle(fontSize: 14, letterSpacing: 0))),
|
||||
]
|
||||
Text("Hoy", style: TextStyle(fontSize: 14, letterSpacing: 0)),
|
||||
Text("Esta semana", style: TextStyle(fontSize: 14, letterSpacing: 0)),
|
||||
Text("Este mes", style: TextStyle(fontSize: 14, letterSpacing: 0))
|
||||
],
|
||||
values: ["day", "week", "month"],
|
||||
onChanged: (value)=>{},
|
||||
color: Colors.transparent,
|
||||
width: 151,
|
||||
),
|
||||
)
|
||||
]),
|
||||
@@ -136,33 +136,26 @@ class LineGraphState extends ConsumerState<LineGraph> {
|
||||
top: const BorderSide(color: Colors.transparent),
|
||||
),
|
||||
),
|
||||
lineBarsData: [
|
||||
lineBarsData: List<LineChartBarData>.generate(widget.lines.length, (int i)=>
|
||||
LineChartBarData(
|
||||
isCurved: true,
|
||||
color: Colors.pink,
|
||||
barWidth: 5,
|
||||
isStrokeCapRound: true,
|
||||
dotData: const FlDotData(show: false),
|
||||
belowBarData: BarAreaData(show: false),
|
||||
spots: List<FlSpot>.generate(days.length, (int index){
|
||||
return FlSpot(index.toDouble(), (index+1)%2);
|
||||
})
|
||||
isCurved: true,
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.bottomCenter,
|
||||
end: Alignment.topCenter,
|
||||
colors: theme.getCardColorFor(i)
|
||||
),
|
||||
barWidth: 5,
|
||||
isStrokeCapRound: true,
|
||||
dotData: const FlDotData(show: false),
|
||||
belowBarData: BarAreaData(show: false),
|
||||
spots: List<FlSpot>.generate(widget.lines[i].length, (int j){
|
||||
return FlSpot(j.toDouble(), widget.lines[i][j].toDouble());
|
||||
})
|
||||
),
|
||||
LineChartBarData(
|
||||
isCurved: true,
|
||||
color: Colors.cyan,
|
||||
barWidth: 5,
|
||||
isStrokeCapRound: true,
|
||||
dotData: const FlDotData(show: false),
|
||||
belowBarData: BarAreaData(show: false),
|
||||
spots: List<FlSpot>.generate(days.length, (int index){
|
||||
return FlSpot(index.toDouble(), index%2);
|
||||
})
|
||||
),
|
||||
],
|
||||
),
|
||||
minX: 0,
|
||||
maxX: days.length-1,
|
||||
maxY: 1,
|
||||
maxY: widget.maxValue.toDouble(),
|
||||
minY: 0,
|
||||
))
|
||||
)
|
||||
|
||||
@@ -49,8 +49,26 @@ class WalletBalanceBlock extends ConsumerWidget {
|
||||
Spacer(),
|
||||
Text("$savingsPlan€")
|
||||
]),
|
||||
ProgressBar(savingsPlan, savings, 24, 16, 12, theme.getColorFor(ThemeCode.backgroundSecondary), theme.getColorFor(ThemeCode.backgroundTertiary), theme.getColorFor(ThemeCode.textPrimary)),
|
||||
ProgressBar(max, value, 83, 40, 24, theme.getColorFor(ThemeCode.backgroundTertiary), theme.getColorFor(ThemeCode.buttonPrimary), theme.getColorFor(ThemeCode.textSecondary)),
|
||||
ProgressBar(
|
||||
max: savingsPlan,
|
||||
value: savings,
|
||||
height: 24,
|
||||
textSize: 16,
|
||||
textSecondarySize: 12,
|
||||
backgroundColor: theme.getColorFor(ThemeCode.backgroundSecondary),
|
||||
foregroundColor: theme.getColorFor(ThemeCode.backgroundTertiary),
|
||||
textColor: theme.getColorFor(ThemeCode.textPrimary)
|
||||
),
|
||||
ProgressBar(
|
||||
max: max,
|
||||
value: value,
|
||||
height: 83,
|
||||
textSize: 40,
|
||||
textSecondarySize: 24,
|
||||
backgroundColor: theme.getColorFor(ThemeCode.backgroundTertiary),
|
||||
foregroundColor: theme.getColorFor(ThemeCode.buttonPrimary),
|
||||
textColor: theme.getColorFor(ThemeCode.textSecondary)
|
||||
),
|
||||
Center(child: Text("Disponible")),
|
||||
],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user