diff --git a/assets/icons/ic_coins.svg b/assets/icons/ic_coins.svg
new file mode 100644
index 0000000..fba439d
--- /dev/null
+++ b/assets/icons/ic_coins.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/ic_currency.svg b/assets/icons/ic_currency.svg
new file mode 100644
index 0000000..b1409c5
--- /dev/null
+++ b/assets/icons/ic_currency.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/ic_customer_support.svg b/assets/icons/ic_customer_support.svg
new file mode 100644
index 0000000..8148786
--- /dev/null
+++ b/assets/icons/ic_customer_support.svg
@@ -0,0 +1,7 @@
+
diff --git a/assets/icons/ic_help.svg b/assets/icons/ic_help.svg
new file mode 100644
index 0000000..0afc8a0
--- /dev/null
+++ b/assets/icons/ic_help.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/ic_settings.svg b/assets/icons/ic_settings.svg
new file mode 100644
index 0000000..f61d23a
--- /dev/null
+++ b/assets/icons/ic_settings.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/icons/ic_sun.svg b/assets/icons/ic_sun.svg
new file mode 100644
index 0000000..43f429c
--- /dev/null
+++ b/assets/icons/ic_sun.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/ic_translation.svg b/assets/icons/ic_translation.svg
new file mode 100644
index 0000000..d3b2e91
--- /dev/null
+++ b/assets/icons/ic_translation.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/images/money_background.png b/assets/images/money_background.png
new file mode 100644
index 0000000..4d7594b
Binary files /dev/null and b/assets/images/money_background.png differ
diff --git a/lib/core/di/cubit_di.dart b/lib/core/di/cubit_di.dart
index 7265b75..dd5ad81 100644
--- a/lib/core/di/cubit_di.dart
+++ b/lib/core/di/cubit_di.dart
@@ -13,6 +13,7 @@ import 'package:moneyplus/presentation/statistics/cubit/statistics_cubit.dart';
import 'package:moneyplus/presentation/transactions/cubit/transaction_cubit.dart';
import 'package:moneyplus/presentation/trasnaction_details/trasnaction_details_cubit.dart';
+import '../../presentation/accout/cubit/account_cubit.dart';
import '../../presentation/expense/cubit/add_expense_cubit.dart';
import 'injection.dart';
@@ -70,4 +71,7 @@ void initCubitDI() {
getIt(),
),
);
+ getIt.registerFactory(
+ () => AccountCubit(getIt()),
+ );
}
diff --git a/lib/core/l10n/app_ar.arb b/lib/core/l10n/app_ar.arb
index c605350..cec8832 100644
--- a/lib/core/l10n/app_ar.arb
+++ b/lib/core/l10n/app_ar.arb
@@ -138,6 +138,15 @@
"transaction_details": "تفاصيل المعاملة",
"income_details": "تفاصيل الدخل",
"expense_details": "تفاصيل المصروف",
+ "account": "حساب",
+ "manageCategories": "إدارة الفئات",
+ "appLanguage": "لغة التطبيق",
+ "appTheme": "ثيم التطبيق",
+ "salarySettings": "إعدادات الراتب",
+ "frequentlyAskedQuestion": "الأسئلة المتكررة",
+ "helpAndSupport": "المساعدة والدعم",
+ "appVersion": "اصدار التطبيق",
+ "expense_details": "تفاصيل المصروف",
"add_transaction_sheet_subtitle": "اختر نوع المعاملة التي تريد إضافتها",
"make_expense": "تسجيل مصروف",
"continueButton": "متابعة",
diff --git a/lib/core/l10n/app_en.arb b/lib/core/l10n/app_en.arb
index 81c8cc1..9c83c33 100644
--- a/lib/core/l10n/app_en.arb
+++ b/lib/core/l10n/app_en.arb
@@ -149,6 +149,14 @@
"no_monthly_overview": "No income or expenses recorded for this period",
"error_loading_statistics": "Failed to load statistics",
"retry": "Retry",
+ "account": "Account",
+ "manageCategories": "Manage categories",
+ "appLanguage": "App language",
+ "appTheme": "App theme",
+ "salarySettings": "Salary settings",
+ "frequentlyAskedQuestion": "Frequently asked question",
+ "helpAndSupport": "Help & Support",
+ "appVersion": "App version",
"transaction_details": "Transaction details",
"income_details": "Income details",
"expense_details": "Expense details",
diff --git a/lib/data/repository/account_repository.dart b/lib/data/repository/account_repository.dart
index b936dcf..eed3085 100644
--- a/lib/data/repository/account_repository.dart
+++ b/lib/data/repository/account_repository.dart
@@ -1,4 +1,6 @@
import 'package:moneyplus/domain/entity/currency.dart';
+import 'package:moneyplus/domain/entity/user.dart';
+import 'package:supabase_flutter/supabase_flutter.dart' hide User;
import '../../domain/repository/account_repository.dart';
import '../../core/service/supabase_service.dart';
@@ -9,15 +11,19 @@ class AccountRepositoryImpl extends AccountRepository {
AccountRepositoryImpl({required this.supabaseService});
@override
- Future> getCurrencies() async{
- try{
+ Future> getCurrencies() async {
+ try {
final client = await supabaseService.getClient();
final response = await client.from('currencies').select();
return response.map((e) => Currency.fromJson(e)).toList();
- }catch(e){
+ } catch (e) {
throw Exception('Failed to fetch currencies');
}
+ }
+ @override
+ Future getCurrentUser() async {
+ throw Exception('Failed to get current user');
}
}
\ No newline at end of file
diff --git a/lib/design_system/assets/app_assets.dart b/lib/design_system/assets/app_assets.dart
index 2617f89..c21718c 100644
--- a/lib/design_system/assets/app_assets.dart
+++ b/lib/design_system/assets/app_assets.dart
@@ -70,6 +70,14 @@ class AppAssets {
static const String icEmptyTransactionPattern = '$_icons/empty_transaction_pattern.svg';
static const String icFilter = "$_icons/ic_filter.svg";
static const String imgNoAnalysis = "$_images/img_no_analysis.png";
- static const String icAddAmount = "$_icons/ic_add_transaction_income.svg";
- static const String icAddExpense = "$_icons/ic_add_transaction_expense.svg";
+ static const String icAddAmount = '$_icons/ic_add_transaction_income.svg';
+ static const String icAddExpense = '$_icons/ic_add_transaction_expense.svg';
+ static const String icCoins = '$_icons/ic_coins.svg';
+ static const String icCustomerSupport = '$_icons/ic_customer_support.svg';
+ static const String icHelp = '$_icons/ic_help.svg';
+ static const String icSettings = '$_icons/ic_settings.svg';
+ static const String icSun = '$_icons/ic_sun.svg';
+ static const String icTranslation = '$_icons/ic_translation.svg';
+ static const String icCurrency = '$_icons/ic_currency.svg';
+ static const String glowBackground = '$_images/money_background.png';
}
diff --git a/lib/domain/repository/account_repository.dart b/lib/domain/repository/account_repository.dart
index f11c038..55f8515 100644
--- a/lib/domain/repository/account_repository.dart
+++ b/lib/domain/repository/account_repository.dart
@@ -1,6 +1,9 @@
-
import 'package:moneyplus/domain/entity/currency.dart';
+import 'package:moneyplus/domain/entity/user.dart';
abstract class AccountRepository {
Future> getCurrencies();
+
+ Future getCurrentUser();
+
}
\ No newline at end of file
diff --git a/lib/presentation/accout/cubit/account_cubit.dart b/lib/presentation/accout/cubit/account_cubit.dart
new file mode 100644
index 0000000..0ebcfdf
--- /dev/null
+++ b/lib/presentation/accout/cubit/account_cubit.dart
@@ -0,0 +1,21 @@
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import '../../../domain/repository/account_repository.dart';
+import 'account_state.dart';
+
+class AccountCubit extends Cubit {
+ final AccountRepository _accountRepository;
+
+ AccountCubit(this._accountRepository)
+ : super(const AccountLoading(isLoading: true));
+
+ void loadUserInfo() {
+ emit(const AccountLoading(isLoading: true));
+
+ _accountRepository.getCurrentUser().then((user) {
+ emit(AccountLoaded(user: user));
+ }).catchError((error) {
+ emit(AccountError(errorMessage: error.toString()));
+ });
+ }
+}
diff --git a/lib/presentation/accout/cubit/account_state.dart b/lib/presentation/accout/cubit/account_state.dart
new file mode 100644
index 0000000..1ef474b
--- /dev/null
+++ b/lib/presentation/accout/cubit/account_state.dart
@@ -0,0 +1,30 @@
+import 'package:flutter/cupertino.dart';
+
+import '../../../domain/entity/user.dart';
+
+@immutable
+sealed class AccountState {
+ const AccountState();
+}
+
+class AccountLoading extends AccountState {
+ final bool isLoading;
+
+ const AccountLoading({required this.isLoading});
+}
+
+class AccountLoaded extends AccountState {
+ final User user;
+
+ const AccountLoaded({required this.user});
+
+ AccountLoaded copyWith({User? user}) {
+ return AccountLoaded(user: user ?? this.user);
+ }
+}
+
+class AccountError extends AccountState {
+ final String errorMessage;
+
+ const AccountError({required this.errorMessage});
+}
diff --git a/lib/presentation/accout/screen/account_screen.dart b/lib/presentation/accout/screen/account_screen.dart
new file mode 100644
index 0000000..b577c99
--- /dev/null
+++ b/lib/presentation/accout/screen/account_screen.dart
@@ -0,0 +1,126 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import '../../../core/di/injection.dart';
+import '../../../core/l10n/app_localizations.dart';
+import '../../../design_system/assets/app_assets.dart';
+import '../../../design_system/theme/money_extension_context.dart';
+import '../../../design_system/widgets/app_bar.dart';
+import '../cubit/account_cubit.dart';
+import '../cubit/account_state.dart';
+import '../widget/account_section.dart';
+import '../widget/personal_info_card.dart';
+
+class AccountScreen extends StatelessWidget {
+ const AccountScreen({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ final l10n = AppLocalizations.of(context)!;
+ final colors = context.colors;
+ final typography = context.typography;
+
+ return Scaffold(
+ backgroundColor: colors.surface,
+ appBar: CustomAppBar(title: l10n.account,backgroundColor: colors.surfaceLow),
+ body: BlocProvider(
+ create: (_) => getIt()..loadUserInfo(),
+ child: BlocConsumer(
+ listener: (context, state) {},
+ builder: (context, state) {
+ return _buildBody(context, state, l10n, colors, typography);
+ },
+ ),
+ ),
+ );
+ }
+
+ Widget _buildBody(
+ BuildContext context,
+ AccountState state,
+ AppLocalizations l10n,
+ dynamic colors,
+ dynamic typography,
+ ) {
+ if (state is AccountLoading) {
+ return const Center(child: CircularProgressIndicator());
+ }
+
+ final user = state is AccountLoaded ? state.user : null;
+
+ return Stack(
+ children: [
+ Positioned(
+ child: Align(
+ alignment: Alignment.bottomRight,
+ child: SizedBox(
+ width: MediaQuery.of(context).size.width * 0.75,
+ height: 150,
+
+ child: Image.asset(
+ AppAssets.glowBackground,
+ fit: BoxFit.contain,
+ ),
+ ),
+ ),
+ ),
+
+ SingleChildScrollView(
+ child: Container(
+ padding: const EdgeInsets.only(top: 24, left: 16, right: 16),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ personalInfoCard(
+ image: '',
+ name: user?.name ?? '',
+ email: user?.email ?? '',
+ ),
+ const SizedBox(height: 24),
+ accountSection(
+ title: l10n.manageCategories,
+ iconPath: AppAssets.icSettings,
+ ),
+ accountSection(
+ title: l10n.appLanguage,
+ iconPath: AppAssets.icTranslation,
+ ),
+ accountSection(title: l10n.appTheme, iconPath: AppAssets.icSun),
+ accountSection(
+ title: l10n.currency,
+ iconPath: AppAssets.icCurrency,
+ ),
+ accountSection(
+ title: l10n.salarySettings,
+ iconPath: AppAssets.iconMoney,
+ ),
+ accountSection(
+ title: l10n.frequentlyAskedQuestion,
+ iconPath: AppAssets.icHelp,
+ ),
+ accountSection(
+ title: l10n.helpAndSupport,
+ iconPath: AppAssets.icCustomerSupport,
+ showDivider: false,
+ ),
+ const SizedBox(height: 24),
+ Align(
+ alignment: Alignment.center,
+ child: Padding(
+ padding: const EdgeInsets.only(bottom: 8),
+ child: Text(
+ "${l10n.appVersion} 1.0",
+ style: typography.label.small.copyWith(
+ color: colors.body,
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/accout/widget/account_section.dart b/lib/presentation/accout/widget/account_section.dart
new file mode 100644
index 0000000..ee80fb3
--- /dev/null
+++ b/lib/presentation/accout/widget/account_section.dart
@@ -0,0 +1,49 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+
+import '../../../design_system/theme/money_colors.dart';
+import '../../../design_system/theme/money_typography.dart';
+
+Widget accountSection({
+ required String title,
+ required String iconPath,
+ bool showDivider = true,
+ VoidCallback? onTap,
+}) {
+ return InkWell(
+ onTap: () {
+ if (onTap != null) {
+ onTap();
+ }
+ },
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Container(
+ decoration: BoxDecoration(
+ shape: BoxShape.rectangle,
+ color: MoneyColors.light.surfaceHigh,
+ borderRadius: BorderRadius.circular(12),
+ ),
+ padding: EdgeInsets.symmetric(vertical: 12, horizontal: 11),
+ alignment: Alignment.center,
+ child: SvgPicture.asset(iconPath, width: 24, height: 24),
+ ),
+ SizedBox(width: 8),
+ Text(
+ title,
+ style: MoneyTypography.typography.label.large.copyWith(
+ color: MoneyColors.light.title,
+ ),
+ ),
+ ],
+ ),
+ if (showDivider)
+ Divider(color: MoneyColors.light.stroke, thickness: 0.5),
+ ],
+ ),
+ );
+}
diff --git a/lib/presentation/accout/widget/personal_info_card.dart b/lib/presentation/accout/widget/personal_info_card.dart
new file mode 100644
index 0000000..95d24a3
--- /dev/null
+++ b/lib/presentation/accout/widget/personal_info_card.dart
@@ -0,0 +1,89 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter_svg/svg.dart';
+
+import '../../../design_system/assets/app_assets.dart';
+import '../../../design_system/theme/money_colors.dart';
+import '../../../design_system/theme/money_typography.dart';
+
+Widget personalInfoCard({
+ required String? image,
+ required String name,
+ required String email,
+}) {
+ return Container(
+ decoration: BoxDecoration(
+ color: MoneyColors.light.surfaceLow,
+ borderRadius: BorderRadius.circular(16),
+ ),
+ padding: EdgeInsets.all(8),
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ updateUserAvatar(image, name),
+ SizedBox(width: 12),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ name,
+ style: MoneyTypography.typography.title.small.copyWith(
+ color: MoneyColors.light.title,
+ ),
+ ),
+ Text(
+ email,
+ style: MoneyTypography.typography.label.small.copyWith(
+ color: MoneyColors.light.body,
+ ),
+ ),
+ ],
+ ),
+ Spacer(),
+ GestureDetector(
+ onTap: () {
+ // Handle click
+ },
+ child: Container(
+ decoration: BoxDecoration(
+ shape: BoxShape.circle,
+ border: Border.all(color: MoneyColors.light.stroke),
+ ),
+ padding: EdgeInsets.all(8),
+ child: SvgPicture.asset(AppAssets.icEdit, width: 16, height: 16),
+ ),
+ ),
+ ],
+ ),
+ );
+}
+
+Widget updateUserAvatar(String? imageUrl, String fullName) {
+ if (imageUrl != null && imageUrl.isNotEmpty) {
+ return Image.asset(imageUrl, height: 52, width: 52);
+ } else {
+ String initials = '';
+ if (fullName.isNotEmpty) {
+ final nameParts = fullName.trim().split(' ');
+ if (nameParts.length >= 2) {
+ initials = (nameParts[0][0] + nameParts[1][0]).toUpperCase();
+ } else {
+ initials = fullName[0].toUpperCase();
+ }
+ }
+ return Container(
+ decoration: BoxDecoration(
+ shape: BoxShape.rectangle,
+ color: MoneyColors.light.surface,
+ borderRadius: BorderRadius.circular(12),
+ ),
+ padding: EdgeInsets.symmetric(vertical: 12, horizontal: 11),
+ alignment: Alignment.center,
+ child: Text(
+ initials,
+ style: MoneyTypography.typography.title.large.copyWith(
+ color: MoneyColors.light.title,
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/main_container/screen/main_screen.dart b/lib/presentation/main_container/screen/main_screen.dart
index 1adea93..a8bf6cb 100644
--- a/lib/presentation/main_container/screen/main_screen.dart
+++ b/lib/presentation/main_container/screen/main_screen.dart
@@ -1,7 +1,7 @@
-import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:moneyplus/design_system/theme/money_extension_context.dart';
+import 'package:moneyplus/presentation/accout/screen/account_screen.dart';
import 'package:moneyplus/presentation/main_container/cubit/main_state.dart';
import 'package:moneyplus/presentation/statistics/statistics_screen.dart';
import 'package:moneyplus/presentation/transactions/screen/transactions_screen.dart';
@@ -44,7 +44,7 @@ class MainScreen extends StatelessWidget {
case NavBarTab.statistics:
return const StatisticsScreen();
case NavBarTab.account:
- return const TransactionsScreen(); //change to account
+ return const AccountScreen();
}
}
}