Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions assets/icons/icon_cancel_category.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 0 additions & 4 deletions lib/core/l10n/app_ar.arb
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,8 @@
"no_monthly_overview": "لم يتم تسجيل أي دخل أو مصروفات لهذه الفترة",
"error_loading_statistics": "فشل تحميل الإحصائيات",
"retry": "إعادة المحاولة",
"noDataAvailable": "لا توجد بيانات متاحة",
"current_balance":"الرصيد الحالي",
"how_much_money": "ما مقدار المال المتوفر لديك حاليًا؟",
"noDataAvailable": "لا توجد بيانات متاحة",
"no_spending_categories": "لا يوجد معاملات متاحة",
"month_january": "يناير",
"month_february": "فبراير",
Expand All @@ -124,7 +122,6 @@
"month_december": "ديسمبر",
"no_transaction_record_title": "لا توجد سجلات معاملات",
"no_transaction_record_content": "أضف أول معاملة للبدء",
"add_transaction": "إضافة معاملة",
"all": "الكل",
"incomes": "الإيرادات",
"expenses": "المصروفات",
Expand All @@ -139,7 +136,6 @@
"transaction_delete_fail" : "نم مسح المعاملة بنجاح",
"add" : "اضافة",
"transaction_details": "تفاصيل المعاملة",
"transaction_details": "Transaction details",
"income_details": "تفاصيل الدخل",
"expense_details": "تفاصيل المصروف"
}
14 changes: 7 additions & 7 deletions lib/core/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@
"spendingTrend": "Spending Trend",
"noDataAvailable": "No data available",
"date": "Date",
"amount": "Amount",
"addIncome": "Add income",
"note": "Note",
"add": "Add",
"saving": "Saving...",
"incomeAddedSuccessfully": "Income added successfully!",
Expand Down Expand Up @@ -67,9 +65,9 @@
"updatePasswordSuccessMessage": "Password updated successfully",
"updatePasswordErrorMessage": "Error updating password",
"error": "Error",
"success" : "Success",
"loading" : "Loading",
"login_successfully" : "Login Successfully",
"success": "Success",
"loading": "Loading",
"login_successfully": "Login Successfully",
"login_welcome_title": "Welcome again!",
"login_welcome_subtitle": "Enter your credentials to access your account",
"login_email_hint": "Email",
Expand Down Expand Up @@ -151,8 +149,10 @@
"no_monthly_overview": "No income or expenses recorded for this period",
"error_loading_statistics": "Failed to load statistics",
"retry": "Retry",
"add" : "Add",
"transaction_details": "Transaction details",
"income_details": "Income details",
"expense_details": "Expense details"
"expense_details": "Expense details",
"whereDoYouUsuallySpendYourMoney": "Where do you usually spend your money?",
"suggestions": "Suggestions:",
"selectedCategories": "Selected Categories:"
}
1 change: 1 addition & 0 deletions lib/design_system/assets/app_assets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class AppAssets {
static const icArrowUp = '$_icons/ic_arrow_up.svg';
static const icArrowRight = '$_icons/ic_arrow_right.svg';
static const String iconCancel = "$_icons/ic_cancel.svg";
static const String iconCancelCategory = "$_icons/icon_cancel_category.svg";
static const String iconError = "$_icons/ic_error.svg";
static const String iconSuccess = "$_icons/ic_success.svg";
static const String icCategory = "$_icons/ic_menu-square.svg";
Expand Down
57 changes: 57 additions & 0 deletions lib/design_system/widgets/selected_category_item.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:moneyplus/design_system/assets/app_assets.dart';
import 'package:moneyplus/design_system/theme/money_extension_context.dart';

class SelectedCategoryItem extends StatelessWidget {
final String label;
final VoidCallback onDelete;

const SelectedCategoryItem({
super.key,
required this.label,
required this.onDelete,
});

@override
Widget build(BuildContext context) {
final colors = context.colors;
final typo = context.typography;

return Row(
children: [
Expanded(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: BoxDecoration(
color: colors.surfaceLow,
borderRadius: BorderRadius.circular(16),
),
child: Text(
label,
style: typo.body.medium.copyWith(color: colors.title),
),
),
),
const SizedBox(width: 4),
GestureDetector(
onTap: onDelete,
behavior: HitTestBehavior.opaque,
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: colors.redVariant,
borderRadius: BorderRadius.circular(16),
),
child: SvgPicture.asset(
AppAssets.iconCancelCategory,
width: 52,
height: 28,
colorFilter: ColorFilter.mode(colors.red, BlendMode.srcIn),
),
),
),
],
);
}
}
9 changes: 9 additions & 0 deletions lib/presentation/account_setup/cubit/account_setup_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,13 @@ class AccountSetupCubit extends Cubit<AccountSetupState> {
break;
}
}
void toggleCategory(String category) {
final List<String> updatedCategories = List.from(state.categories);
if (updatedCategories.contains(category)) {
updatedCategories.remove(category);
} else {
updatedCategories.add(category);
}
emit(state.copyWith(categories: updatedCategories));
}
}
17 changes: 17 additions & 0 deletions lib/presentation/account_setup/cubit/account_setup_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class AccountSetupState {
final String query;
final bool isButtonEnabled;
final List<Currency> currencies;
final List<String> categories;
final List<String> suggestions;
final bool isLoading;
final String errorMessage;
final AccountSetupStep accountStep;
Expand All @@ -27,6 +29,19 @@ class AccountSetupState {
this.query = "",
this.isButtonEnabled = false,
this.currencies = const [],
this.categories = const [],
this.suggestions = const [
'Food',
'Transport',
'Shopping',
'Health',
'Education',
'Gift',
'Cafe',
'Work',
'Home',
'Travel'
],
this.isLoading = true,
this.errorMessage = "",
this.accountStep = AccountSetupStep.step1,
Expand All @@ -41,6 +56,8 @@ class AccountSetupState {
String? query,
bool? isButtonEnabled,
List<Currency>? currencies,
List<String>? categories,
List<String>? suggestions,
String? errorMessage,
bool? isLoading,
AccountSetupStep? accountStep,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:moneyplus/design_system/assets/app_assets.dart';
import 'package:moneyplus/design_system/widgets/app_bar.dart';
import 'package:moneyplus/presentation/account_setup/screen/page1.dart';
import 'package:moneyplus/presentation/account_setup/screen/page2.dart';
import 'package:moneyplus/presentation/account_setup/screen/account_setup_step_three.dart';

import '../../../core/di/injection.dart';
import '../../../core/l10n/app_localizations.dart';
Expand Down Expand Up @@ -108,7 +109,8 @@ class _AccountSetupScreenState extends State<AccountSetupScreen> {
children: [
SingleChildScrollView(child: Page1(state: state,)),
SingleChildScrollView(child: Page2(currency: state.currency, currentBalanceState: state.currentBalance)),
// page3()
SingleChildScrollView(child: AccountSetupStepThree(state: state)),

],
),
),
Expand Down
122 changes: 122 additions & 0 deletions lib/presentation/account_setup/screen/account_setup_step_three.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:moneyplus/design_system/widgets/chip.dart';
import 'package:moneyplus/design_system/widgets/text_field.dart';
import 'package:moneyplus/presentation/account_setup/cubit/account_setup_cubit.dart';
import 'package:moneyplus/presentation/account_setup/cubit/account_setup_state.dart';

import '../../../core/l10n/app_localizations.dart';
import '../../../design_system/theme/money_extension_context.dart';
import '../../../design_system/widgets/selected_category_item.dart';

class AccountSetupStepThree extends StatefulWidget {
final AccountSetupState state;
const AccountSetupStepThree({super.key, required this.state});

@override
State<AccountSetupStepThree> createState() => _AccountSetupStepThreeState();
}

class _AccountSetupStepThreeState extends State<AccountSetupStepThree> {
final TextEditingController categoryController = TextEditingController();
String _searchQuery = '';

@override
void initState() {
super.initState();
categoryController.addListener(() {
setState(() {
_searchQuery = categoryController.text.toLowerCase();
});
});
}

@override
void dispose() {
categoryController.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
final cubit = context.read<AccountSetupCubit>();

final filteredSuggestions = widget.state.suggestions
.where((suggestion) =>
suggestion.toLowerCase().contains(_searchQuery) &&
!widget.state.categories.contains(suggestion))
.toList();

return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
l10n.whereDoYouUsuallySpendYourMoney,
style: context.typography.label.small.copyWith(
color: context.colors.body,
),
),
const SizedBox(height: 24),
MTextField(
hint: l10n.category_name,
keyboardType: TextInputType.text,
value: categoryController.text,
onChanged: (value) {
categoryController.text = value;
},
),
const SizedBox(height: 16),
if (filteredSuggestions.isNotEmpty) ...[
Text(
l10n.suggestions,
style: context.typography.label.medium.copyWith(
color: context.colors.title,
),
),
const SizedBox(height: 12),
Wrap(
spacing: 8,
runSpacing: 8,
children: filteredSuggestions.map((suggestion) {
return MChip(
label: suggestion,
selected: false,
onTap: () {
cubit.toggleCategory(suggestion);
categoryController.clear();
},
);
}).toList(),
),
],
if (widget.state.categories.isNotEmpty) ...[
const SizedBox(height: 24),
Text(
l10n.selectedCategories,
style: context.typography.label.medium.copyWith(
color: context.colors.title,
),
),
const SizedBox(height: 12),
ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: widget.state.categories.length,
separatorBuilder: (context, index) => const SizedBox(height: 8),
itemBuilder: (context, index) {
final category = widget.state.categories[index];
return SelectedCategoryItem(
label: category,
onDelete: () => cubit.toggleCategory(category),
);
},
),
],
const SizedBox(height: 24),
],
),
);
}
}