feat: merchat detail page
This commit is contained in:
parent
c36a4059e1
commit
f70b43c6ab
@ -51,9 +51,7 @@ class HomePopularMerchantSection extends StatelessWidget {
|
||||
rating: 4.8,
|
||||
distance: '0.5 km',
|
||||
isOpen: true,
|
||||
onTap: () {
|
||||
print('Warung Bu Sari tapped');
|
||||
},
|
||||
onTap: () {},
|
||||
),
|
||||
|
||||
HomePopularMerchantCard(
|
||||
|
||||
@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../common/theme/theme.dart';
|
||||
import '../../components/field/field.dart';
|
||||
import '../../router/app_router.gr.dart';
|
||||
import 'widgets/empty_merchant_card.dart';
|
||||
import 'widgets/merchant_card.dart';
|
||||
|
||||
@ -90,12 +91,7 @@ class _MerchantPageState extends State<MerchantPage> {
|
||||
return MerchantCard(
|
||||
merchant: merchant,
|
||||
onTap: () {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Selected ${merchant.name}'),
|
||||
backgroundColor: AppColor.primary,
|
||||
),
|
||||
);
|
||||
context.router.push(MerchantDetailRoute(merchant: merchant));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,725 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../../../common/theme/theme.dart';
|
||||
import '../../merchant_page.dart';
|
||||
|
||||
// Models
|
||||
class ProductCategory {
|
||||
final String id;
|
||||
final String name;
|
||||
final String icon;
|
||||
final int productCount;
|
||||
|
||||
ProductCategory({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.icon,
|
||||
required this.productCount,
|
||||
});
|
||||
}
|
||||
|
||||
class Product {
|
||||
final String id;
|
||||
final String name;
|
||||
final String description;
|
||||
final int price;
|
||||
final String categoryId;
|
||||
final String imageUrl;
|
||||
final bool isAvailable;
|
||||
final double rating;
|
||||
final int soldCount;
|
||||
|
||||
Product({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.description,
|
||||
required this.price,
|
||||
required this.categoryId,
|
||||
required this.imageUrl,
|
||||
required this.isAvailable,
|
||||
required this.rating,
|
||||
required this.soldCount,
|
||||
});
|
||||
}
|
||||
|
||||
@RoutePage()
|
||||
class MerchantDetailPage extends StatefulWidget {
|
||||
final MerchantModel merchant;
|
||||
|
||||
const MerchantDetailPage({super.key, required this.merchant});
|
||||
|
||||
@override
|
||||
State<MerchantDetailPage> createState() => _MerchantDetailPageState();
|
||||
}
|
||||
|
||||
class _MerchantDetailPageState extends State<MerchantDetailPage> {
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
final List<GlobalKey> _productSectionKeys = [];
|
||||
|
||||
String _selectedCategoryId = "";
|
||||
|
||||
// Sample data
|
||||
final List<ProductCategory> categories = [
|
||||
ProductCategory(id: "1", name: "Makanan", icon: "🍽️", productCount: 8),
|
||||
ProductCategory(id: "2", name: "Minuman", icon: "🥤", productCount: 6),
|
||||
ProductCategory(id: "3", name: "Snack", icon: "🍿", productCount: 5),
|
||||
ProductCategory(id: "4", name: "Es Krim", icon: "🍦", productCount: 4),
|
||||
ProductCategory(id: "5", name: "Paket", icon: "📦", productCount: 3),
|
||||
];
|
||||
|
||||
final List<Product> products = [
|
||||
// Makanan
|
||||
Product(
|
||||
id: "1",
|
||||
name: "Nasi Gudeg",
|
||||
description: "Gudeg khas Yogyakarta dengan ayam dan telur",
|
||||
price: 25000,
|
||||
categoryId: "1",
|
||||
imageUrl: "https://via.placeholder.com/150",
|
||||
isAvailable: true,
|
||||
rating: 4.5,
|
||||
soldCount: 50,
|
||||
),
|
||||
Product(
|
||||
id: "2",
|
||||
name: "Soto Ayam",
|
||||
description: "Soto ayam kuning dengan nasi dan kerupuk",
|
||||
price: 18000,
|
||||
categoryId: "1",
|
||||
imageUrl: "https://via.placeholder.com/150",
|
||||
isAvailable: true,
|
||||
rating: 4.3,
|
||||
soldCount: 75,
|
||||
),
|
||||
Product(
|
||||
id: "3",
|
||||
name: "Gado-gado",
|
||||
description: "Gado-gado segar dengan bumbu kacang",
|
||||
price: 15000,
|
||||
categoryId: "1",
|
||||
imageUrl: "https://via.placeholder.com/150",
|
||||
isAvailable: false,
|
||||
rating: 4.2,
|
||||
soldCount: 30,
|
||||
),
|
||||
|
||||
// Minuman
|
||||
Product(
|
||||
id: "4",
|
||||
name: "Es Teh Manis",
|
||||
description: "Es teh manis segar",
|
||||
price: 5000,
|
||||
categoryId: "2",
|
||||
imageUrl: "https://via.placeholder.com/150",
|
||||
isAvailable: true,
|
||||
rating: 4.0,
|
||||
soldCount: 120,
|
||||
),
|
||||
Product(
|
||||
id: "5",
|
||||
name: "Jus Jeruk",
|
||||
description: "Jus jeruk segar tanpa gula tambahan",
|
||||
price: 12000,
|
||||
categoryId: "2",
|
||||
imageUrl: "https://via.placeholder.com/150",
|
||||
isAvailable: true,
|
||||
rating: 4.4,
|
||||
soldCount: 45,
|
||||
),
|
||||
|
||||
// Snack
|
||||
Product(
|
||||
id: "6",
|
||||
name: "Keripik Pisang",
|
||||
description: "Keripik pisang renyah dan manis",
|
||||
price: 8000,
|
||||
categoryId: "3",
|
||||
imageUrl: "https://via.placeholder.com/150",
|
||||
isAvailable: true,
|
||||
rating: 4.1,
|
||||
soldCount: 25,
|
||||
),
|
||||
];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_selectedCategoryId = categories.isNotEmpty ? categories.first.id : "";
|
||||
|
||||
// Initialize keys for each category
|
||||
for (int i = 0; i < categories.length; i++) {
|
||||
_productSectionKeys.add(GlobalKey());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_scrollController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _scrollToCategory(String categoryId) {
|
||||
setState(() {
|
||||
_selectedCategoryId = categoryId;
|
||||
});
|
||||
|
||||
final categoryIndex = categories.indexWhere((cat) => cat.id == categoryId);
|
||||
if (categoryIndex >= 0 && categoryIndex < _productSectionKeys.length) {
|
||||
final key = _productSectionKeys[categoryIndex];
|
||||
final context = key.currentContext;
|
||||
|
||||
if (context != null) {
|
||||
Future.delayed(Duration(milliseconds: 100), () {
|
||||
if (mounted) {
|
||||
Scrollable.ensureVisible(
|
||||
context,
|
||||
duration: Duration(milliseconds: 500),
|
||||
curve: Curves.easeInOut,
|
||||
alignment: 0.1,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Product> _getProductsByCategory(String categoryId) {
|
||||
return products
|
||||
.where((product) => product.categoryId == categoryId)
|
||||
.toList();
|
||||
}
|
||||
|
||||
String _formatCurrency(int amount) {
|
||||
return amount.toString().replaceAllMapped(
|
||||
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
|
||||
(Match m) => '${m[1]}.',
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColor.background,
|
||||
body: CustomScrollView(
|
||||
controller: _scrollController,
|
||||
slivers: [
|
||||
// App Bar with merchant info
|
||||
SliverAppBar(
|
||||
expandedHeight: 280,
|
||||
pinned: true,
|
||||
backgroundColor: AppColor.primary,
|
||||
leading: IconButton(
|
||||
icon: Icon(Icons.arrow_back, color: AppColor.textWhite),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.share, color: AppColor.textWhite),
|
||||
onPressed: () {},
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.favorite_border, color: AppColor.textWhite),
|
||||
onPressed: () {},
|
||||
),
|
||||
],
|
||||
flexibleSpace: FlexibleSpaceBar(background: _buildMerchantHeader()),
|
||||
),
|
||||
|
||||
// Categories (will be pinned)
|
||||
SliverPersistentHeader(
|
||||
pinned: true,
|
||||
delegate: _SliverCategoryDelegate(
|
||||
categories: categories,
|
||||
selectedCategoryId: _selectedCategoryId,
|
||||
onCategoryTap: _scrollToCategory,
|
||||
),
|
||||
),
|
||||
|
||||
// Product sections by category
|
||||
...categories.map((category) {
|
||||
final categoryProducts = _getProductsByCategory(category.id);
|
||||
final categoryIndex = categories.indexOf(category);
|
||||
|
||||
return SliverToBoxAdapter(
|
||||
key: _productSectionKeys[categoryIndex],
|
||||
child: _buildProductSection(category, categoryProducts),
|
||||
);
|
||||
}).toList(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildMerchantHeader() {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [AppColor.primary, AppColor.primary.withOpacity(0.8)],
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
),
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
// Background decoration
|
||||
Positioned(
|
||||
right: 20,
|
||||
top: 60,
|
||||
child: Opacity(
|
||||
opacity: 0.1,
|
||||
child: Icon(Icons.store, size: 100, color: AppColor.textWhite),
|
||||
),
|
||||
),
|
||||
|
||||
// Content
|
||||
Positioned(
|
||||
left: 20,
|
||||
right: 20,
|
||||
bottom: 20,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Merchant avatar
|
||||
Container(
|
||||
width: 80,
|
||||
height: 80,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.surface,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColor.black.withOpacity(0.2),
|
||||
blurRadius: 8,
|
||||
offset: Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
_getCategoryIcon(widget.merchant.category),
|
||||
style: TextStyle(fontSize: 36),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(height: 16),
|
||||
|
||||
// Merchant name
|
||||
Text(
|
||||
widget.merchant.name,
|
||||
style: AppStyle.h4.copyWith(
|
||||
color: AppColor.textWhite,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(height: 4),
|
||||
|
||||
// Category and status
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
widget.merchant.category,
|
||||
style: AppStyle.md.copyWith(
|
||||
color: AppColor.textWhite.withOpacity(0.9),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 12),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: widget.merchant.isOpen
|
||||
? AppColor.success
|
||||
: AppColor.error,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Text(
|
||||
widget.merchant.isOpen ? "BUKA" : "TUTUP",
|
||||
style: AppStyle.xs.copyWith(
|
||||
color: AppColor.textWhite,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
SizedBox(height: 8),
|
||||
|
||||
// Rating
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.star, color: AppColor.warning, size: 16),
|
||||
SizedBox(width: 4),
|
||||
Text(
|
||||
"${widget.merchant.rating}",
|
||||
style: AppStyle.md.copyWith(
|
||||
color: AppColor.textWhite,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
"• ${products.length} produk",
|
||||
style: AppStyle.sm.copyWith(
|
||||
color: AppColor.textWhite.withOpacity(0.8),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildProductSection(
|
||||
ProductCategory category,
|
||||
List<Product> categoryProducts,
|
||||
) {
|
||||
return Container(
|
||||
margin: EdgeInsets.only(bottom: 24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Section header
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(category.icon, style: AppStyle.h5),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
category.name,
|
||||
style: AppStyle.lg.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColor.textPrimary,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
"(${categoryProducts.length})",
|
||||
style: AppStyle.md.copyWith(color: AppColor.textSecondary),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// Products grid
|
||||
if (categoryProducts.isEmpty)
|
||||
_buildEmptyCategory()
|
||||
else
|
||||
GridView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
crossAxisSpacing: 12,
|
||||
mainAxisSpacing: 12,
|
||||
childAspectRatio: 0.75,
|
||||
),
|
||||
itemCount: categoryProducts.length,
|
||||
itemBuilder: (context, index) {
|
||||
return _buildProductCard(categoryProducts[index]);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildProductCard(Product product) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.surface,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColor.black.withOpacity(0.06),
|
||||
blurRadius: 8,
|
||||
offset: Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Product image
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.backgroundLight,
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: Radius.circular(12),
|
||||
),
|
||||
),
|
||||
child: Center(
|
||||
child: Icon(
|
||||
Icons.fastfood,
|
||||
size: 40,
|
||||
color: AppColor.textLight,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Availability overlay
|
||||
if (!product.isAvailable)
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.black.withOpacity(0.6),
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: Radius.circular(12),
|
||||
),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
"HABIS",
|
||||
style: AppStyle.sm.copyWith(
|
||||
color: AppColor.textWhite,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Rating badge
|
||||
Positioned(
|
||||
top: 8,
|
||||
right: 8,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.surface,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(Icons.star, size: 12, color: AppColor.warning),
|
||||
SizedBox(width: 2),
|
||||
Text(
|
||||
"${product.rating}",
|
||||
style: AppStyle.xs.copyWith(
|
||||
color: AppColor.textPrimary,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// Product info
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
product.name,
|
||||
style: AppStyle.md.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColor.textPrimary,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
|
||||
Spacer(),
|
||||
|
||||
// Price and sold count
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Rp ${_formatCurrency(product.price)}",
|
||||
style: AppStyle.md.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColor.primary,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"${product.soldCount} terjual",
|
||||
style: AppStyle.xs.copyWith(
|
||||
color: AppColor.textSecondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildEmptyCategory() {
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 16),
|
||||
padding: EdgeInsets.all(24),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.surface,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: AppColor.borderLight),
|
||||
),
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.inventory_2_outlined,
|
||||
size: 48,
|
||||
color: AppColor.textLight,
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
Text(
|
||||
"Belum ada produk",
|
||||
style: AppStyle.md.copyWith(color: AppColor.textSecondary),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _getCategoryIcon(String category) {
|
||||
switch (category.toLowerCase()) {
|
||||
case 'food & beverage':
|
||||
return '🍽️';
|
||||
case 'electronics':
|
||||
return '📱';
|
||||
case 'healthcare':
|
||||
return '⚕️';
|
||||
case 'clothing':
|
||||
return '👕';
|
||||
case 'automotive':
|
||||
return '🚗';
|
||||
case 'retail':
|
||||
return '🛍️';
|
||||
case 'beauty':
|
||||
return '💄';
|
||||
case 'service':
|
||||
return '🔧';
|
||||
default:
|
||||
return '🏪';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Custom delegate for pinned category bar
|
||||
class _SliverCategoryDelegate extends SliverPersistentHeaderDelegate {
|
||||
final List<ProductCategory> categories;
|
||||
final String selectedCategoryId;
|
||||
final Function(String) onCategoryTap;
|
||||
|
||||
_SliverCategoryDelegate({
|
||||
required this.categories,
|
||||
required this.selectedCategoryId,
|
||||
required this.onCategoryTap,
|
||||
});
|
||||
|
||||
@override
|
||||
double get minExtent => 60;
|
||||
|
||||
@override
|
||||
double get maxExtent => 60;
|
||||
|
||||
@override
|
||||
Widget build(
|
||||
BuildContext context,
|
||||
double shrinkOffset,
|
||||
bool overlapsContent,
|
||||
) {
|
||||
return Container(
|
||||
height: 60,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.surface,
|
||||
border: Border(
|
||||
bottom: BorderSide(color: AppColor.borderLight, width: 1),
|
||||
),
|
||||
),
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
itemCount: categories.length,
|
||||
itemBuilder: (context, index) {
|
||||
final category = categories[index];
|
||||
final isSelected = category.id == selectedCategoryId;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () => onCategoryTap(category.id),
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(right: 12),
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected ? AppColor.primary : AppColor.backgroundLight,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(
|
||||
color: isSelected ? AppColor.primary : AppColor.border,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(category.icon, style: AppStyle.md),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
category.name,
|
||||
style: AppStyle.md.copyWith(
|
||||
color: isSelected
|
||||
? AppColor.textWhite
|
||||
: AppColor.textPrimary,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 4),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? AppColor.textWhite.withOpacity(0.2)
|
||||
: AppColor.primary.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Text(
|
||||
"${category.productCount}",
|
||||
style: AppStyle.xs.copyWith(
|
||||
color: isSelected
|
||||
? AppColor.textWhite
|
||||
: AppColor.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
|
||||
return oldDelegate is _SliverCategoryDelegate &&
|
||||
(oldDelegate.selectedCategoryId != selectedCategoryId ||
|
||||
oldDelegate.categories != categories);
|
||||
}
|
||||
}
|
||||
@ -30,6 +30,7 @@ class AppRouter extends RootStackRouter {
|
||||
|
||||
// Merchant
|
||||
AutoRoute(page: MerchantRoute.page),
|
||||
AutoRoute(page: MerchantDetailRoute.page),
|
||||
|
||||
// Reward
|
||||
AutoRoute(page: RewardRoute.page),
|
||||
|
||||
@ -9,12 +9,12 @@
|
||||
// coverage:ignore-file
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'package:auto_route/auto_route.dart' as _i17;
|
||||
import 'package:auto_route/auto_route.dart' as _i18;
|
||||
import 'package:enaklo/presentation/pages/auth/login/login_page.dart' as _i4;
|
||||
import 'package:enaklo/presentation/pages/auth/otp/otp_page.dart' as _i9;
|
||||
import 'package:enaklo/presentation/pages/auth/pin/pin_page.dart' as _i10;
|
||||
import 'package:enaklo/presentation/pages/auth/otp/otp_page.dart' as _i10;
|
||||
import 'package:enaklo/presentation/pages/auth/pin/pin_page.dart' as _i11;
|
||||
import 'package:enaklo/presentation/pages/auth/register/register_page.dart'
|
||||
as _i13;
|
||||
as _i14;
|
||||
import 'package:enaklo/presentation/pages/draw/draw_page.dart' as _i2;
|
||||
import 'package:enaklo/presentation/pages/draw/pages/draw_detail/draw_detail_page.dart'
|
||||
as _i1;
|
||||
@ -22,27 +22,29 @@ import 'package:enaklo/presentation/pages/main/main_page.dart' as _i5;
|
||||
import 'package:enaklo/presentation/pages/main/pages/home/home_page.dart'
|
||||
as _i3;
|
||||
import 'package:enaklo/presentation/pages/main/pages/order/order_page.dart'
|
||||
as _i8;
|
||||
as _i9;
|
||||
import 'package:enaklo/presentation/pages/main/pages/profile/profile_page.dart'
|
||||
as _i12;
|
||||
as _i13;
|
||||
import 'package:enaklo/presentation/pages/main/pages/voucher/voucher_page.dart'
|
||||
as _i16;
|
||||
import 'package:enaklo/presentation/pages/merchant/merchant_page.dart' as _i6;
|
||||
as _i17;
|
||||
import 'package:enaklo/presentation/pages/merchant/merchant_page.dart' as _i7;
|
||||
import 'package:enaklo/presentation/pages/merchant/pages/merchant_detail/merchant_detail_page.dart'
|
||||
as _i6;
|
||||
import 'package:enaklo/presentation/pages/onboarding/onboarding_page.dart'
|
||||
as _i7;
|
||||
as _i8;
|
||||
import 'package:enaklo/presentation/pages/reward/pages/product_redeem/product_redeem_page.dart'
|
||||
as _i11;
|
||||
import 'package:enaklo/presentation/pages/reward/reward_page.dart' as _i14;
|
||||
import 'package:enaklo/presentation/pages/splash/splash_page.dart' as _i15;
|
||||
import 'package:flutter/material.dart' as _i18;
|
||||
as _i12;
|
||||
import 'package:enaklo/presentation/pages/reward/reward_page.dart' as _i15;
|
||||
import 'package:enaklo/presentation/pages/splash/splash_page.dart' as _i16;
|
||||
import 'package:flutter/material.dart' as _i19;
|
||||
|
||||
/// generated route for
|
||||
/// [_i1.DrawDetailPage]
|
||||
class DrawDetailRoute extends _i17.PageRouteInfo<DrawDetailRouteArgs> {
|
||||
class DrawDetailRoute extends _i18.PageRouteInfo<DrawDetailRouteArgs> {
|
||||
DrawDetailRoute({
|
||||
_i18.Key? key,
|
||||
_i19.Key? key,
|
||||
required _i2.DrawEvent drawEvent,
|
||||
List<_i17.PageRouteInfo>? children,
|
||||
List<_i18.PageRouteInfo>? children,
|
||||
}) : super(
|
||||
DrawDetailRoute.name,
|
||||
args: DrawDetailRouteArgs(key: key, drawEvent: drawEvent),
|
||||
@ -51,7 +53,7 @@ class DrawDetailRoute extends _i17.PageRouteInfo<DrawDetailRouteArgs> {
|
||||
|
||||
static const String name = 'DrawDetailRoute';
|
||||
|
||||
static _i17.PageInfo page = _i17.PageInfo(
|
||||
static _i18.PageInfo page = _i18.PageInfo(
|
||||
name,
|
||||
builder: (data) {
|
||||
final args = data.argsAs<DrawDetailRouteArgs>();
|
||||
@ -63,7 +65,7 @@ class DrawDetailRoute extends _i17.PageRouteInfo<DrawDetailRouteArgs> {
|
||||
class DrawDetailRouteArgs {
|
||||
const DrawDetailRouteArgs({this.key, required this.drawEvent});
|
||||
|
||||
final _i18.Key? key;
|
||||
final _i19.Key? key;
|
||||
|
||||
final _i2.DrawEvent drawEvent;
|
||||
|
||||
@ -75,13 +77,13 @@ class DrawDetailRouteArgs {
|
||||
|
||||
/// generated route for
|
||||
/// [_i2.DrawPage]
|
||||
class DrawRoute extends _i17.PageRouteInfo<void> {
|
||||
const DrawRoute({List<_i17.PageRouteInfo>? children})
|
||||
class DrawRoute extends _i18.PageRouteInfo<void> {
|
||||
const DrawRoute({List<_i18.PageRouteInfo>? children})
|
||||
: super(DrawRoute.name, initialChildren: children);
|
||||
|
||||
static const String name = 'DrawRoute';
|
||||
|
||||
static _i17.PageInfo page = _i17.PageInfo(
|
||||
static _i18.PageInfo page = _i18.PageInfo(
|
||||
name,
|
||||
builder: (data) {
|
||||
return const _i2.DrawPage();
|
||||
@ -91,13 +93,13 @@ class DrawRoute extends _i17.PageRouteInfo<void> {
|
||||
|
||||
/// generated route for
|
||||
/// [_i3.HomePage]
|
||||
class HomeRoute extends _i17.PageRouteInfo<void> {
|
||||
const HomeRoute({List<_i17.PageRouteInfo>? children})
|
||||
class HomeRoute extends _i18.PageRouteInfo<void> {
|
||||
const HomeRoute({List<_i18.PageRouteInfo>? children})
|
||||
: super(HomeRoute.name, initialChildren: children);
|
||||
|
||||
static const String name = 'HomeRoute';
|
||||
|
||||
static _i17.PageInfo page = _i17.PageInfo(
|
||||
static _i18.PageInfo page = _i18.PageInfo(
|
||||
name,
|
||||
builder: (data) {
|
||||
return const _i3.HomePage();
|
||||
@ -107,13 +109,13 @@ class HomeRoute extends _i17.PageRouteInfo<void> {
|
||||
|
||||
/// generated route for
|
||||
/// [_i4.LoginPage]
|
||||
class LoginRoute extends _i17.PageRouteInfo<void> {
|
||||
const LoginRoute({List<_i17.PageRouteInfo>? children})
|
||||
class LoginRoute extends _i18.PageRouteInfo<void> {
|
||||
const LoginRoute({List<_i18.PageRouteInfo>? children})
|
||||
: super(LoginRoute.name, initialChildren: children);
|
||||
|
||||
static const String name = 'LoginRoute';
|
||||
|
||||
static _i17.PageInfo page = _i17.PageInfo(
|
||||
static _i18.PageInfo page = _i18.PageInfo(
|
||||
name,
|
||||
builder: (data) {
|
||||
return const _i4.LoginPage();
|
||||
@ -123,13 +125,13 @@ class LoginRoute extends _i17.PageRouteInfo<void> {
|
||||
|
||||
/// generated route for
|
||||
/// [_i5.MainPage]
|
||||
class MainRoute extends _i17.PageRouteInfo<void> {
|
||||
const MainRoute({List<_i17.PageRouteInfo>? children})
|
||||
class MainRoute extends _i18.PageRouteInfo<void> {
|
||||
const MainRoute({List<_i18.PageRouteInfo>? children})
|
||||
: super(MainRoute.name, initialChildren: children);
|
||||
|
||||
static const String name = 'MainRoute';
|
||||
|
||||
static _i17.PageInfo page = _i17.PageInfo(
|
||||
static _i18.PageInfo page = _i18.PageInfo(
|
||||
name,
|
||||
builder: (data) {
|
||||
return const _i5.MainPage();
|
||||
@ -138,77 +140,114 @@ class MainRoute extends _i17.PageRouteInfo<void> {
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [_i6.MerchantPage]
|
||||
class MerchantRoute extends _i17.PageRouteInfo<void> {
|
||||
const MerchantRoute({List<_i17.PageRouteInfo>? children})
|
||||
/// [_i6.MerchantDetailPage]
|
||||
class MerchantDetailRoute extends _i18.PageRouteInfo<MerchantDetailRouteArgs> {
|
||||
MerchantDetailRoute({
|
||||
_i19.Key? key,
|
||||
required _i7.MerchantModel merchant,
|
||||
List<_i18.PageRouteInfo>? children,
|
||||
}) : super(
|
||||
MerchantDetailRoute.name,
|
||||
args: MerchantDetailRouteArgs(key: key, merchant: merchant),
|
||||
initialChildren: children,
|
||||
);
|
||||
|
||||
static const String name = 'MerchantDetailRoute';
|
||||
|
||||
static _i18.PageInfo page = _i18.PageInfo(
|
||||
name,
|
||||
builder: (data) {
|
||||
final args = data.argsAs<MerchantDetailRouteArgs>();
|
||||
return _i6.MerchantDetailPage(key: args.key, merchant: args.merchant);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
class MerchantDetailRouteArgs {
|
||||
const MerchantDetailRouteArgs({this.key, required this.merchant});
|
||||
|
||||
final _i19.Key? key;
|
||||
|
||||
final _i7.MerchantModel merchant;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'MerchantDetailRouteArgs{key: $key, merchant: $merchant}';
|
||||
}
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [_i7.MerchantPage]
|
||||
class MerchantRoute extends _i18.PageRouteInfo<void> {
|
||||
const MerchantRoute({List<_i18.PageRouteInfo>? children})
|
||||
: super(MerchantRoute.name, initialChildren: children);
|
||||
|
||||
static const String name = 'MerchantRoute';
|
||||
|
||||
static _i17.PageInfo page = _i17.PageInfo(
|
||||
static _i18.PageInfo page = _i18.PageInfo(
|
||||
name,
|
||||
builder: (data) {
|
||||
return const _i6.MerchantPage();
|
||||
return const _i7.MerchantPage();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [_i7.OnboardingPage]
|
||||
class OnboardingRoute extends _i17.PageRouteInfo<void> {
|
||||
const OnboardingRoute({List<_i17.PageRouteInfo>? children})
|
||||
/// [_i8.OnboardingPage]
|
||||
class OnboardingRoute extends _i18.PageRouteInfo<void> {
|
||||
const OnboardingRoute({List<_i18.PageRouteInfo>? children})
|
||||
: super(OnboardingRoute.name, initialChildren: children);
|
||||
|
||||
static const String name = 'OnboardingRoute';
|
||||
|
||||
static _i17.PageInfo page = _i17.PageInfo(
|
||||
static _i18.PageInfo page = _i18.PageInfo(
|
||||
name,
|
||||
builder: (data) {
|
||||
return const _i7.OnboardingPage();
|
||||
return const _i8.OnboardingPage();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [_i8.OrderPage]
|
||||
class OrderRoute extends _i17.PageRouteInfo<void> {
|
||||
const OrderRoute({List<_i17.PageRouteInfo>? children})
|
||||
/// [_i9.OrderPage]
|
||||
class OrderRoute extends _i18.PageRouteInfo<void> {
|
||||
const OrderRoute({List<_i18.PageRouteInfo>? children})
|
||||
: super(OrderRoute.name, initialChildren: children);
|
||||
|
||||
static const String name = 'OrderRoute';
|
||||
|
||||
static _i17.PageInfo page = _i17.PageInfo(
|
||||
static _i18.PageInfo page = _i18.PageInfo(
|
||||
name,
|
||||
builder: (data) {
|
||||
return const _i8.OrderPage();
|
||||
return const _i9.OrderPage();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [_i9.OtpPage]
|
||||
class OtpRoute extends _i17.PageRouteInfo<void> {
|
||||
const OtpRoute({List<_i17.PageRouteInfo>? children})
|
||||
/// [_i10.OtpPage]
|
||||
class OtpRoute extends _i18.PageRouteInfo<void> {
|
||||
const OtpRoute({List<_i18.PageRouteInfo>? children})
|
||||
: super(OtpRoute.name, initialChildren: children);
|
||||
|
||||
static const String name = 'OtpRoute';
|
||||
|
||||
static _i17.PageInfo page = _i17.PageInfo(
|
||||
static _i18.PageInfo page = _i18.PageInfo(
|
||||
name,
|
||||
builder: (data) {
|
||||
return const _i9.OtpPage();
|
||||
return const _i10.OtpPage();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [_i10.PinPage]
|
||||
class PinRoute extends _i17.PageRouteInfo<PinRouteArgs> {
|
||||
/// [_i11.PinPage]
|
||||
class PinRoute extends _i18.PageRouteInfo<PinRouteArgs> {
|
||||
PinRoute({
|
||||
_i18.Key? key,
|
||||
_i19.Key? key,
|
||||
bool isCreatePin = true,
|
||||
String? title,
|
||||
List<_i17.PageRouteInfo>? children,
|
||||
List<_i18.PageRouteInfo>? children,
|
||||
}) : super(
|
||||
PinRoute.name,
|
||||
args: PinRouteArgs(key: key, isCreatePin: isCreatePin, title: title),
|
||||
@ -217,13 +256,13 @@ class PinRoute extends _i17.PageRouteInfo<PinRouteArgs> {
|
||||
|
||||
static const String name = 'PinRoute';
|
||||
|
||||
static _i17.PageInfo page = _i17.PageInfo(
|
||||
static _i18.PageInfo page = _i18.PageInfo(
|
||||
name,
|
||||
builder: (data) {
|
||||
final args = data.argsAs<PinRouteArgs>(
|
||||
orElse: () => const PinRouteArgs(),
|
||||
);
|
||||
return _i10.PinPage(
|
||||
return _i11.PinPage(
|
||||
key: args.key,
|
||||
isCreatePin: args.isCreatePin,
|
||||
title: args.title,
|
||||
@ -235,7 +274,7 @@ class PinRoute extends _i17.PageRouteInfo<PinRouteArgs> {
|
||||
class PinRouteArgs {
|
||||
const PinRouteArgs({this.key, this.isCreatePin = true, this.title});
|
||||
|
||||
final _i18.Key? key;
|
||||
final _i19.Key? key;
|
||||
|
||||
final bool isCreatePin;
|
||||
|
||||
@ -248,14 +287,14 @@ class PinRouteArgs {
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [_i11.ProductRedeemPage]
|
||||
class ProductRedeemRoute extends _i17.PageRouteInfo<ProductRedeemRouteArgs> {
|
||||
/// [_i12.ProductRedeemPage]
|
||||
class ProductRedeemRoute extends _i18.PageRouteInfo<ProductRedeemRouteArgs> {
|
||||
ProductRedeemRoute({
|
||||
_i18.Key? key,
|
||||
required _i14.Product product,
|
||||
required _i14.Merchant merchant,
|
||||
required _i14.PointCard pointCard,
|
||||
List<_i17.PageRouteInfo>? children,
|
||||
_i19.Key? key,
|
||||
required _i15.Product product,
|
||||
required _i15.Merchant merchant,
|
||||
required _i15.PointCard pointCard,
|
||||
List<_i18.PageRouteInfo>? children,
|
||||
}) : super(
|
||||
ProductRedeemRoute.name,
|
||||
args: ProductRedeemRouteArgs(
|
||||
@ -269,11 +308,11 @@ class ProductRedeemRoute extends _i17.PageRouteInfo<ProductRedeemRouteArgs> {
|
||||
|
||||
static const String name = 'ProductRedeemRoute';
|
||||
|
||||
static _i17.PageInfo page = _i17.PageInfo(
|
||||
static _i18.PageInfo page = _i18.PageInfo(
|
||||
name,
|
||||
builder: (data) {
|
||||
final args = data.argsAs<ProductRedeemRouteArgs>();
|
||||
return _i11.ProductRedeemPage(
|
||||
return _i12.ProductRedeemPage(
|
||||
key: args.key,
|
||||
product: args.product,
|
||||
merchant: args.merchant,
|
||||
@ -291,13 +330,13 @@ class ProductRedeemRouteArgs {
|
||||
required this.pointCard,
|
||||
});
|
||||
|
||||
final _i18.Key? key;
|
||||
final _i19.Key? key;
|
||||
|
||||
final _i14.Product product;
|
||||
final _i15.Product product;
|
||||
|
||||
final _i14.Merchant merchant;
|
||||
final _i15.Merchant merchant;
|
||||
|
||||
final _i14.PointCard pointCard;
|
||||
final _i15.PointCard pointCard;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
@ -306,81 +345,81 @@ class ProductRedeemRouteArgs {
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [_i12.ProfilePage]
|
||||
class ProfileRoute extends _i17.PageRouteInfo<void> {
|
||||
const ProfileRoute({List<_i17.PageRouteInfo>? children})
|
||||
/// [_i13.ProfilePage]
|
||||
class ProfileRoute extends _i18.PageRouteInfo<void> {
|
||||
const ProfileRoute({List<_i18.PageRouteInfo>? children})
|
||||
: super(ProfileRoute.name, initialChildren: children);
|
||||
|
||||
static const String name = 'ProfileRoute';
|
||||
|
||||
static _i17.PageInfo page = _i17.PageInfo(
|
||||
static _i18.PageInfo page = _i18.PageInfo(
|
||||
name,
|
||||
builder: (data) {
|
||||
return const _i12.ProfilePage();
|
||||
return const _i13.ProfilePage();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [_i13.RegisterPage]
|
||||
class RegisterRoute extends _i17.PageRouteInfo<void> {
|
||||
const RegisterRoute({List<_i17.PageRouteInfo>? children})
|
||||
/// [_i14.RegisterPage]
|
||||
class RegisterRoute extends _i18.PageRouteInfo<void> {
|
||||
const RegisterRoute({List<_i18.PageRouteInfo>? children})
|
||||
: super(RegisterRoute.name, initialChildren: children);
|
||||
|
||||
static const String name = 'RegisterRoute';
|
||||
|
||||
static _i17.PageInfo page = _i17.PageInfo(
|
||||
static _i18.PageInfo page = _i18.PageInfo(
|
||||
name,
|
||||
builder: (data) {
|
||||
return const _i13.RegisterPage();
|
||||
return const _i14.RegisterPage();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [_i14.RewardPage]
|
||||
class RewardRoute extends _i17.PageRouteInfo<void> {
|
||||
const RewardRoute({List<_i17.PageRouteInfo>? children})
|
||||
/// [_i15.RewardPage]
|
||||
class RewardRoute extends _i18.PageRouteInfo<void> {
|
||||
const RewardRoute({List<_i18.PageRouteInfo>? children})
|
||||
: super(RewardRoute.name, initialChildren: children);
|
||||
|
||||
static const String name = 'RewardRoute';
|
||||
|
||||
static _i17.PageInfo page = _i17.PageInfo(
|
||||
static _i18.PageInfo page = _i18.PageInfo(
|
||||
name,
|
||||
builder: (data) {
|
||||
return const _i14.RewardPage();
|
||||
return const _i15.RewardPage();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [_i15.SplashPage]
|
||||
class SplashRoute extends _i17.PageRouteInfo<void> {
|
||||
const SplashRoute({List<_i17.PageRouteInfo>? children})
|
||||
/// [_i16.SplashPage]
|
||||
class SplashRoute extends _i18.PageRouteInfo<void> {
|
||||
const SplashRoute({List<_i18.PageRouteInfo>? children})
|
||||
: super(SplashRoute.name, initialChildren: children);
|
||||
|
||||
static const String name = 'SplashRoute';
|
||||
|
||||
static _i17.PageInfo page = _i17.PageInfo(
|
||||
static _i18.PageInfo page = _i18.PageInfo(
|
||||
name,
|
||||
builder: (data) {
|
||||
return const _i15.SplashPage();
|
||||
return const _i16.SplashPage();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [_i16.VoucherPage]
|
||||
class VoucherRoute extends _i17.PageRouteInfo<void> {
|
||||
const VoucherRoute({List<_i17.PageRouteInfo>? children})
|
||||
/// [_i17.VoucherPage]
|
||||
class VoucherRoute extends _i18.PageRouteInfo<void> {
|
||||
const VoucherRoute({List<_i18.PageRouteInfo>? children})
|
||||
: super(VoucherRoute.name, initialChildren: children);
|
||||
|
||||
static const String name = 'VoucherRoute';
|
||||
|
||||
static _i17.PageInfo page = _i17.PageInfo(
|
||||
static _i18.PageInfo page = _i18.PageInfo(
|
||||
name,
|
||||
builder: (data) {
|
||||
return const _i16.VoucherPage();
|
||||
return const _i17.VoucherPage();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user