feat: category

This commit is contained in:
efrilm
2025-08-17 12:50:10 +07:00
parent f84090c0e6
commit 4a4f6388d7
19 changed files with 2041 additions and 20 deletions
@@ -1,27 +1,37 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:line_icons/line_icons.dart';
import '../../../application/category/category_loader/category_loader_bloc.dart';
import '../../../common/theme/theme.dart';
import '../../../domain/category/category.dart';
import '../../../injection.dart';
import '../../components/appbar/appbar.dart';
import '../../components/button/button.dart';
import 'widgets/category_delegate.dart';
import 'widgets/product_tile.dart';
@RoutePage()
class ProductPage extends StatefulWidget {
class ProductPage extends StatefulWidget implements AutoRouteWrapper {
const ProductPage({super.key});
@override
State<ProductPage> createState() => _ProductPageState();
@override
Widget wrappedRoute(BuildContext context) => BlocProvider(
create: (context) =>
getIt<CategoryLoaderBloc>()..add(CategoryLoaderEvent.fetched()),
child: this,
);
}
enum ViewType { grid, list }
class _ProductPageState extends State<ProductPage>
with TickerProviderStateMixin {
String selectedCategory = 'Semua';
List<String> categories = ['Semua', 'Makanan', 'Minuman', 'Snack', 'Dessert'];
Category selectedCategory = Category.addAllData();
ViewType currentViewType = ViewType.grid;
// Sample product data
@@ -121,7 +131,8 @@ class _ProductPageState extends State<ProductPage>
List<Product> get filteredProducts {
return products.where((product) {
bool matchesCategory =
selectedCategory == 'Semua' || product.category == selectedCategory;
selectedCategory.name == 'Semua' ||
product.category == selectedCategory.id;
return matchesCategory;
}).toList();
}
@@ -173,17 +184,21 @@ class _ProductPageState extends State<ProductPage>
}
Widget _buildCategoryFilter() {
return SliverPersistentHeader(
pinned: true,
delegate: ProductCategoryHeaderDelegate(
categories: categories,
selectedCategory: selectedCategory,
onCategoryChanged: (category) {
setState(() {
selectedCategory = category;
});
},
),
return BlocBuilder<CategoryLoaderBloc, CategoryLoaderState>(
builder: (context, state) {
return SliverPersistentHeader(
pinned: true,
delegate: ProductCategoryHeaderDelegate(
categories: state.categories,
selectedCategory: selectedCategory,
onCategoryChanged: (category) {
setState(() {
selectedCategory = category;
});
},
),
);
},
);
}
@@ -1,11 +1,12 @@
import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/category/category.dart';
class ProductCategoryHeaderDelegate extends SliverPersistentHeaderDelegate {
final List<String> categories;
final String selectedCategory;
final ValueChanged<String> onCategoryChanged;
final List<Category> categories;
final Category selectedCategory;
final ValueChanged<Category> onCategoryChanged;
ProductCategoryHeaderDelegate({
required this.categories,
@@ -35,7 +36,7 @@ class ProductCategoryHeaderDelegate extends SliverPersistentHeaderDelegate {
return Container(
margin: const EdgeInsets.only(right: 12.0),
child: FilterChip(
label: Text(category),
label: Text(category.name),
selected: isSelected,
onSelected: (selected) => onCategoryChanged(category),
backgroundColor: AppColor.surface,
@@ -64,6 +65,7 @@ class ProductCategoryHeaderDelegate extends SliverPersistentHeaderDelegate {
@override
bool shouldRebuild(ProductCategoryHeaderDelegate oldDelegate) {
return oldDelegate.selectedCategory != selectedCategory;
return oldDelegate.categories != categories ||
oldDelegate.selectedCategory != selectedCategory;
}
}