From 9905ed8642724e9cce60e1e86b55625131ce3eb6 Mon Sep 17 00:00:00 2001 From: Aboud Date: Tue, 20 Jan 2026 10:34:29 -0800 Subject: [PATCH 01/29] feat: add email to User entity --- lib/domain/entity/user.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/domain/entity/user.dart b/lib/domain/entity/user.dart index 479ca6af..ec78b721 100644 --- a/lib/domain/entity/user.dart +++ b/lib/domain/entity/user.dart @@ -1,9 +1,11 @@ class User { final int id; final String username; + final String email; User({ required this.id, + required this.email, required this.username, }); } \ No newline at end of file From 645c7a1ce9768344c37628ad9fd05dc090a2584c Mon Sep 17 00:00:00 2001 From: Aboud Date: Tue, 20 Jan 2026 10:38:45 -0800 Subject: [PATCH 02/29] feat: add authentication validator --- lib/domain/validator/authentication_validator.dart | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 lib/domain/validator/authentication_validator.dart diff --git a/lib/domain/validator/authentication_validator.dart b/lib/domain/validator/authentication_validator.dart new file mode 100644 index 00000000..3a0c9ed6 --- /dev/null +++ b/lib/domain/validator/authentication_validator.dart @@ -0,0 +1,11 @@ +class AuthenticationValidator { + bool isEmailValid(String email) { + return RegExp(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$').hasMatch(email); + } + + bool isPasswordValid(String password) { + return password.length >= 8 && + password.contains(RegExp(r'[A-Z]')) && + password.contains(RegExp(r'[!@#$%^&*(),.?":{}|<>]')); + } +} From 9aa80ce65158aece8d741ed82753ab7accb6eb27 Mon Sep 17 00:00:00 2001 From: Aboud Date: Tue, 20 Jan 2026 10:40:13 -0800 Subject: [PATCH 03/29] feat: add create account cubit --- .../cubit/create_account_cubit.dart | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 lib/presentation/createAccount/cubit/create_account_cubit.dart diff --git a/lib/presentation/createAccount/cubit/create_account_cubit.dart b/lib/presentation/createAccount/cubit/create_account_cubit.dart new file mode 100644 index 00000000..f81b0929 --- /dev/null +++ b/lib/presentation/createAccount/cubit/create_account_cubit.dart @@ -0,0 +1,50 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:moneyplus/domain/repository/authentication_repository.dart'; + +import '../../../domain/validator/authentication_validator.dart'; +import 'create_account_state.dart'; + +class CreateAccountCubit extends Cubit { + final AuthenticationValidator _validator; + final AuthenticationRepository _authenticationRepository; + + CreateAccountCubit(this._validator, this._authenticationRepository) + : super(CreateAccountState()); + + void emailChanged(String value) { + emit(state.copyWith(email: value)); + enable(); + } + + void nameChanged(String value) { + emit(state.copyWith(name: value)); + enable(); + } + + void passwordChanged(String value) { + emit(state.copyWith(password: value)); + if (_validator.isPasswordValid(state.password)) { + enable(); + } else { + emit(state.copyWith(isEnabled: false)); + } + } + + void enable() { + if (_validator.isEmailValid(state.email) && + state.name.isNotEmpty && + _validator.isPasswordValid(state.password)) { + emit(state.copyWith(isEnabled: true)); + } else { + emit(state.copyWith(isEnabled: false)); + } + } + + void submit() { + _authenticationRepository.register(state.toEntity(), state.password); + } + + void togglePasswordVisibility() { + emit(state.copyWith(isPasswordVisible: !state.isPasswordVisible)); + } +} From 805d7cd1b56bf75bdb4816a2e4df12327f9f656e Mon Sep 17 00:00:00 2001 From: Aboud Date: Tue, 20 Jan 2026 10:40:28 -0800 Subject: [PATCH 04/29] feat: add create account screen --- .../screen/create_account_screen.dart | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 lib/presentation/createAccount/screen/create_account_screen.dart diff --git a/lib/presentation/createAccount/screen/create_account_screen.dart b/lib/presentation/createAccount/screen/create_account_screen.dart new file mode 100644 index 00000000..5667cdc8 --- /dev/null +++ b/lib/presentation/createAccount/screen/create_account_screen.dart @@ -0,0 +1,173 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:moneyplus/design_system/assets/app_assets.dart'; +import 'package:moneyplus/design_system/widgets/app_logo.dart'; +import 'package:svg_flutter/svg.dart'; + +import '../../../design_system/component/buttons/button/default_button.dart'; +import '../../../design_system/theme/money_extension_context.dart'; +import '../../../design_system/widgets/app_bar.dart'; +import '../../../design_system/widgets/text_field.dart'; +import '../../../domain/repository/authentication_repository.dart'; +import '../../../domain/validator/authentication_validator.dart'; +import '../cubit/create_account_cubit.dart'; +import '../cubit/create_account_state.dart'; + +class CreateAccountScreen extends StatefulWidget { + const CreateAccountScreen({super.key}); + + @override + State createState() => _CreateAccountScreenState(); +} + +class _CreateAccountScreenState extends State { + @override + Widget build(BuildContext context) { + final colors = context.colors; + final typography = context.typography; + + return BlocProvider( + create: (context) => CreateAccountCubit( + context.read(), + context.read(), + ), + child: BlocBuilder( + builder: (context, state) { + final cubit = context.read(); + return Scaffold( + appBar: CustomAppBar( + title: "Create Account", + trailing: AppLogo(assetPath: AppAssets.appBrand), + leading: AppBarCircleButton( + assetPath: AppAssets.icArrowLeft, + onTap: () => Navigator.pop(context), + ), + ), + resizeToAvoidBottomInset: true, + body: Container( + color: colors.surface, + padding: const EdgeInsets.all(16), + child: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Create new account", + style: typography.headline.medium.copyWith( + color: colors.title, + ), + ), + const SizedBox(height: 4), + Text( + "Start taking control of your money", + style: typography.body.small.copyWith(color: colors.body), + ), + const SizedBox(height: 24), + _textField( + hint: 'Email', + value: state.email, + onChanged: cubit.emailChanged, + assetPath: AppAssets.icMail, + ), + const SizedBox(height: 12), + _textField( + hint: 'Name', + value: state.name, + onChanged: cubit.nameChanged, + assetPath: AppAssets.icUser, + ), + const SizedBox(height: 12), + _passwordTextField( + password: state.password, + hint: 'Password', + isPasswordVisible: state.isPasswordVisible, + onPasswordChanged: cubit.passwordChanged, + onToggleVisibility: cubit.togglePasswordVisibility, + ), + const SizedBox(height: 8), + Text( + "*Use at least 8 characters, Contain at least one capital letter and one symbol.", + style: typography.label.small.copyWith( + color: colors.yellow, + ), + ), + ], + ), + ), + ), + + bottomNavigationBar: AnimatedPadding( + duration: const Duration(milliseconds: 150), + curve: Curves.easeOut, + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).viewInsets.bottom + 16, + left: 16, + right: 16, + ), + child: SafeArea( + child: DefaultButton( + text: "Create Account", + onPressed: () => cubit.submit(), + isEnabled: state.isEnabled, + isLoading: state.isLoading, + ), + ), + ), + ); + }, + ), + ); + } + + Widget _textField({ + required String hint, + required String value, + required ValueChanged onChanged, + required String assetPath, + }) { + return MTextField( + hint: hint, + value: value, + onChanged: (value) => onChanged(value), + minLines: 1, + maxLines: 1, + leading: Padding( + padding: EdgeInsetsGeometry.only(top: 14, bottom: 14, right: 8), + child: SvgPicture.asset(assetPath), + ), + ); + } + + Widget _passwordTextField({ + required String password, + required String hint, + required bool isPasswordVisible, + required ValueChanged onPasswordChanged, + required VoidCallback onToggleVisibility, + }) { + return MTextField( + hint: hint, + value: password, + onChanged: onPasswordChanged, + obscureText: !isPasswordVisible, + minLines: 1, + maxLines: 1, + leading: Padding( + padding: const EdgeInsetsDirectional.only(top: 14, bottom: 14, end: 8), + child: SvgPicture.asset(AppAssets.icSquareLock), + ), + trailing: Padding( + padding: EdgeInsetsGeometry.only(top: 2), + child: IconButton( + onPressed: onToggleVisibility, + icon: SvgPicture.asset( + isPasswordVisible ? AppAssets.openEye : AppAssets.closedEye, + height: 20, + width: 20, + ), + ), + ), + ); + } +} From 3d1e821826fd4859f8449fa92542a5ad4afd1e89 Mon Sep 17 00:00:00 2001 From: Aboud Date: Tue, 20 Jan 2026 10:41:11 -0800 Subject: [PATCH 05/29] feat: add create account state --- .../cubit/create_account_state.dart | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 lib/presentation/createAccount/cubit/create_account_state.dart diff --git a/lib/presentation/createAccount/cubit/create_account_state.dart b/lib/presentation/createAccount/cubit/create_account_state.dart new file mode 100644 index 00000000..a9b09166 --- /dev/null +++ b/lib/presentation/createAccount/cubit/create_account_state.dart @@ -0,0 +1,46 @@ +import '../../../domain/entity/user.dart'; + +class CreateAccountState { + final String email; + final String name; + final String password; + final bool isLoading; + final bool isEnabled; + final bool isPasswordVisible; + + const CreateAccountState({ + this.email = "", + this.name = "", + this.password = "", + this.isLoading = false, + this.isEnabled = false, + this.isPasswordVisible = false, + }); + + CreateAccountState copyWith({ + String? email, + String? name, + String? password, + bool? isLoading, + bool? isEnabled, + bool? showPasswordRequirements, + bool? isPasswordVisible, + }) { + return CreateAccountState( + email: email ?? this.email, + name: name ?? this.name, + password: password ?? this.password, + isLoading: isLoading ?? this.isLoading, + isEnabled: isEnabled ?? this.isEnabled, + isPasswordVisible: isPasswordVisible ?? this.isPasswordVisible, + ); + } + + User toEntity() { + return User( + id: 0, + email: email, + username: name, + ); + } +} From 3595aba4de9cab66f9ed1dbe8c20349568dedd19 Mon Sep 17 00:00:00 2001 From: Aboud Date: Tue, 20 Jan 2026 10:41:33 -0800 Subject: [PATCH 06/29] feat: add register method to AuthenticationRepository --- lib/domain/repository/authentication_repository.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/domain/repository/authentication_repository.dart b/lib/domain/repository/authentication_repository.dart index 0304779f..308c7e04 100644 --- a/lib/domain/repository/authentication_repository.dart +++ b/lib/domain/repository/authentication_repository.dart @@ -1,3 +1,5 @@ -abstract class AuthenticationRepository { +import '../entity/user.dart'; +abstract class AuthenticationRepository { + void register(User user, String password); } \ No newline at end of file From f24a35479c8decdbb1e7eed1e84298e0f6bbd2d1 Mon Sep 17 00:00:00 2001 From: Aboud Date: Tue, 20 Jan 2026 10:41:45 -0800 Subject: [PATCH 07/29] feat: implement AuthenticationRepository --- .../repository/authentication_repository.dart | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/data/repository/authentication_repository.dart b/lib/data/repository/authentication_repository.dart index 952d71c9..30270dfe 100644 --- a/lib/data/repository/authentication_repository.dart +++ b/lib/data/repository/authentication_repository.dart @@ -1,5 +1,18 @@ +import 'package:moneyplus/data/service/supabase_service.dart'; +import 'package:moneyplus/domain/entity/user.dart' as user_entity; import '../../domain/repository/authentication_repository.dart'; -class AuthenticationRepositoryImp implements AuthenticationRepository { +class AuthenticationRepositoryImpl implements AuthenticationRepository { + final SupabaseService _supabaseService; + AuthenticationRepositoryImpl(this._supabaseService); + @override + Future register(user_entity.User user, String password) async { + final client = await _supabaseService.getClient(); + await client.auth.signUp( + email: user.email, + password: password, + data: { "name" : user.username} + ); + } } \ No newline at end of file From 8e489d8ee9c466926a9003476e082619e48a58b3 Mon Sep 17 00:00:00 2001 From: Aboud Date: Tue, 20 Jan 2026 10:42:13 -0800 Subject: [PATCH 08/29] feat: set app bar background color --- lib/design_system/widgets/app_bar.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/design_system/widgets/app_bar.dart b/lib/design_system/widgets/app_bar.dart index 384c0899..dabcfc59 100644 --- a/lib/design_system/widgets/app_bar.dart +++ b/lib/design_system/widgets/app_bar.dart @@ -27,6 +27,7 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { titleSpacing: 8, leadingWidth: leadingWidth, automaticallyImplyLeading: false, + backgroundColor: colors.surfaceLow, title: title != null ? Text(title!, style: typo.title.small.copyWith(color: contentColor)) From 9a9b74164c3ad2f37f77fb98d807f9f0494b5d6c Mon Sep 17 00:00:00 2001 From: Aboud Date: Tue, 20 Jan 2026 10:42:29 -0800 Subject: [PATCH 09/29] feat: add square lock, mail, and user icons --- assets/icons/ic_heroicons_outline.svg | 3 +++ assets/icons/ic_mail.svg | 5 +++++ assets/icons/ic_square_lock.svg | 5 +++++ assets/icons/ic_user_square.svg | 6 ++++++ lib/design_system/assets/app_assets.dart | 4 +++- 5 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 assets/icons/ic_heroicons_outline.svg create mode 100644 assets/icons/ic_mail.svg create mode 100644 assets/icons/ic_square_lock.svg create mode 100644 assets/icons/ic_user_square.svg diff --git a/assets/icons/ic_heroicons_outline.svg b/assets/icons/ic_heroicons_outline.svg new file mode 100644 index 00000000..252c1a5a --- /dev/null +++ b/assets/icons/ic_heroicons_outline.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/ic_mail.svg b/assets/icons/ic_mail.svg new file mode 100644 index 00000000..a7f4e69c --- /dev/null +++ b/assets/icons/ic_mail.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/icons/ic_square_lock.svg b/assets/icons/ic_square_lock.svg new file mode 100644 index 00000000..6a663ccc --- /dev/null +++ b/assets/icons/ic_square_lock.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/icons/ic_user_square.svg b/assets/icons/ic_user_square.svg new file mode 100644 index 00000000..5e88a421 --- /dev/null +++ b/assets/icons/ic_user_square.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/lib/design_system/assets/app_assets.dart b/lib/design_system/assets/app_assets.dart index 2e61cadd..1e3113c4 100644 --- a/lib/design_system/assets/app_assets.dart +++ b/lib/design_system/assets/app_assets.dart @@ -29,5 +29,7 @@ class AppAssets { static const String openEye = '$_icons/ic_open_eye.svg'; static const String tradeUp = '$_icons/ic_trade_up.svg'; static const String tradeDown = '$_icons/ic_trade_down.svg'; - + static const String icSquareLock = '$_icons/ic_square_lock.svg'; + static const String icMail = '$_icons/ic_mail.svg'; + static const String icUser = '$_icons/ic_user_square.svg'; } From 1fd3d6dabe761738b2685358782dce25d92b2934 Mon Sep 17 00:00:00 2001 From: Aboud Date: Tue, 20 Jan 2026 10:43:40 -0800 Subject: [PATCH 10/29] feat: add create account dependencies --- lib/di/injection.dart | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/di/injection.dart b/lib/di/injection.dart index f3f932b9..3e34f4b7 100644 --- a/lib/di/injection.dart +++ b/lib/di/injection.dart @@ -4,6 +4,8 @@ import '../data/repository/authentication_repository.dart'; import '../data/service/app_secrets_provider.dart'; import '../data/service/supabase_service.dart'; import '../domain/repository/authentication_repository.dart'; +import '../domain/validator/authentication_validator.dart'; +import '../presentation/createAccount/cubit/create_account_cubit.dart'; import '../presentation/home/cubit/home_cubit.dart'; import '../presentation/login/cubit/login_cubit.dart'; @@ -15,9 +17,18 @@ void initDI() { () => SupabaseService(appSecretsProvider: getIt()), ); getIt.registerLazySingleton( - () => AuthenticationRepositoryImp(), + () => AuthenticationRepositoryImpl(getIt()), ); getIt.registerFactory(() => LoginCubit()); getIt.registerFactory(() => HomeCubit()); + getIt.registerFactory( + () => AuthenticationValidator(), + ); + getIt.registerFactory( + () => CreateAccountCubit( + getIt(), + getIt(), + ), + ); } From 5b64b5db6cb8b6a04600eb0ae1be81c4eb6150a0 Mon Sep 17 00:00:00 2001 From: Aboud Date: Tue, 20 Jan 2026 10:44:16 -0800 Subject: [PATCH 11/29] feat: add uuid dependency --- pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/pubspec.yaml b/pubspec.yaml index 9e11fe7a..293b38b6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,6 +36,7 @@ dependencies: flutter_svg: ^2.0.9 flutter_dotenv: ^6.0.0 supabase_flutter: ^2.12.0 + uuid: ^4.5.1 logging: ^1.3.0 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. From 0904f4ebd006dac17150333ba5bee4b3089876e6 Mon Sep 17 00:00:00 2001 From: Aboud Date: Wed, 21 Jan 2026 04:27:22 -0800 Subject: [PATCH 12/29] feat: add create account localization --- lib/core/l10n/app_ar.arb | 11 +++++++++- lib/core/l10n/app_en.arb | 12 ++++++++++- .../screen/create_account_screen.dart | 20 ++++++++++--------- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/lib/core/l10n/app_ar.arb b/lib/core/l10n/app_ar.arb index b68dc164..aab255bc 100644 --- a/lib/core/l10n/app_ar.arb +++ b/lib/core/l10n/app_ar.arb @@ -2,5 +2,14 @@ "income": "الدخل", "expense": "المصروف", "moneyAmount": "{amount} {currency} ", - "date": "التاريخ" + "date": "التاريخ", + + "createAccount": "إنشاء حساب", + "createNewAccount": "إنشاء حساب جديد", + "startTakingControl": "ابدأ بالتحكم في أموالك", + "email": "البريد الإلكتروني", + "name": "الاسم", + "password": "كلمة المرور", + "passwordLimit": "*استخدم 8 أحرف على الأقل، وتأكد من وجود حرف كبير ورمز واحد على الأقل.", + "create": "إنشاء حساب" } diff --git a/lib/core/l10n/app_en.arb b/lib/core/l10n/app_en.arb index 56084342..1583142d 100644 --- a/lib/core/l10n/app_en.arb +++ b/lib/core/l10n/app_en.arb @@ -8,5 +8,15 @@ "currency": {} } }, - "date": "Date" + "date": "Date", + + "createAccount": "Create Account", + "createNewAccount": "Create new account", + "startTakingControl": "Start taking control of your money", + "email": "Email", + "name": "Name", + "password": "Password", + "passwordLimit": "*Use at least 8 characters, Contain at least one capital letter and one symbol.", + "create": "Create" + } \ No newline at end of file diff --git a/lib/presentation/createAccount/screen/create_account_screen.dart b/lib/presentation/createAccount/screen/create_account_screen.dart index 5667cdc8..b89aa4e0 100644 --- a/lib/presentation/createAccount/screen/create_account_screen.dart +++ b/lib/presentation/createAccount/screen/create_account_screen.dart @@ -4,6 +4,7 @@ import 'package:moneyplus/design_system/assets/app_assets.dart'; import 'package:moneyplus/design_system/widgets/app_logo.dart'; import 'package:svg_flutter/svg.dart'; +import '../../../core/l10n/app_localizations.dart'; import '../../../design_system/component/buttons/button/default_button.dart'; import '../../../design_system/theme/money_extension_context.dart'; import '../../../design_system/widgets/app_bar.dart'; @@ -25,6 +26,7 @@ class _CreateAccountScreenState extends State { Widget build(BuildContext context) { final colors = context.colors; final typography = context.typography; + final l10n = AppLocalizations.of(context)!; return BlocProvider( create: (context) => CreateAccountCubit( @@ -36,7 +38,7 @@ class _CreateAccountScreenState extends State { final cubit = context.read(); return Scaffold( appBar: CustomAppBar( - title: "Create Account", + title: l10n.createAccount, trailing: AppLogo(assetPath: AppAssets.appBrand), leading: AppBarCircleButton( assetPath: AppAssets.icArrowLeft, @@ -53,26 +55,26 @@ class _CreateAccountScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "Create new account", + l10n.createNewAccount, style: typography.headline.medium.copyWith( color: colors.title, ), ), const SizedBox(height: 4), Text( - "Start taking control of your money", + l10n.startTakingControl, style: typography.body.small.copyWith(color: colors.body), ), const SizedBox(height: 24), _textField( - hint: 'Email', + hint: l10n.email, value: state.email, onChanged: cubit.emailChanged, assetPath: AppAssets.icMail, ), const SizedBox(height: 12), _textField( - hint: 'Name', + hint: l10n.name, value: state.name, onChanged: cubit.nameChanged, assetPath: AppAssets.icUser, @@ -80,14 +82,14 @@ class _CreateAccountScreenState extends State { const SizedBox(height: 12), _passwordTextField( password: state.password, - hint: 'Password', + hint: l10n.password, isPasswordVisible: state.isPasswordVisible, onPasswordChanged: cubit.passwordChanged, onToggleVisibility: cubit.togglePasswordVisibility, ), const SizedBox(height: 8), Text( - "*Use at least 8 characters, Contain at least one capital letter and one symbol.", + l10n.passwordLimit, style: typography.label.small.copyWith( color: colors.yellow, ), @@ -107,7 +109,7 @@ class _CreateAccountScreenState extends State { ), child: SafeArea( child: DefaultButton( - text: "Create Account", + text: l10n.create, onPressed: () => cubit.submit(), isEnabled: state.isEnabled, isLoading: state.isLoading, @@ -133,7 +135,7 @@ class _CreateAccountScreenState extends State { minLines: 1, maxLines: 1, leading: Padding( - padding: EdgeInsetsGeometry.only(top: 14, bottom: 14, right: 8), + padding: EdgeInsetsGeometry.directional(top: 14, bottom: 14, end: 8), child: SvgPicture.asset(assetPath), ), ); From d4f7128b4c5467edf03366e099c3170b60ad50e0 Mon Sep 17 00:00:00 2001 From: Aboud Date: Wed, 21 Jan 2026 04:35:23 -0800 Subject: [PATCH 13/29] refactor: change user id type from int to String --- lib/domain/entity/user.dart | 2 +- lib/presentation/createAccount/cubit/create_account_state.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/domain/entity/user.dart b/lib/domain/entity/user.dart index ec78b721..2d65bda2 100644 --- a/lib/domain/entity/user.dart +++ b/lib/domain/entity/user.dart @@ -1,5 +1,5 @@ class User { - final int id; + final String id; final String username; final String email; diff --git a/lib/presentation/createAccount/cubit/create_account_state.dart b/lib/presentation/createAccount/cubit/create_account_state.dart index a9b09166..cc4c5834 100644 --- a/lib/presentation/createAccount/cubit/create_account_state.dart +++ b/lib/presentation/createAccount/cubit/create_account_state.dart @@ -38,7 +38,7 @@ class CreateAccountState { User toEntity() { return User( - id: 0, + id: "", email: email, username: name, ); From 03c831a1b33c3b311ecd59cddeb22ba44bbf4314 Mon Sep 17 00:00:00 2001 From: Aboud Date: Fri, 23 Jan 2026 07:44:41 -0800 Subject: [PATCH 14/29] feat: use gitIt instead of context.read --- .../createAccount/screen/create_account_screen.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/presentation/createAccount/screen/create_account_screen.dart b/lib/presentation/createAccount/screen/create_account_screen.dart index b89aa4e0..b88390d9 100644 --- a/lib/presentation/createAccount/screen/create_account_screen.dart +++ b/lib/presentation/createAccount/screen/create_account_screen.dart @@ -9,6 +9,7 @@ import '../../../design_system/component/buttons/button/default_button.dart'; import '../../../design_system/theme/money_extension_context.dart'; import '../../../design_system/widgets/app_bar.dart'; import '../../../design_system/widgets/text_field.dart'; +import '../../../di/cubit_injection.dart'; import '../../../domain/repository/authentication_repository.dart'; import '../../../domain/validator/authentication_validator.dart'; import '../cubit/create_account_cubit.dart'; @@ -30,8 +31,8 @@ class _CreateAccountScreenState extends State { return BlocProvider( create: (context) => CreateAccountCubit( - context.read(), - context.read(), + getIt(), + getIt(), ), child: BlocBuilder( builder: (context, state) { From f6270addd76a2a6c2a07ab84e56f2e18c7072642 Mon Sep 17 00:00:00 2001 From: Aboud Date: Sun, 25 Jan 2026 11:19:14 -0800 Subject: [PATCH 15/29] feat: add is_complete field to user sign up data --- lib/data/repository/authentication_repository.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/data/repository/authentication_repository.dart b/lib/data/repository/authentication_repository.dart index 30270dfe..b734a0fc 100644 --- a/lib/data/repository/authentication_repository.dart +++ b/lib/data/repository/authentication_repository.dart @@ -1,9 +1,11 @@ import 'package:moneyplus/data/service/supabase_service.dart'; import 'package:moneyplus/domain/entity/user.dart' as user_entity; + import '../../domain/repository/authentication_repository.dart'; class AuthenticationRepositoryImpl implements AuthenticationRepository { final SupabaseService _supabaseService; + AuthenticationRepositoryImpl(this._supabaseService); @override @@ -12,7 +14,7 @@ class AuthenticationRepositoryImpl implements AuthenticationRepository { await client.auth.signUp( email: user.email, password: password, - data: { "name" : user.username} + data: {"name": user.username, "is_complete": false}, ); } -} \ No newline at end of file +} From 307b36c6e8a1d998195b1d6bfdf795fab421d2b5 Mon Sep 17 00:00:00 2001 From: Aboud Date: Sun, 25 Jan 2026 11:21:40 -0800 Subject: [PATCH 16/29] refactor: reorder name and email fields --- .../screen/create_account_screen.dart | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/presentation/createAccount/screen/create_account_screen.dart b/lib/presentation/createAccount/screen/create_account_screen.dart index b88390d9..70245c62 100644 --- a/lib/presentation/createAccount/screen/create_account_screen.dart +++ b/lib/presentation/createAccount/screen/create_account_screen.dart @@ -5,9 +5,9 @@ import 'package:moneyplus/design_system/widgets/app_logo.dart'; import 'package:svg_flutter/svg.dart'; import '../../../core/l10n/app_localizations.dart'; -import '../../../design_system/component/buttons/button/default_button.dart'; import '../../../design_system/theme/money_extension_context.dart'; import '../../../design_system/widgets/app_bar.dart'; +import '../../../design_system/widgets/buttons/button/default_button.dart'; import '../../../design_system/widgets/text_field.dart'; import '../../../di/cubit_injection.dart'; import '../../../domain/repository/authentication_repository.dart'; @@ -67,13 +67,6 @@ class _CreateAccountScreenState extends State { style: typography.body.small.copyWith(color: colors.body), ), const SizedBox(height: 24), - _textField( - hint: l10n.email, - value: state.email, - onChanged: cubit.emailChanged, - assetPath: AppAssets.icMail, - ), - const SizedBox(height: 12), _textField( hint: l10n.name, value: state.name, @@ -81,6 +74,13 @@ class _CreateAccountScreenState extends State { assetPath: AppAssets.icUser, ), const SizedBox(height: 12), + _textField( + hint: l10n.email, + value: state.email, + onChanged: cubit.emailChanged, + assetPath: AppAssets.icMail, + ), + const SizedBox(height: 12), _passwordTextField( password: state.password, hint: l10n.password, From 221b277bbf22b5268da2c434fd4f30ea5c62e336 Mon Sep 17 00:00:00 2001 From: Aboud Date: Sun, 25 Jan 2026 11:30:40 -0800 Subject: [PATCH 17/29] chore: add trailing comma in app_ar.arb --- lib/core/l10n/app_ar.arb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/core/l10n/app_ar.arb b/lib/core/l10n/app_ar.arb index 176dc461..f76aebf6 100644 --- a/lib/core/l10n/app_ar.arb +++ b/lib/core/l10n/app_ar.arb @@ -16,8 +16,7 @@ "next": "التالي", "finishSetup": "إنهاء الإعداد", "stepOf": "الخطوة {current} من {total}", - "stepOfTotal": "الخطوة {current} من {total}" - + "stepOfTotal": "الخطوة {current} من {total}", "createAccount": "إنشاء حساب", "createNewAccount": "إنشاء حساب جديد", "startTakingControl": "ابدأ بالتحكم في أموالك", From 8cc18eabdadd5b66ece6bfa2e1ddff327da46a02 Mon Sep 17 00:00:00 2001 From: Aboud Date: Tue, 27 Jan 2026 14:02:04 -0800 Subject: [PATCH 18/29] resolve conflict --- .../repository/authentication_repository.dart | 17 +++--- lib/di/injection.dart | 8 +-- .../screen/create_account_screen.dart | 2 +- pubspec.lock | 56 +++++++++++++++++++ 4 files changed, 69 insertions(+), 14 deletions(-) diff --git a/lib/data/repository/authentication_repository.dart b/lib/data/repository/authentication_repository.dart index 64aadb15..4d190ae9 100644 --- a/lib/data/repository/authentication_repository.dart +++ b/lib/data/repository/authentication_repository.dart @@ -1,21 +1,17 @@ -import 'package:moneyplus/data/service/supabase_service.dart'; -import 'package:moneyplus/domain/entity/user.dart' as user_entity; - - import 'package:flutter/foundation.dart'; import 'package:google_sign_in/google_sign_in.dart'; +import 'package:moneyplus/data/service/supabase_service.dart'; +import 'package:moneyplus/domain/entity/user.dart' as user_entity; import 'package:supabase_flutter/supabase_flutter.dart'; import '../../core/app_constants.dart'; import '../../domain/repository/authentication_repository.dart'; import '../service/app_secrets_provider.dart'; -import '../service/supabase_service.dart'; - class AuthenticationRepositoryImpl implements AuthenticationRepository { - final SupabaseService _supabaseService; + final SupabaseService supabaseService; + final AppSecretsProvider appSecrets; - AuthenticationRepositoryImpl(this._supabaseService); AuthenticationRepositoryImpl({ required this.supabaseService, required this.appSecrets, @@ -23,13 +19,14 @@ class AuthenticationRepositoryImpl implements AuthenticationRepository { @override Future register(user_entity.User user, String password) async { - final client = await _supabaseService.getClient(); + final client = await supabaseService.getClient(); await client.auth.signUp( email: user.email, password: password, data: {"name": user.username, "is_complete": false}, ); } + @override void signInWithGoogle() async { try { @@ -69,6 +66,7 @@ class AuthenticationRepositoryImpl implements AuthenticationRepository { static const String _googleWebClientId = "GOOGLE_WEB_CLIENT_ID"; static const String _googleIosClientId = "GOOGLE_IOS_CLIENT_ID"; static const List _googleScopes = ['email', 'profile', 'openid']; + @override Stream get onAuthStateChange { final supabaseClientFuture = supabaseService.getClient(); @@ -85,6 +83,7 @@ class AuthenticationRepositoryImpl implements AuthenticationRepository { redirectTo: AppConstants.resetPasswordRedirect, ); } + @override Future updatePassword(String password) async { final client = await supabaseService.getClient(); diff --git a/lib/di/injection.dart b/lib/di/injection.dart index 8f491ae6..e88eb822 100644 --- a/lib/di/injection.dart +++ b/lib/di/injection.dart @@ -17,10 +17,10 @@ void initDI() { () => SupabaseService(appSecretsProvider: getIt()), ); getIt.registerLazySingleton( - () => AuthenticationRepositoryImpl( - supabaseService: getIt(), - appSecrets: getIt(), - ), + () => AuthenticationRepositoryImpl( + supabaseService: getIt(), + appSecrets: getIt(), + ), ); getIt.registerFactory(() => LoginCubit()); diff --git a/lib/presentation/createAccount/screen/create_account_screen.dart b/lib/presentation/createAccount/screen/create_account_screen.dart index 70245c62..7094eab5 100644 --- a/lib/presentation/createAccount/screen/create_account_screen.dart +++ b/lib/presentation/createAccount/screen/create_account_screen.dart @@ -78,7 +78,7 @@ class _CreateAccountScreenState extends State { hint: l10n.email, value: state.email, onChanged: cubit.emailChanged, - assetPath: AppAssets.icMail, + assetPath: AppAssets.icEmail, ), const SizedBox(height: 12), _passwordTextField( diff --git a/pubspec.lock b/pubspec.lock index 1d8f2112..d663afd5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -389,6 +389,54 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.3" + google_identity_services_web: + dependency: transitive + description: + name: google_identity_services_web + sha256: "5d187c46dc59e02646e10fe82665fc3884a9b71bc1c90c2b8b749316d33ee454" + url: "https://pub.dev" + source: hosted + version: "0.3.3+1" + google_sign_in: + dependency: "direct main" + description: + name: google_sign_in + sha256: "521031b65853b4409b8213c0387d57edaad7e2a949ce6dea0d8b2afc9cb29763" + url: "https://pub.dev" + source: hosted + version: "7.2.0" + google_sign_in_android: + dependency: transitive + description: + name: google_sign_in_android + sha256: "5ec98ab35387c68c0050495bb211bd88375873723a80fae7c2e9266ea0bdd8bb" + url: "https://pub.dev" + source: hosted + version: "7.2.7" + google_sign_in_ios: + dependency: transitive + description: + name: google_sign_in_ios + sha256: "234fc2830b55d1bbeb7e05662967691f5994143ff43dc70d3f139d1bbb3b8fb2" + url: "https://pub.dev" + source: hosted + version: "6.2.5" + google_sign_in_platform_interface: + dependency: transitive + description: + name: google_sign_in_platform_interface + sha256: "7f59208c42b415a3cca203571128d6f84f885fead2d5b53eb65a9e27f2965bb5" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + google_sign_in_web: + dependency: transitive + description: + name: google_sign_in_web + sha256: "2fc1f941e6443b2d6984f4056a727a3eaeab15d8ee99ba7125d79029be75a1da" + url: "https://pub.dev" + source: hosted + version: "1.1.0" gotrue: dependency: transitive description: @@ -1066,6 +1114,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.5" + uuid: + dependency: "direct main" + description: + name: uuid + sha256: a11b666489b1954e01d992f3d601b1804a33937b5a8fe677bd26b8a9f96f96e8 + url: "https://pub.dev" + source: hosted + version: "4.5.2" vector_graphics: dependency: transitive description: From 506672b927957db4404850c7ceab8720afb4c18d Mon Sep 17 00:00:00 2001 From: Aboud Date: Fri, 30 Jan 2026 15:04:10 -0800 Subject: [PATCH 19/29] feat: add create account route --- lib/presentation/navigation/routes.dart | 12 +++++++++++ lib/presentation/navigation/routes.g.dart | 26 ++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/lib/presentation/navigation/routes.dart b/lib/presentation/navigation/routes.dart index f0dc325e..c9c70cf0 100644 --- a/lib/presentation/navigation/routes.dart +++ b/lib/presentation/navigation/routes.dart @@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; +import 'package:moneyplus/presentation/createAccount/screen/create_account_screen.dart'; import 'package:moneyplus/presentation/home/screen/home_screen.dart'; import 'package:moneyplus/presentation/login/screen/login_screen.dart'; @@ -55,3 +56,14 @@ class HomeRoute extends GoRouteData with $HomeRoute { return HomeScreen(); } } + +@TypedGoRoute(path: '/createAccount') +@immutable +class CreateAccountRoute extends GoRouteData with $CreateAccountRoute { + const CreateAccountRoute(); + + @override + Widget build(BuildContext context, GoRouterState state) { + return CreateAccountScreen(); + } +} \ No newline at end of file diff --git a/lib/presentation/navigation/routes.g.dart b/lib/presentation/navigation/routes.g.dart index 90f3bb29..a34abc93 100644 --- a/lib/presentation/navigation/routes.g.dart +++ b/lib/presentation/navigation/routes.g.dart @@ -6,7 +6,7 @@ part of 'routes.dart'; // GoRouterGenerator // ************************************************************************** -List get $appRoutes => [$onBoardingRoute, $loginRoute, $homeRoute]; +List get $appRoutes => [$onBoardingRoute, $loginRoute, $homeRoute, $createAccountRoute]; RouteBase get $onBoardingRoute => GoRouteData.$route(path: '/', factory: $OnBoardingRoute._fromState); @@ -77,3 +77,27 @@ mixin $HomeRoute on GoRouteData { @override void replace(BuildContext context) => context.replace(location); } + +RouteBase get $createAccountRoute => + GoRouteData.$route(path: '/createAccount', factory: $CreateAccountRoute._fromState); + +mixin $CreateAccountRoute on GoRouteData { + static $CreateAccountRoute _fromState(GoRouterState state) => + const CreateAccountRoute(); + + @override + String get location => GoRouteData.$location('/createAccount'); + + @override + void go(BuildContext context) => context.go(location); + + @override + Future push(BuildContext context) => context.push(location); + + @override + void pushReplacement(BuildContext context) => + context.pushReplacement(location); + + @override + void replace(BuildContext context) => context.replace(location); +} From 97826f98e703076d83c38b4dc5c95d49ed35a69b Mon Sep 17 00:00:00 2001 From: Aboud Date: Fri, 30 Jan 2026 15:04:22 -0800 Subject: [PATCH 20/29] feat: implement navigation to create account screen --- lib/presentation/login/screen/login_screen.dart | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/presentation/login/screen/login_screen.dart b/lib/presentation/login/screen/login_screen.dart index ee08c023..8823f19d 100644 --- a/lib/presentation/login/screen/login_screen.dart +++ b/lib/presentation/login/screen/login_screen.dart @@ -4,6 +4,8 @@ import 'package:moneyplus/design_system/assets/app_assets.dart'; import 'package:moneyplus/design_system/theme/money_colors.dart'; import 'package:moneyplus/design_system/theme/money_typography.dart'; import 'package:moneyplus/design_system/widgets/buttons/money_button.dart'; +import 'package:moneyplus/presentation/navigation/routes.dart'; + import '../../../core/l10n/app_localizations.dart'; import '../../../design_system/theme/money_extension_context.dart'; import '../../../design_system/widgets/snack_bar.dart'; @@ -137,16 +139,12 @@ class _LoginHeader extends StatelessWidget { children: [ Text( localizations.login_welcome_title, - style: typography.headline.medium.copyWith( - color: colors.title, - ), + style: typography.headline.medium.copyWith(color: colors.title), ), const SizedBox(height: 4), Text( localizations.login_welcome_subtitle, - style: typography.body.small.copyWith( - color: colors.body, - ), + style: typography.body.small.copyWith(color: colors.body), ), ], ); @@ -229,7 +227,9 @@ class _SocialMediaButtons extends StatelessWidget { ), SizedBox(height: 8), MoneyButton( - onPressed: () {}, + onPressed: () { + CreateAccountRoute().push(context); + }, backgroundColor: colors.surfaceLow, disabledBackgroundColor: Colors.red, borderWidth: 0.5, From 8015f3e10dc4cec85d79111e282b869dba1e171d Mon Sep 17 00:00:00 2001 From: Aboud Date: Fri, 30 Jan 2026 15:04:37 -0800 Subject: [PATCH 21/29] feat: handle create account errors and display snackbar --- .../repository/authentication_repository.dart | 28 +++++++++++++------ .../repository/authentication_repository.dart | 2 +- .../cubit/create_account_cubit.dart | 18 ++++++++++-- .../cubit/create_account_state.dart | 6 +++- .../screen/create_account_screen.dart | 18 ++++++++++-- 5 files changed, 57 insertions(+), 15 deletions(-) diff --git a/lib/data/repository/authentication_repository.dart b/lib/data/repository/authentication_repository.dart index dd7a6917..f58298ee 100644 --- a/lib/data/repository/authentication_repository.dart +++ b/lib/data/repository/authentication_repository.dart @@ -23,13 +23,25 @@ class AuthenticationRepositoryImpl implements AuthenticationRepository { }); @override - Future register(User user, String password) async { - final client = await supabaseService.getClient(); - await client.auth.signUp( - email: user.email, - password: password, - data: {"name": user.name, "is_complete": false}, - ); + Future> register(User user, String password) async { + try { + final client = await supabaseService.getClient(); + final response = await client.auth.signUp( + email: user.email, + password: password, + data: {"name": user.name, "is_complete": false}, + ); + + if (response.user != null) { + return Result.success(null); + } else { + return Result.error(ErrorModel('User data is null')); + } + } on AuthException catch (error) { + return Result.error(SupabaseAuthError.fromAuthException(error)); + } catch (error) { + return Result.error(ErrorModel(error.toString())); + } } @override @@ -83,7 +95,7 @@ class AuthenticationRepositoryImpl implements AuthenticationRepository { @override Future resetPasswordForEmail(String email) async { final client = await supabaseService.getClient(); - await client.auth.resetPasswordForEmail( + final response = await client.auth.resetPasswordForEmail( email, redirectTo: AppConstants.resetPasswordRedirect, ); diff --git a/lib/domain/repository/authentication_repository.dart b/lib/domain/repository/authentication_repository.dart index e04e13ae..da61734d 100644 --- a/lib/domain/repository/authentication_repository.dart +++ b/lib/domain/repository/authentication_repository.dart @@ -8,7 +8,7 @@ import '../../core/errors/result.dart'; import '../../domain/entity/user.dart'; abstract class AuthenticationRepository { - void register(user_entity.User user, String password); + Future> register(user_entity.User user, String password); void signInWithGoogle(); Future resetPasswordForEmail(String email); diff --git a/lib/presentation/createAccount/cubit/create_account_cubit.dart b/lib/presentation/createAccount/cubit/create_account_cubit.dart index f81b0929..3aa07554 100644 --- a/lib/presentation/createAccount/cubit/create_account_cubit.dart +++ b/lib/presentation/createAccount/cubit/create_account_cubit.dart @@ -40,8 +40,22 @@ class CreateAccountCubit extends Cubit { } } - void submit() { - _authenticationRepository.register(state.toEntity(), state.password); + Future submit() async { + emit(state.copyWith(isLoading: true)); + final result = await _authenticationRepository.register( + state.toEntity(), + state.password, + ); + result.when( + onSuccess: (user) { + emit(state.copyWith(isLoading: false)); + }, + onError: (error){ + emit(state.copyWith(isLoading: false)); + emit(state.copyWith(errorMessage: error.message)); + emit(state.copyWith(errorMessage: null)); + }, + ); } void togglePasswordVisibility() { diff --git a/lib/presentation/createAccount/cubit/create_account_state.dart b/lib/presentation/createAccount/cubit/create_account_state.dart index cc4c5834..4704908f 100644 --- a/lib/presentation/createAccount/cubit/create_account_state.dart +++ b/lib/presentation/createAccount/cubit/create_account_state.dart @@ -7,6 +7,7 @@ class CreateAccountState { final bool isLoading; final bool isEnabled; final bool isPasswordVisible; + final String? errorMessage; const CreateAccountState({ this.email = "", @@ -15,6 +16,7 @@ class CreateAccountState { this.isLoading = false, this.isEnabled = false, this.isPasswordVisible = false, + this.errorMessage, }); CreateAccountState copyWith({ @@ -25,6 +27,7 @@ class CreateAccountState { bool? isEnabled, bool? showPasswordRequirements, bool? isPasswordVisible, + String? errorMessage, }) { return CreateAccountState( email: email ?? this.email, @@ -33,6 +36,7 @@ class CreateAccountState { isLoading: isLoading ?? this.isLoading, isEnabled: isEnabled ?? this.isEnabled, isPasswordVisible: isPasswordVisible ?? this.isPasswordVisible, + errorMessage: errorMessage ?? this.errorMessage, ); } @@ -40,7 +44,7 @@ class CreateAccountState { return User( id: "", email: email, - username: name, + name: name, ); } } diff --git a/lib/presentation/createAccount/screen/create_account_screen.dart b/lib/presentation/createAccount/screen/create_account_screen.dart index 7094eab5..476418d6 100644 --- a/lib/presentation/createAccount/screen/create_account_screen.dart +++ b/lib/presentation/createAccount/screen/create_account_screen.dart @@ -8,6 +8,7 @@ import '../../../core/l10n/app_localizations.dart'; import '../../../design_system/theme/money_extension_context.dart'; import '../../../design_system/widgets/app_bar.dart'; import '../../../design_system/widgets/buttons/button/default_button.dart'; +import '../../../design_system/widgets/snack_bar.dart'; import '../../../design_system/widgets/text_field.dart'; import '../../../di/cubit_injection.dart'; import '../../../domain/repository/authentication_repository.dart'; @@ -34,7 +35,15 @@ class _CreateAccountScreenState extends State { getIt(), getIt(), ), - child: BlocBuilder( + child: BlocConsumer( + listener: (context, state) { + if (state.errorMessage != null) { + MSnackBar.error( + message: state.errorMessage!, + title: l10n.error, + ).showSnackBar(context: context); + } + }, builder: (context, state) { final cubit = context.read(); return Scaffold( @@ -136,7 +145,7 @@ class _CreateAccountScreenState extends State { minLines: 1, maxLines: 1, leading: Padding( - padding: EdgeInsetsGeometry.directional(top: 14, bottom: 14, end: 8), + padding: EdgeInsetsGeometry.symmetric(vertical: 14, horizontal: 8), child: SvgPicture.asset(assetPath), ), ); @@ -157,7 +166,10 @@ class _CreateAccountScreenState extends State { minLines: 1, maxLines: 1, leading: Padding( - padding: const EdgeInsetsDirectional.only(top: 14, bottom: 14, end: 8), + padding: const EdgeInsetsDirectional.symmetric( + vertical: 14, + horizontal: 8, + ), child: SvgPicture.asset(AppAssets.icSquareLock), ), trailing: Padding( From 2782c542fdb12aea7b0542903f07e02d40d3e0ac Mon Sep 17 00:00:00 2001 From: Aboud Date: Fri, 30 Jan 2026 15:13:24 -0800 Subject: [PATCH 22/29] refactor: rename l10n to localizations for consistency --- .../screen/create_account_screen.dart | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/presentation/createAccount/screen/create_account_screen.dart b/lib/presentation/createAccount/screen/create_account_screen.dart index 476418d6..e35f50ad 100644 --- a/lib/presentation/createAccount/screen/create_account_screen.dart +++ b/lib/presentation/createAccount/screen/create_account_screen.dart @@ -28,7 +28,7 @@ class _CreateAccountScreenState extends State { Widget build(BuildContext context) { final colors = context.colors; final typography = context.typography; - final l10n = AppLocalizations.of(context)!; + final localizations = AppLocalizations.of(context)!; return BlocProvider( create: (context) => CreateAccountCubit( @@ -40,7 +40,7 @@ class _CreateAccountScreenState extends State { if (state.errorMessage != null) { MSnackBar.error( message: state.errorMessage!, - title: l10n.error, + title: localizations.error, ).showSnackBar(context: context); } }, @@ -48,7 +48,7 @@ class _CreateAccountScreenState extends State { final cubit = context.read(); return Scaffold( appBar: CustomAppBar( - title: l10n.createAccount, + title: localizations.createAccount, trailing: AppLogo(assetPath: AppAssets.appBrand), leading: AppBarCircleButton( assetPath: AppAssets.icArrowLeft, @@ -65,26 +65,26 @@ class _CreateAccountScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - l10n.createNewAccount, + localizations.createNewAccount, style: typography.headline.medium.copyWith( color: colors.title, ), ), const SizedBox(height: 4), Text( - l10n.startTakingControl, + localizations.startTakingControl, style: typography.body.small.copyWith(color: colors.body), ), const SizedBox(height: 24), _textField( - hint: l10n.name, + hint: localizations.name, value: state.name, onChanged: cubit.nameChanged, assetPath: AppAssets.icUser, ), const SizedBox(height: 12), _textField( - hint: l10n.email, + hint: localizations.email, value: state.email, onChanged: cubit.emailChanged, assetPath: AppAssets.icEmail, @@ -92,14 +92,14 @@ class _CreateAccountScreenState extends State { const SizedBox(height: 12), _passwordTextField( password: state.password, - hint: l10n.password, + hint: localizations.password, isPasswordVisible: state.isPasswordVisible, onPasswordChanged: cubit.passwordChanged, onToggleVisibility: cubit.togglePasswordVisibility, ), const SizedBox(height: 8), Text( - l10n.passwordLimit, + localizations.passwordLimit, style: typography.label.small.copyWith( color: colors.yellow, ), @@ -119,7 +119,7 @@ class _CreateAccountScreenState extends State { ), child: SafeArea( child: DefaultButton( - text: l10n.create, + text: localizations.create, onPressed: () => cubit.submit(), isEnabled: state.isEnabled, isLoading: state.isLoading, From c15f85bd584ae88e8b70188c45d94cbbb5ffb347 Mon Sep 17 00:00:00 2001 From: Aboud Date: Fri, 30 Jan 2026 15:14:30 -0800 Subject: [PATCH 23/29] feat: add spending trend localization strings --- lib/core/l10n/app_en.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/core/l10n/app_en.arb b/lib/core/l10n/app_en.arb index 00f712c8..8dfddac1 100644 --- a/lib/core/l10n/app_en.arb +++ b/lib/core/l10n/app_en.arb @@ -8,6 +8,8 @@ "currency": {} } }, + "spendingTrend": "Spending Trend", + "noDataAvailable": "No data available", "date": "Date", "setUpYourAccount": "Let’s set up your account", "setSalary": "Set Salary", From 8e000c7b99b547ea72478224fecac5c30ec53ee4 Mon Sep 17 00:00:00 2001 From: Aboud Date: Fri, 30 Jan 2026 15:18:23 -0800 Subject: [PATCH 24/29] refactor: rename email icon asset for consistency --- lib/design_system/assets/app_assets.dart | 1 - lib/presentation/login/widget/login_form.dart | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/design_system/assets/app_assets.dart b/lib/design_system/assets/app_assets.dart index e0f06e65..e99407a4 100644 --- a/lib/design_system/assets/app_assets.dart +++ b/lib/design_system/assets/app_assets.dart @@ -43,7 +43,6 @@ class AppAssets { static const String eyeClose = "$_icons/ic_eye_close.svg"; static const String eyeOpen = "$_icons/ic_eye_open.svg"; static const String lock = "$_icons/ic_lock.svg"; - static const String email = "$_icons/ic_email.svg"; static const String google = "$_icons/ic_google.svg"; static const String icSquareLock = '$_icons/ic_square_lock.svg'; static const String icUser = '$_icons/ic_user_square.svg'; diff --git a/lib/presentation/login/widget/login_form.dart b/lib/presentation/login/widget/login_form.dart index 3e0de06f..ddf918ed 100644 --- a/lib/presentation/login/widget/login_form.dart +++ b/lib/presentation/login/widget/login_form.dart @@ -34,7 +34,7 @@ class _LoginFormState extends State { hint: localizations.login_email_hint, leading: Padding( padding: const EdgeInsets.symmetric(vertical: 14, horizontal: 8), - child: SvgPicture.asset(AppAssets.email), + child: SvgPicture.asset(AppAssets.icEmail), ), onChanged: widget.onEmailChanged, keyboardType: TextInputType.emailAddress, From e58ffa6e30db401b1b91c4b1301f73584895f7ba Mon Sep 17 00:00:00 2001 From: Aboud Date: Fri, 30 Jan 2026 22:01:56 -0800 Subject: [PATCH 25/29] fix: di error --- .../createAccount/screen/create_account_screen.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/createAccount/screen/create_account_screen.dart b/lib/presentation/createAccount/screen/create_account_screen.dart index e35f50ad..31151328 100644 --- a/lib/presentation/createAccount/screen/create_account_screen.dart +++ b/lib/presentation/createAccount/screen/create_account_screen.dart @@ -10,7 +10,7 @@ import '../../../design_system/widgets/app_bar.dart'; import '../../../design_system/widgets/buttons/button/default_button.dart'; import '../../../design_system/widgets/snack_bar.dart'; import '../../../design_system/widgets/text_field.dart'; -import '../../../di/cubit_injection.dart'; +import '../../../di/injection.dart'; import '../../../domain/repository/authentication_repository.dart'; import '../../../domain/validator/authentication_validator.dart'; import '../cubit/create_account_cubit.dart'; From 542aa1fbf23ac9a46d83119225cb230d9a2ad86c Mon Sep 17 00:00:00 2001 From: Aboud Date: Thu, 5 Feb 2026 01:48:54 -0800 Subject: [PATCH 26/29] resolve conflict --- lib/design_system/widgets/app_bar.dart | 1 - lib/presentation/createAccount/screen/create_account_screen.dart | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/design_system/widgets/app_bar.dart b/lib/design_system/widgets/app_bar.dart index 62b1f716..53c6acbf 100644 --- a/lib/design_system/widgets/app_bar.dart +++ b/lib/design_system/widgets/app_bar.dart @@ -30,7 +30,6 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { titleSpacing: 8, leadingWidth: leadingWidth, automaticallyImplyLeading: false, - backgroundColor: colors.surfaceLow, title: title != null ? Text(title!, style: typo.title.small.copyWith(color: contentColor)) diff --git a/lib/presentation/createAccount/screen/create_account_screen.dart b/lib/presentation/createAccount/screen/create_account_screen.dart index 31151328..7119d7d5 100644 --- a/lib/presentation/createAccount/screen/create_account_screen.dart +++ b/lib/presentation/createAccount/screen/create_account_screen.dart @@ -48,6 +48,7 @@ class _CreateAccountScreenState extends State { final cubit = context.read(); return Scaffold( appBar: CustomAppBar( + backgroundColor: colors.surfaceLow, title: localizations.createAccount, trailing: AppLogo(assetPath: AppAssets.appBrand), leading: AppBarCircleButton( From d2517737e3610bfac62a0c905f64e561a5393064 Mon Sep 17 00:00:00 2001 From: Aboud Date: Tue, 10 Feb 2026 06:33:42 -0800 Subject: [PATCH 27/29] feat: add log to the register error --- lib/data/repository/authentication_repository.dart | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/data/repository/authentication_repository.dart b/lib/data/repository/authentication_repository.dart index f58298ee..01222889 100644 --- a/lib/data/repository/authentication_repository.dart +++ b/lib/data/repository/authentication_repository.dart @@ -40,7 +40,10 @@ class AuthenticationRepositoryImpl implements AuthenticationRepository { } on AuthException catch (error) { return Result.error(SupabaseAuthError.fromAuthException(error)); } catch (error) { - return Result.error(ErrorModel(error.toString())); + if (kDebugMode) { + print('Caught error during register: $error'); + } + rethrow; } } @@ -95,7 +98,7 @@ class AuthenticationRepositoryImpl implements AuthenticationRepository { @override Future resetPasswordForEmail(String email) async { final client = await supabaseService.getClient(); - final response = await client.auth.resetPasswordForEmail( + client.auth.resetPasswordForEmail( email, redirectTo: AppConstants.resetPasswordRedirect, ); From d77b144f90503696919258bc341f5edca2fa6a3e Mon Sep 17 00:00:00 2001 From: Aboud Date: Tue, 10 Feb 2026 06:35:50 -0800 Subject: [PATCH 28/29] resolve conflict --- lib/di/injection.dart | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/di/injection.dart b/lib/di/injection.dart index 93fc5eee..d64a7d6a 100644 --- a/lib/di/injection.dart +++ b/lib/di/injection.dart @@ -69,9 +69,6 @@ void initDI() { () => TransactionCubit(transactionRepository: getIt()), ); - getIt.registerFactory( - () => AuthenticationValidator(), - ); getIt.registerFactory( () => CreateAccountCubit( getIt(), From 54fd22d434bc0532e0853377da6c2a36346560f3 Mon Sep 17 00:00:00 2001 From: Aboud Date: Tue, 10 Feb 2026 06:41:59 -0800 Subject: [PATCH 29/29] resolve conflict --- lib/data/repository/authentication_repository.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/data/repository/authentication_repository.dart b/lib/data/repository/authentication_repository.dart index 01222889..f705ec75 100644 --- a/lib/data/repository/authentication_repository.dart +++ b/lib/data/repository/authentication_repository.dart @@ -98,7 +98,7 @@ class AuthenticationRepositoryImpl implements AuthenticationRepository { @override Future resetPasswordForEmail(String email) async { final client = await supabaseService.getClient(); - client.auth.resetPasswordForEmail( + await client.auth.resetPasswordForEmail( email, redirectTo: AppConstants.resetPasswordRedirect, );