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
7 changes: 6 additions & 1 deletion lib/core/l10n/app_ar.arb
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,10 @@
"expenses": "المصروفات",
"transaction": "المعاملات",
"transaction_error_title": "خطأ في المعاملات",
"transaction_error_content": "فشل في تحميل المعاملات"
"transaction_error_content": "فشل في تحميل المعاملات",
"manage_categories" : "ادارةالتصنيفات",
"add_new_category": "اضافة تصنيف جديد",
"add_custom_category" : "اضافة تصنيف مخصص",
"category_name" : "اسم التصنيف",
"add" : "اضافة"
}
7 changes: 6 additions & 1 deletion lib/core/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -134,5 +134,10 @@
"month_september": "September",
"month_october": "October",
"month_november": "November",
"month_december": "December"
"month_december": "December",
"manage_categories" : "Manage categories",
"add_new_category": "Add new category",
"add_custom_category" : "Add custom category",
"category_name" : "Category name",
"add" : "Add"
}
4 changes: 3 additions & 1 deletion lib/design_system/widgets/buttons/button/default_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@ class _DefaultButtonState extends State<DefaultButton> {
offset: const Offset(0, 4),
blurRadius: 12,
spreadRadius: 0,
blurStyle: BlurStyle.inner,
),
outerShadow: BoxShadow(
color: const Color(0x29DC143C),
offset: const Offset(0, 4),
blurRadius: 8,
spreadRadius: 0,
blurStyle: BlurStyle.outer,
),
);
}
}
}
93 changes: 93 additions & 0 deletions lib/presentation/categories/screen/manage_categories_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:go_router/go_router.dart';
import 'package:moneyplus/design_system/assets/app_assets.dart';

import '../../../core/l10n/app_localizations.dart';
import '../../../design_system/theme/money_extension_context.dart';
import '../../../design_system/widgets/buttons/button/default_button.dart';
import '../widget/add_category_bottom_sheet.dart';
import '../widget/category_chip.dart';

class ManageCategoriesScreen extends StatelessWidget {
ManageCategoriesScreen({super.key});

// TODO : Replace with actual categories from backend
final List<String> categories = [
'Food',
'Transport',
'Rent',
'Entertainment',
'Electricity',
'Shopping',
'Health',
'Fitness / Gym',
'Internet',
'Cats',
'University',
];

@override
Widget build(BuildContext context) {
final colors = context.colors;
final typography = context.typography;
final localizations = AppLocalizations.of(context)!;
return Scaffold(
backgroundColor: colors.surface,
appBar: AppBar(
leading: Padding(
padding: const EdgeInsetsGeometry.only(left: 16),
child: IconButton(
padding: EdgeInsets.zero,
onPressed: () => context.pop(),
icon: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: colors.surface,
shape: BoxShape.circle,
),
child: Center(child: SvgPicture.asset(AppAssets.icArrowLeft)),
),
),
),
title: Text(localizations.manage_categories, style: typography.title.small),
),
body: Padding(
padding: const EdgeInsetsGeometry.only(top: 16, left: 16, right: 16),
child: Wrap(
spacing: 8,
runSpacing: 8,
children: categories
.map(
(category) => CategoryChip(
label: category,
onEdit: () => print('$category'),
),
)
.toList(),
),
),
bottomNavigationBar: Container(
width: double.infinity,
height: 84,
color: colors.surfaceLow,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
child: DefaultButton(
text: localizations.add_new_category,
onPressed: () => _openBottomSheet(context),
),
),
),
);
}

void _openBottomSheet(BuildContext context) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => const AddCategorySheet(),
);
}
}
92 changes: 92 additions & 0 deletions lib/presentation/categories/widget/add_category_bottom_sheet.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import 'package:flutter/material.dart';
import 'package:moneyplus/design_system/assets/app_assets.dart';
import 'package:moneyplus/design_system/widgets/text_field.dart';
import 'package:svg_flutter/svg.dart';

import '../../../core/l10n/app_localizations.dart';
import '../../../design_system/theme/money_extension_context.dart';
import '../../../design_system/widgets/buttons/button/default_button.dart';

class AddCategorySheet extends StatefulWidget {
const AddCategorySheet({super.key});

@override
State<AddCategorySheet> createState() => _AddCategorySheetState();
}

class _AddCategorySheetState extends State<AddCategorySheet> {
final TextEditingController _controller = TextEditingController();
bool _isButtonEnabled = false;

@override
void initState() {
super.initState();
_controller.addListener(() {
setState(() {
_isButtonEnabled = _controller.text.trim().isNotEmpty;
});
});
}

@override
Widget build(BuildContext context) {
final colors = context.colors;
final typography = context.typography;
final localizations = AppLocalizations.of(context)!;
return Container(
padding: EdgeInsets.only(
left: 16,
right: 16,
top: 24,
bottom: MediaQuery.of(context).viewInsets.bottom + 24,
),
decoration: BoxDecoration(
color: colors.surface,
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(localizations.add_custom_category, style: typography.title.small),
IconButton(
onPressed: () => Navigator.pop(context),
icon: SvgPicture.asset(AppAssets.iconCancel),
),
],
),
Divider(color: colors.stroke, thickness: 1),
const SizedBox(height: 12),

MTextField(
leading: Padding(
padding: const EdgeInsetsGeometry.only(left: 16, right: 8),
child: SvgPicture.asset(AppAssets.icCategory),
),
hint: localizations.category_name,
value: '',
onChanged: (String value) {
setState(() {
_isButtonEnabled = value.trim().isNotEmpty;
});
},
),

const SizedBox(height: 24),

DefaultButton(
text:localizations.add,
isEnabled: _isButtonEnabled,
onPressed: _isButtonEnabled
? () {
Navigator.pop(context);
}
: null,
),
],
),
);
}
}
34 changes: 34 additions & 0 deletions lib/presentation/categories/widget/category_chip.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';

import '../../../design_system/assets/app_assets.dart';
import '../../../design_system/theme/money_extension_context.dart';

class CategoryChip extends StatelessWidget {
final String label;
final VoidCallback onEdit;

const CategoryChip({super.key, required this.label, required this.onEdit});


@override
Widget build(BuildContext context) {
final colors = context.colors;
final typography = context.typography;
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: colors.surfaceLow,
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(label, style: typography.label.medium),
const SizedBox(width: 8),
SvgPicture.asset(AppAssets.icEdit),
],
),
);
}
}