diff --git a/assets/images/bakso343.jpeg b/assets/images/bakso343.jpeg new file mode 100644 index 0000000..ef67f5e Binary files /dev/null and b/assets/images/bakso343.jpeg differ diff --git a/assets/images/ramenmulu.jpeg b/assets/images/ramenmulu.jpeg new file mode 100644 index 0000000..6ee1919 Binary files /dev/null and b/assets/images/ramenmulu.jpeg differ diff --git a/assets/images/tumulu.jpeg b/assets/images/tumulu.jpeg new file mode 100644 index 0000000..227af1a Binary files /dev/null and b/assets/images/tumulu.jpeg differ diff --git a/assets/images/woku.jpeg b/assets/images/woku.jpeg new file mode 100644 index 0000000..543bce2 Binary files /dev/null and b/assets/images/woku.jpeg differ diff --git a/lib/presentation/components/assets/assets.gen.dart b/lib/presentation/components/assets/assets.gen.dart index 16673c3..4ca2ee5 100644 --- a/lib/presentation/components/assets/assets.gen.dart +++ b/lib/presentation/components/assets/assets.gen.dart @@ -14,6 +14,10 @@ import 'package:flutter/widgets.dart'; class $AssetsImagesGen { const $AssetsImagesGen(); + /// File path: assets/images/bakso343.jpeg + AssetGenImage get bakso343 => + const AssetGenImage('assets/images/bakso343.jpeg'); + /// File path: assets/images/launcher.png AssetGenImage get launcher => const AssetGenImage('assets/images/launcher.png'); @@ -33,13 +37,27 @@ class $AssetsImagesGen { AssetGenImage get onboarding3 => const AssetGenImage('assets/images/onboarding3.png'); + /// File path: assets/images/ramenmulu.jpeg + AssetGenImage get ramenmulu => + const AssetGenImage('assets/images/ramenmulu.jpeg'); + + /// File path: assets/images/tumulu.jpeg + AssetGenImage get tumulu => const AssetGenImage('assets/images/tumulu.jpeg'); + + /// File path: assets/images/woku.jpeg + AssetGenImage get woku => const AssetGenImage('assets/images/woku.jpeg'); + /// List of all assets List get values => [ + bakso343, launcher, logo, onboarding1, onboarding2, onboarding3, + ramenmulu, + tumulu, + woku, ]; } diff --git a/lib/presentation/pages/main/pages/home/widgets/popular_merchant_card.dart b/lib/presentation/pages/main/pages/home/widgets/popular_merchant_card.dart index 1ad3405..b038e07 100644 --- a/lib/presentation/pages/main/pages/home/widgets/popular_merchant_card.dart +++ b/lib/presentation/pages/main/pages/home/widgets/popular_merchant_card.dart @@ -1,26 +1,17 @@ import 'package:flutter/material.dart'; import '../../../../../../common/theme/theme.dart'; +import '../../../../../../sample/sample_data.dart'; import '../../../../../components/image/image.dart'; class HomePopularMerchantCard extends StatelessWidget { - final String merchantName; - final String merchantImage; - final String category; - final double rating; - final String distance; - final bool isOpen; + final MerchantModel merchant; final VoidCallback? onTap; const HomePopularMerchantCard({ super.key, - required this.merchantName, - required this.merchantImage, - required this.category, - required this.rating, - required this.distance, - this.isOpen = true, this.onTap, + required this.merchant, }); @override @@ -53,15 +44,25 @@ class HomePopularMerchantCard extends StatelessWidget { ), child: ClipRRect( borderRadius: BorderRadius.circular(8), - child: Image.network( - merchantImage, - width: 60, - height: 60, - fit: BoxFit.cover, - errorBuilder: (context, error, stackTrace) { - return ImagePlaceholder(width: 60, height: 60); - }, - ), + child: merchant.imageUrl.startsWith('http') + ? Image.network( + merchant.imageUrl, + width: 60, + height: 60, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return ImagePlaceholder(width: 60, height: 60); + }, + ) + : Image.asset( + merchant.imageUrl, + width: 60, + height: 60, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return ImagePlaceholder(width: 60, height: 60); + }, + ), ), ), @@ -73,7 +74,7 @@ class HomePopularMerchantCard extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - merchantName, + merchant.name, style: AppStyle.md.copyWith( fontWeight: FontWeight.w600, height: 1.2, @@ -85,31 +86,11 @@ class HomePopularMerchantCard extends StatelessWidget { const SizedBox(height: 4), Text( - category, + merchant.category, style: AppStyle.sm.copyWith(color: AppColor.textSecondary), maxLines: 1, overflow: TextOverflow.ellipsis, ), - - const SizedBox(height: 6), - - // Distance - Row( - children: [ - Icon( - Icons.location_on, - size: 12, - color: AppColor.textSecondary, - ), - const SizedBox(width: 2), - Text( - distance, - style: AppStyle.xs.copyWith( - color: AppColor.textSecondary, - ), - ), - ], - ), ], ), ), @@ -127,11 +108,11 @@ class HomePopularMerchantCard extends StatelessWidget { vertical: 2, ), decoration: BoxDecoration( - color: isOpen ? AppColor.success : AppColor.error, + color: merchant.isOpen ? AppColor.success : AppColor.error, borderRadius: BorderRadius.circular(6), ), child: Text( - isOpen ? 'OPEN' : 'CLOSED', + merchant.isOpen ? 'OPEN' : 'CLOSED', style: AppStyle.xs.copyWith( color: AppColor.textWhite, fontWeight: FontWeight.w600, @@ -158,7 +139,7 @@ class HomePopularMerchantCard extends StatelessWidget { Icon(Icons.star, size: 12, color: AppColor.warning), const SizedBox(width: 2), Text( - rating.toString(), + merchant.rating.toString(), style: AppStyle.xs.copyWith( fontWeight: FontWeight.w600, color: AppColor.primary, diff --git a/lib/presentation/pages/main/pages/home/widgets/popular_merchant_section.dart b/lib/presentation/pages/main/pages/home/widgets/popular_merchant_section.dart index aa5fbbe..4b154e4 100644 --- a/lib/presentation/pages/main/pages/home/widgets/popular_merchant_section.dart +++ b/lib/presentation/pages/main/pages/home/widgets/popular_merchant_section.dart @@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import '../../../../../../common/theme/theme.dart'; +import '../../../../../../sample/sample_data.dart'; import '../../../../../router/app_router.gr.dart'; import 'popular_merchant_card.dart'; @@ -44,38 +45,9 @@ class HomePopularMerchantSection extends StatelessWidget { ], ), SizedBox(height: 16), - HomePopularMerchantCard( - merchantName: 'Warung Bu Sari', - merchantImage: 'https://via.placeholder.com/280x160', - category: 'Indonesian Food', - rating: 4.8, - distance: '0.5 km', - isOpen: true, - onTap: () {}, - ), - - HomePopularMerchantCard( - merchantName: 'Pizza Corner', - merchantImage: 'https://via.placeholder.com/280x160', - category: 'Italian Food', - rating: 4.6, - distance: '1.2 km', - isOpen: false, - onTap: () { - print('Pizza Corner tapped'); - }, - ), - - HomePopularMerchantCard( - merchantName: 'Kopi Kenangan', - merchantImage: 'https://via.placeholder.com/280x160', - category: 'Coffee & Drinks', - rating: 4.9, - distance: '0.8 km', - isOpen: true, - onTap: () { - print('Kopi Kenangan tapped'); - }, + ...List.generate( + merchants.length, + (index) => HomePopularMerchantCard(merchant: merchants[index]), ), ], ), diff --git a/lib/presentation/pages/main/pages/voucher/widgets/voucher_card.dart b/lib/presentation/pages/main/pages/voucher/widgets/voucher_card.dart index ad747f0..1d80ec9 100644 --- a/lib/presentation/pages/main/pages/voucher/widgets/voucher_card.dart +++ b/lib/presentation/pages/main/pages/voucher/widgets/voucher_card.dart @@ -57,7 +57,7 @@ class VoucherCard extends StatelessWidget { children: [ Text( title, - style: AppStyle.lg.copyWith( + style: AppStyle.md.copyWith( color: AppColor.textPrimary, fontWeight: FontWeight.w600, ), @@ -65,7 +65,7 @@ class VoucherCard extends StatelessWidget { SizedBox(height: 4), Text( subtitle, - style: AppStyle.md.copyWith( + style: AppStyle.sm.copyWith( color: AppColor.textSecondary, ), ), diff --git a/lib/presentation/pages/merchant/merchant_page.dart b/lib/presentation/pages/merchant/merchant_page.dart index 0769c12..bac7b57 100644 --- a/lib/presentation/pages/merchant/merchant_page.dart +++ b/lib/presentation/pages/merchant/merchant_page.dart @@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import '../../../common/theme/theme.dart'; +import '../../../sample/sample_data.dart'; import '../../components/field/field.dart'; import '../../router/app_router.gr.dart'; import 'widgets/empty_merchant_card.dart'; @@ -113,7 +114,7 @@ class _MerchantPageState extends State { Padding( padding: const EdgeInsets.only(right: 8), child: FilterChip( - label: const Text('All'), + label: const Text('Semua'), selected: _selectedCategory == null, onSelected: (selected) { _onCategorySelected(null); @@ -193,89 +194,6 @@ class _MerchantPageState extends State { } static List _generateMockMerchants() { - return [ - MerchantModel( - id: '1', - name: 'Warung Makan Sederhana', - category: 'Food & Beverage', - rating: 4.5, - isOpen: true, - imageUrl: 'https://via.placeholder.com/150', - ), - MerchantModel( - id: '2', - name: 'Toko Elektronik', - category: 'Electronics', - rating: 4.2, - isOpen: true, - imageUrl: 'https://via.placeholder.com/150', - ), - MerchantModel( - id: '3', - name: 'Apotek Sehat', - category: 'Healthcare', - rating: 4.8, - isOpen: false, - imageUrl: 'https://via.placeholder.com/150', - ), - MerchantModel( - id: '4', - name: 'Fashion Store', - category: 'Clothing', - rating: 4.1, - isOpen: true, - imageUrl: 'https://via.placeholder.com/150', - ), - MerchantModel( - id: '5', - name: 'Bengkel Motor', - category: 'Automotive', - rating: 4.3, - isOpen: true, - imageUrl: 'https://via.placeholder.com/150', - ), - MerchantModel( - id: '6', - name: 'Minimarket 24', - category: 'Retail', - rating: 4.0, - isOpen: true, - imageUrl: 'https://via.placeholder.com/150', - ), - MerchantModel( - id: '7', - name: 'Salon Kecantikan', - category: 'Beauty', - rating: 4.6, - isOpen: false, - imageUrl: 'https://via.placeholder.com/150', - ), - MerchantModel( - id: '8', - name: 'Laundry Express', - category: 'Service', - rating: 4.4, - isOpen: true, - imageUrl: 'https://via.placeholder.com/150', - ), - ]; + return merchants; } } - -class MerchantModel { - final String id; - final String name; - final String category; - final double rating; - final bool isOpen; - final String imageUrl; - - MerchantModel({ - required this.id, - required this.name, - required this.category, - required this.rating, - required this.isOpen, - required this.imageUrl, - }); -} diff --git a/lib/presentation/pages/merchant/pages/merchant_detail/merchant_detail_page.dart b/lib/presentation/pages/merchant/pages/merchant_detail/merchant_detail_page.dart index a059fe1..313a148 100644 --- a/lib/presentation/pages/merchant/pages/merchant_detail/merchant_detail_page.dart +++ b/lib/presentation/pages/merchant/pages/merchant_detail/merchant_detail_page.dart @@ -1,7 +1,7 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import '../../../../../common/theme/theme.dart'; -import '../../merchant_page.dart'; +import '../../../../../sample/sample_data.dart'; // Models class ProductCategory { @@ -295,9 +295,9 @@ class _MerchantDetailPageState extends State { ], ), child: Center( - child: Text( - _getCategoryIcon(widget.merchant.category), - style: TextStyle(fontSize: 36), + child: ClipRRect( + borderRadius: BorderRadius.circular(12), + child: Image.asset(widget.merchant.imageUrl), ), ), ), @@ -596,29 +596,6 @@ class _MerchantDetailPageState extends State { ), ); } - - 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 diff --git a/lib/presentation/pages/merchant/widgets/merchant_card.dart b/lib/presentation/pages/merchant/widgets/merchant_card.dart index a0ff3c2..e528436 100644 --- a/lib/presentation/pages/merchant/widgets/merchant_card.dart +++ b/lib/presentation/pages/merchant/widgets/merchant_card.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import '../../../../common/theme/theme.dart'; +import '../../../../sample/sample_data.dart'; import '../../../components/image/image.dart'; -import '../merchant_page.dart'; class MerchantCard extends StatelessWidget { final MerchantModel merchant; @@ -44,35 +44,44 @@ class MerchantCard extends StatelessWidget { topLeft: Radius.circular(8), topRight: Radius.circular(8), ), - child: Image.network( - merchant.imageUrl, - width: double.infinity, - fit: BoxFit.cover, - loadingBuilder: (context, child, loadingProgress) { - if (loadingProgress == null) return child; - return Center( - child: SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - strokeWidth: 2, - color: AppColor.primary, - value: loadingProgress.expectedTotalBytes != null - ? loadingProgress.cumulativeBytesLoaded / - loadingProgress.expectedTotalBytes! - : null, - ), + child: merchant.imageUrl.startsWith('assets') + ? Image.asset( + merchant.imageUrl, + fit: BoxFit.fill, + errorBuilder: (context, error, stackTrace) { + return ImagePlaceholder(width: 60, height: 60); + }, + ) + : Image.network( + merchant.imageUrl, + width: double.infinity, + fit: BoxFit.cover, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) return child; + return Center( + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + color: AppColor.primary, + value: + loadingProgress.expectedTotalBytes != null + ? loadingProgress.cumulativeBytesLoaded / + loadingProgress.expectedTotalBytes! + : null, + ), + ), + ); + }, + errorBuilder: (context, error, stackTrace) { + return ImagePlaceholder( + width: double.infinity, + height: 100, + showBorderRadius: false, + ); + }, ), - ); - }, - errorBuilder: (context, error, stackTrace) { - return ImagePlaceholder( - width: double.infinity, - height: 100, - showBorderRadius: false, - ); - }, - ), ), ), const SizedBox(height: 10), diff --git a/lib/presentation/router/app_router.gr.dart b/lib/presentation/router/app_router.gr.dart index 4da7aae..6417177 100644 --- a/lib/presentation/router/app_router.gr.dart +++ b/lib/presentation/router/app_router.gr.dart @@ -49,6 +49,7 @@ import 'package:enaklo/presentation/pages/reward/reward_page.dart' as _i21; import 'package:enaklo/presentation/pages/splash/splash_page.dart' as _i22; import 'package:enaklo/presentation/pages/voucher/voucher_detail/voucher_detail_page.dart' as _i23; +import 'package:enaklo/sample/sample_data.dart' as _i27; import 'package:flutter/material.dart' as _i26; /// generated route for @@ -173,7 +174,7 @@ class MainRoute extends _i25.PageRouteInfo { class MerchantDetailRoute extends _i25.PageRouteInfo { MerchantDetailRoute({ _i26.Key? key, - required _i8.MerchantModel merchant, + required _i27.MerchantModel merchant, List<_i25.PageRouteInfo>? children, }) : super( MerchantDetailRoute.name, @@ -197,7 +198,7 @@ class MerchantDetailRouteArgs { final _i26.Key? key; - final _i8.MerchantModel merchant; + final _i27.MerchantModel merchant; @override String toString() { diff --git a/lib/sample/sample_data.dart b/lib/sample/sample_data.dart new file mode 100644 index 0000000..bba889e --- /dev/null +++ b/lib/sample/sample_data.dart @@ -0,0 +1,54 @@ +import '../presentation/components/assets/assets.gen.dart'; + +class MerchantModel { + final String id; + final String name; + final String category; + final double rating; + final bool isOpen; + final String imageUrl; + + MerchantModel({ + required this.id, + required this.name, + required this.category, + required this.rating, + required this.isOpen, + required this.imageUrl, + }); +} + +List merchants = [ + MerchantModel( + id: 'hsjdhaj12', + name: 'Bakso 343', + category: 'Restaurant', + rating: 5, + isOpen: true, + imageUrl: Assets.images.bakso343.path, + ), + MerchantModel( + id: 'ahjs7812', + name: 'Tumulu Coffee', + category: 'Coffe Shop', + rating: 5, + isOpen: true, + imageUrl: Assets.images.tumulu.path, + ), + MerchantModel( + id: 'ahjs7812', + name: 'Ramenmulu', + category: 'Ramen', + rating: 5, + isOpen: true, + imageUrl: Assets.images.ramenmulu.path, + ), + MerchantModel( + id: '178271bjas', + name: 'Woku Pedas', + category: 'Restaurant', + rating: 5, + isOpen: true, + imageUrl: Assets.images.woku.path, + ), +];