update icon

This commit is contained in:
Phuoc Nguyen
2025-11-14 18:02:37 +07:00
parent aae3c9d080
commit b5f90c364d
54 changed files with 534 additions and 245 deletions

View File

@@ -0,0 +1,227 @@
# FontAwesome Icon Migration Guide
## Package Added
```yaml
font_awesome_flutter: ^10.7.0
```
## Import Statement
```dart
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
```
## Icon Mapping Reference
### Navigation Icons
| Material Icon | FontAwesome Icon | Usage |
|---------------|------------------|-------|
| `Icons.arrow_back` | `FontAwesomeIcons.arrowLeft` | Back buttons |
| `Icons.arrow_forward` | `FontAwesomeIcons.arrowRight` | Forward navigation |
| `Icons.home` | `FontAwesomeIcons.house` | Home button |
| `Icons.menu` | `FontAwesomeIcons.bars` | Menu/hamburger |
| `Icons.close` | `FontAwesomeIcons.xmark` | Close buttons |
### Shopping & Cart Icons
| Material Icon | FontAwesome Icon | Usage |
|---------------|------------------|-------|
| `Icons.shopping_cart` | `FontAwesomeIcons.cartShopping` | Shopping cart |
| `Icons.shopping_cart_outlined` | `FontAwesomeIcons.cartShopping` | Cart outline |
| `Icons.shopping_bag` | `FontAwesomeIcons.bagShopping` | Shopping bag |
| `Icons.shopping_bag_outlined` | `FontAwesomeIcons.bagShopping` | Bag outline |
| `Icons.add_shopping_cart` | `FontAwesomeIcons.cartPlus` | Add to cart |
### Action Icons
| Material Icon | FontAwesome Icon | Usage |
|---------------|------------------|-------|
| `Icons.add` | `FontAwesomeIcons.plus` | Add/increment |
| `Icons.remove` | `FontAwesomeIcons.minus` | Remove/decrement |
| `Icons.delete` | `FontAwesomeIcons.trash` | Delete |
| `Icons.delete_outline` | `FontAwesomeIcons.trashCan` | Delete outline |
| `Icons.edit` | `FontAwesomeIcons.pen` | Edit |
| `Icons.check` | `FontAwesomeIcons.check` | Checkmark |
| `Icons.check_circle` | `FontAwesomeIcons.circleCheck` | Check circle |
| `Icons.refresh` | `FontAwesomeIcons.arrowsRotate` | Refresh |
### Status & Feedback Icons
| Material Icon | FontAwesome Icon | Usage |
|---------------|------------------|-------|
| `Icons.error` | `FontAwesomeIcons.circleXmark` | Error |
| `Icons.error_outline` | `FontAwesomeIcons.circleExclamation` | Error outline |
| `Icons.warning` | `FontAwesomeIcons.triangleExclamation` | Warning |
| `Icons.info` | `FontAwesomeIcons.circleInfo` | Info |
| `Icons.info_outline` | `FontAwesomeIcons.circleInfo` | Info outline |
### UI Elements
| Material Icon | FontAwesome Icon | Usage |
|---------------|------------------|-------|
| `Icons.search` | `FontAwesomeIcons.magnifyingGlass` | Search |
| `Icons.filter_list` | `FontAwesomeIcons.filter` | Filter |
| `Icons.sort` | `FontAwesomeIcons.arrowDownAZ` | Sort |
| `Icons.more_vert` | `FontAwesomeIcons.ellipsisVertical` | More options |
| `Icons.more_horiz` | `FontAwesomeIcons.ellipsis` | More horizontal |
### Calendar & Time
| Material Icon | FontAwesome Icon | Usage |
|---------------|------------------|-------|
| `Icons.calendar_today` | `FontAwesomeIcons.calendar` | Calendar |
| `Icons.date_range` | `FontAwesomeIcons.calendarDays` | Date range |
| `Icons.access_time` | `FontAwesomeIcons.clock` | Time |
### Payment Icons
| Material Icon | FontAwesome Icon | Usage |
|---------------|------------------|-------|
| `Icons.payment` | `FontAwesomeIcons.creditCard` | Credit card |
| `Icons.payments` | `FontAwesomeIcons.creditCard` | Payments |
| `Icons.payments_outlined` | `FontAwesomeIcons.creditCard` | Payment outline |
| `Icons.account_balance` | `FontAwesomeIcons.buildingColumns` | Bank |
| `Icons.account_balance_outlined` | `FontAwesomeIcons.buildingColumns` | Bank outline |
| `Icons.account_balance_wallet` | `FontAwesomeIcons.wallet` | Wallet |
### Media & Images
| Material Icon | FontAwesome Icon | Usage |
|---------------|------------------|-------|
| `Icons.image` | `FontAwesomeIcons.image` | Image |
| `Icons.image_not_supported` | `FontAwesomeIcons.imageSlash` | No image |
| `Icons.photo_camera` | `FontAwesomeIcons.camera` | Camera |
| `Icons.photo_library` | `FontAwesomeIcons.images` | Gallery |
### User & Profile
| Material Icon | FontAwesome Icon | Usage |
|---------------|------------------|-------|
| `Icons.person` | `FontAwesomeIcons.user` | User |
| `Icons.person_outline` | `FontAwesomeIcons.user` | User outline |
| `Icons.account_circle` | `FontAwesomeIcons.circleUser` | Account |
### Communication
| Material Icon | FontAwesome Icon | Usage |
|---------------|------------------|-------|
| `Icons.chat` | `FontAwesomeIcons.message` | Chat |
| `Icons.chat_bubble` | `FontAwesomeIcons.commentDots` | Chat bubble |
| `Icons.notifications` | `FontAwesomeIcons.bell` | Notifications |
| `Icons.phone` | `FontAwesomeIcons.phone` | Phone |
| `Icons.email` | `FontAwesomeIcons.envelope` | Email |
## Usage Examples
### Before (Material Icons)
```dart
Icon(Icons.shopping_cart, size: 24, color: Colors.blue)
Icon(Icons.add, size: 16)
IconButton(
icon: Icon(Icons.delete_outline),
onPressed: () {},
)
```
### After (FontAwesome)
```dart
FaIcon(FontAwesomeIcons.cartShopping, size: 24, color: Colors.blue)
FaIcon(FontAwesomeIcons.plus, size: 16)
IconButton(
icon: FaIcon(FontAwesomeIcons.trashCan),
onPressed: () {},
)
```
## Size Guidelines
FontAwesome icons tend to be slightly larger than Material icons at the same size. Recommended adjustments:
| Material Size | FontAwesome Size | Notes |
|---------------|------------------|-------|
| 24 (default) | 20-22 | Standard icons |
| 20 | 18 | Small icons |
| 16 | 14-15 | Tiny icons |
| 48 | 40-44 | Large icons |
| 64 | 56-60 | Extra large |
## Color Usage
FontAwesome icons use the same color properties:
```dart
// Both work the same
Icon(Icons.add, color: AppColors.primaryBlue)
FaIcon(FontAwesomeIcons.plus, color: AppColors.primaryBlue)
```
## Common Issues & Solutions
### Issue 1: Icon Size Mismatch
**Problem**: FontAwesome icons appear larger than expected
**Solution**: Reduce size by 2-4 pixels
```dart
// Before
Icon(Icons.add, size: 24)
// After
FaIcon(FontAwesomeIcons.plus, size: 20)
```
### Issue 2: Icon Alignment
**Problem**: Icons not centered properly
**Solution**: Use `IconTheme` or wrap in `SizedBox`
```dart
SizedBox(
width: 24,
height: 24,
child: FaIcon(FontAwesomeIcons.plus, size: 18),
)
```
### Issue 3: Icon Not Found
**Problem**: Icon name doesn't match
**Solution**: Check FontAwesome documentation or use search
```dart
// Use camelCase, not snake_case
// ❌ FontAwesomeIcons.shopping_cart
// ✅ FontAwesomeIcons.cartShopping
```
## Migration Checklist
- [x] Add `font_awesome_flutter` to pubspec.yaml
- [x] Run `flutter pub get`
- [ ] Update all `Icons.*` to `FontAwesomeIcons.*`
- [ ] Replace `Icon()` with `FaIcon()`
- [ ] Adjust icon sizes as needed
- [ ] Test visual appearance
- [ ] Update documentation
## Cart Feature Icon Updates
### Files to Update
1. `lib/features/cart/presentation/pages/cart_page.dart`
2. `lib/features/cart/presentation/pages/checkout_page.dart`
3. `lib/features/cart/presentation/widgets/cart_item_widget.dart`
4. `lib/features/cart/presentation/widgets/payment_method_section.dart`
5. `lib/features/cart/presentation/widgets/checkout_date_picker_field.dart`
### Specific Replacements
#### cart_page.dart
- `Icons.arrow_back``FontAwesomeIcons.arrowLeft`
- `Icons.delete_outline``FontAwesomeIcons.trashCan`
- `Icons.error_outline``FontAwesomeIcons.circleExclamation`
- `Icons.refresh``FontAwesomeIcons.arrowsRotate`
- `Icons.shopping_cart_outlined``FontAwesomeIcons.cartShopping`
- `Icons.shopping_bag_outlined``FontAwesomeIcons.bagShopping`
- `Icons.check``FontAwesomeIcons.check`
#### cart_item_widget.dart
- `Icons.image_not_supported``FontAwesomeIcons.imageSlash`
- `Icons.remove``FontAwesomeIcons.minus`
- `Icons.add``FontAwesomeIcons.plus`
- `Icons.check``FontAwesomeIcons.check`
#### payment_method_section.dart
- `Icons.account_balance_outlined``FontAwesomeIcons.buildingColumns`
- `Icons.payments_outlined``FontAwesomeIcons.creditCard`
#### checkout_date_picker_field.dart
- `Icons.calendar_today``FontAwesomeIcons.calendar`
## Resources
- [FontAwesome Flutter Package](https://pub.dev/packages/font_awesome_flutter)
- [FontAwesome Icon Gallery](https://fontawesome.com/icons)
- [FontAwesome Flutter Gallery](https://github.com/fluttercommunity/font_awesome_flutter/blob/master/GALLERY.md)

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/theme/colors.dart';
@@ -58,17 +59,17 @@ class CustomBottomNavBar extends StatelessWidget {
selectedFontSize: 12,
unselectedFontSize: 12,
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(icon: FaIcon(FontAwesomeIcons.house, size: 20), label: 'Home'),
BottomNavigationBarItem(
icon: Icon(Icons.shopping_bag),
icon: FaIcon(FontAwesomeIcons.bagShopping, size: 20),
label: 'Products',
),
BottomNavigationBarItem(
icon: Icon(Icons.card_membership),
icon: FaIcon(FontAwesomeIcons.gift, size: 20),
label: 'Loyalty',
),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Account'),
BottomNavigationBarItem(icon: Icon(Icons.menu), label: 'More'),
BottomNavigationBarItem(icon: FaIcon(FontAwesomeIcons.user, size: 20), label: 'Account'),
BottomNavigationBarItem(icon: FaIcon(FontAwesomeIcons.bars, size: 20), label: 'More'),
],
);
}

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/theme/colors.dart';
@@ -54,7 +55,7 @@ class EmptyState extends StatelessWidget {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: iconSize, color: AppColors.grey500),
FaIcon(icon, size: iconSize, color: AppColors.grey500),
const SizedBox(height: 16),
Text(
title,

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/theme/colors.dart';
@@ -43,8 +44,8 @@ class CustomErrorWidget extends StatelessWidget {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
icon ?? Icons.error_outline,
FaIcon(
icon ?? FontAwesomeIcons.circleExclamation,
size: iconSize,
color: AppColors.danger,
),
@@ -62,7 +63,7 @@ class CustomErrorWidget extends StatelessWidget {
const SizedBox(height: 24),
ElevatedButton.icon(
onPressed: onRetry,
icon: const Icon(Icons.refresh),
icon: const FaIcon(FontAwesomeIcons.arrowsRotate, size: 16),
label: const Text('Retry'),
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryBlue,

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/theme/colors.dart';
@@ -43,10 +44,10 @@ class ChatFloatingButton extends StatelessWidget {
onPressed: onPressed,
backgroundColor: AppColors.accentCyan,
elevation: 6,
child: const Icon(
Icons.chat_bubble_outline,
child: const FaIcon(
FontAwesomeIcons.message,
color: Colors.white,
size: 24,
size: 22,
),
),
if (unreadCount != null && unreadCount! > 0)

View File

@@ -5,6 +5,7 @@
library;
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/router/app_router.dart';
@@ -162,7 +163,7 @@ class _BusinessUnitSelectionPageState extends State<BusinessUnitSelectionPage> {
backgroundColor: AppColors.white,
elevation: AppBarSpecs.elevation,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
onPressed: () => context.pop(),
),
title: const Text(
@@ -176,7 +177,7 @@ class _BusinessUnitSelectionPageState extends State<BusinessUnitSelectionPage> {
centerTitle: false,
actions: [
IconButton(
icon: const Icon(Icons.info_outline, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.circleInfo, color: Colors.black, size: 20),
onPressed: _showInfoDialog,
),
const SizedBox(width: AppSpacing.sm),
@@ -331,7 +332,7 @@ class _BusinessUnitSelectionPageState extends State<BusinessUnitSelectionPage> {
borderRadius: BorderRadius.circular(8),
),
child: Icon(
Icons.business,
FontAwesomeIcons.building,
color: isSelected
? AppColors.primaryBlue
: AppColors.grey500,
@@ -387,7 +388,7 @@ class _BusinessUnitSelectionPageState extends State<BusinessUnitSelectionPage> {
),
child: isSelected
? const Icon(
Icons.circle,
FontAwesomeIcons.solidCircle,
size: 10,
color: AppColors.white,
)

View File

@@ -6,6 +6,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/theme/colors.dart';
@@ -147,7 +148,7 @@ class _ForgotPasswordPageState extends ConsumerState<ForgotPasswordPage> {
),
centerTitle: false,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
onPressed: () => context.pop(),
),
actions: const [
@@ -205,7 +206,7 @@ class _ForgotPasswordPageState extends ConsumerState<ForgotPasswordPage> {
shape: BoxShape.circle,
),
child: const Icon(
Icons.lock_reset,
FontAwesomeIcons.key,
size: 50,
color: AppColors.primaryBlue,
),
@@ -349,7 +350,7 @@ class _ForgotPasswordPageState extends ConsumerState<ForgotPasswordPage> {
child: TextButton.icon(
onPressed: _showSupport,
icon: const Icon(
Icons.headset_mic,
FontAwesomeIcons.headset,
size: AppIconSize.sm,
color: AppColors.primaryBlue,
),

View File

@@ -6,6 +6,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/router/app_router.dart';
@@ -329,13 +330,13 @@ class _LoginPageState extends ConsumerState<LoginPage> {
color: AppColors.grey500,
),
prefixIcon: const Icon(
Icons.lock,
FontAwesomeIcons.lock,
color: AppColors.primaryBlue,
size: AppIconSize.md,
),
suffixIcon: IconButton(
icon: Icon(
isPasswordVisible ? Icons.visibility : Icons.visibility_off,
isPasswordVisible ? FontAwesomeIcons.eye : FontAwesomeIcons.eyeSlash,
color: AppColors.grey500,
size: AppIconSize.md,
),
@@ -538,7 +539,7 @@ class _LoginPageState extends ConsumerState<LoginPage> {
child: TextButton.icon(
onPressed: _showSupport,
icon: const Icon(
Icons.headset_mic,
FontAwesomeIcons.headset,
size: AppIconSize.sm,
color: AppColors.primaryBlue,
),

View File

@@ -9,6 +9,7 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:worker/core/constants/ui_constants.dart';
@@ -242,7 +243,7 @@ class _OtpVerificationPageState extends ConsumerState<OtpVerificationPage> {
backgroundColor: AppColors.white,
elevation: AppBarSpecs.elevation,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
onPressed: () => context.pop(),
),
title: const Text(
@@ -280,7 +281,7 @@ class _OtpVerificationPageState extends ConsumerState<OtpVerificationPage> {
shape: BoxShape.circle,
),
child: const Icon(
Icons.shield_outlined,
FontAwesomeIcons.shieldHalved,
size: 36,
color: AppColors.white,
),

View File

@@ -9,6 +9,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:image_picker/image_picker.dart';
@@ -174,12 +175,12 @@ class _RegisterPageState extends ConsumerState<RegisterPage> {
child: Wrap(
children: [
ListTile(
leading: const Icon(Icons.camera_alt),
leading: const FaIcon(FontAwesomeIcons.camera, size: 20),
title: const Text('Chụp ảnh'),
onTap: () => Navigator.pop(context, ImageSource.camera),
),
ListTile(
leading: const Icon(Icons.photo_library),
leading: const FaIcon(FontAwesomeIcons.images, size: 20),
title: const Text('Chọn từ thư viện'),
onTap: () => Navigator.pop(context, ImageSource.gallery),
),
@@ -392,7 +393,7 @@ class _RegisterPageState extends ConsumerState<RegisterPage> {
backgroundColor: AppColors.white,
elevation: AppBarSpecs.elevation,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
onPressed: () => context.pop(),
),
title: const Text(
@@ -470,7 +471,7 @@ class _RegisterPageState extends ConsumerState<RegisterPage> {
textInputAction: TextInputAction.next,
decoration: _buildInputDecoration(
hintText: 'Nhập họ và tên',
prefixIcon: Icons.person,
prefixIcon: FontAwesomeIcons.user,
),
validator: (value) => Validators.minLength(
value,
@@ -498,7 +499,7 @@ class _RegisterPageState extends ConsumerState<RegisterPage> {
textInputAction: TextInputAction.next,
decoration: _buildInputDecoration(
hintText: 'Nhập email',
prefixIcon: Icons.email,
prefixIcon: FontAwesomeIcons.envelope,
),
validator: Validators.email,
),
@@ -513,12 +514,12 @@ class _RegisterPageState extends ConsumerState<RegisterPage> {
textInputAction: TextInputAction.done,
decoration: _buildInputDecoration(
hintText: 'Tạo mật khẩu mới',
prefixIcon: Icons.lock,
prefixIcon: FontAwesomeIcons.lock,
suffixIcon: IconButton(
icon: Icon(
_passwordVisible
? Icons.visibility
: Icons.visibility_off,
? FontAwesomeIcons.eye
: FontAwesomeIcons.eyeSlash,
color: AppColors.grey500,
),
onPressed: () {
@@ -560,7 +561,7 @@ class _RegisterPageState extends ConsumerState<RegisterPage> {
textInputAction: TextInputAction.next,
decoration: _buildInputDecoration(
hintText: 'Nhập tên công ty (không bắt buộc)',
prefixIcon: Icons.business,
prefixIcon: FontAwesomeIcons.building,
),
),
const SizedBox(height: AppSpacing.md),
@@ -761,7 +762,7 @@ class _RegisterPageState extends ConsumerState<RegisterPage> {
value: _selectedRole,
decoration: _buildInputDecoration(
hintText: 'Chọn vai trò',
prefixIcon: Icons.work,
prefixIcon: FontAwesomeIcons.briefcase,
),
items: groups
.map(

View File

@@ -6,6 +6,7 @@ library;
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/theme/colors.dart';
@@ -154,7 +155,7 @@ class FileUploadCard extends StatelessWidget {
height: 50,
color: AppColors.grey100,
child: const Icon(
Icons.broken_image,
FontAwesomeIcons.image,
color: AppColors.grey500,
size: 24,
),
@@ -203,7 +204,7 @@ class FileUploadCard extends StatelessWidget {
// Remove button
IconButton(
icon: const Icon(Icons.close, color: AppColors.danger, size: 20),
icon: const FaIcon(FontAwesomeIcons.xmark, color: AppColors.danger, size: 18),
onPressed: onRemove,
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),

View File

@@ -6,6 +6,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/theme/colors.dart';
@@ -93,7 +94,7 @@ class PhoneInputField extends StatelessWidget {
color: AppColors.grey500,
),
prefixIcon: const Icon(
Icons.phone,
FontAwesomeIcons.phone,
color: AppColors.primaryBlue,
size: AppIconSize.md,
),

View File

@@ -4,6 +4,7 @@
library;
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/theme/colors.dart';
@@ -62,7 +63,7 @@ class RoleDropdown extends StatelessWidget {
color: AppColors.grey500,
),
prefixIcon: const Icon(
Icons.work,
FontAwesomeIcons.briefcase,
color: AppColors.primaryBlue,
size: AppIconSize.md,
),
@@ -104,7 +105,7 @@ class RoleDropdown extends StatelessWidget {
],
onChanged: onChanged,
validator: validator,
icon: const Icon(Icons.arrow_drop_down, color: AppColors.grey500),
icon: const FaIcon(FontAwesomeIcons.chevronDown, color: AppColors.grey500, size: 16),
dropdownColor: AppColors.white,
style: const TextStyle(
fontSize: InputFieldSpecs.fontSize,

View File

@@ -6,6 +6,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:worker/core/constants/ui_constants.dart';
@@ -66,7 +67,7 @@ class _CartPageState extends ConsumerState<CartPage> {
backgroundColor: const Color(0xFFF4F6F8),
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
onPressed: () => context.pop(),
),
title: Text(
@@ -81,7 +82,7 @@ class _CartPageState extends ConsumerState<CartPage> {
if (cartState.isNotEmpty)
IconButton(
icon: Icon(
Icons.delete_outline,
FontAwesomeIcons.trashCan,
color: hasSelection ? AppColors.danger : AppColors.grey500,
),
onPressed: hasSelection
@@ -326,7 +327,7 @@ class _CartPageState extends ConsumerState<CartPage> {
color: AppColors.danger.withValues(alpha: 0.1),
child: Row(
children: [
const Icon(Icons.error_outline, color: AppColors.danger, size: 20),
const FaIcon(FontAwesomeIcons.circleExclamation, color: AppColors.danger, size: 18),
const SizedBox(width: 8),
Expanded(
child: Text(
@@ -345,7 +346,7 @@ class _CartPageState extends ConsumerState<CartPage> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error_outline, size: 64, color: AppColors.danger),
const FaIcon(FontAwesomeIcons.circleExclamation, size: 56, color: AppColors.danger),
const SizedBox(height: 16),
const Text(
'Không thể tải giỏ hàng',
@@ -365,7 +366,7 @@ class _CartPageState extends ConsumerState<CartPage> {
onPressed: () {
ref.read(cartProvider.notifier).initialize();
},
icon: const Icon(Icons.refresh),
icon: const FaIcon(FontAwesomeIcons.arrowsRotate, size: 20),
label: const Text('Thử lại'),
),
],
@@ -380,7 +381,7 @@ class _CartPageState extends ConsumerState<CartPage> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.shopping_cart_outlined,
FontAwesomeIcons.cartShopping,
size: 80,
color: AppColors.grey500.withValues(alpha: 0.5),
),
@@ -399,7 +400,7 @@ class _CartPageState extends ConsumerState<CartPage> {
const SizedBox(height: 24),
ElevatedButton.icon(
onPressed: () => context.go(RouteNames.products),
icon: const Icon(Icons.shopping_bag_outlined),
icon: const FaIcon(FontAwesomeIcons.bagShopping, size: 20),
label: const Text('Xem sản phẩm'),
),
],
@@ -472,7 +473,7 @@ class _CustomCheckbox extends StatelessWidget {
),
child: value
? const Icon(
Icons.check,
FontAwesomeIcons.check,
size: 16,
color: AppColors.white,
)

View File

@@ -12,6 +12,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -95,7 +96,7 @@ class CheckoutPage extends HookConsumerWidget {
backgroundColor: Colors.white,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
onPressed: () => context.pop(),
),
title: const Text(

View File

@@ -6,6 +6,7 @@ library;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
import 'package:worker/core/theme/colors.dart';
import 'package:worker/core/theme/typography.dart';
@@ -135,8 +136,8 @@ class _CartItemWidgetState extends ConsumerState<CartItemWidget> {
width: 100,
height: 100,
color: AppColors.grey100,
child: const Icon(
Icons.image_not_supported,
child: const FaIcon(
FontAwesomeIcons.image,
color: AppColors.grey500,
size: 32,
),
@@ -181,7 +182,7 @@ class _CartItemWidgetState extends ConsumerState<CartItemWidget> {
children: [
// Decrease button
_QuantityButton(
icon: Icons.remove,
icon: FontAwesomeIcons.minus,
onPressed: () {
ref
.read(cartProvider.notifier)
@@ -239,7 +240,7 @@ class _CartItemWidgetState extends ConsumerState<CartItemWidget> {
// Increase button
_QuantityButton(
icon: Icons.add,
icon: FontAwesomeIcons.plus,
onPressed: () {
ref
.read(cartProvider.notifier)
@@ -319,7 +320,7 @@ class _CustomCheckbox extends StatelessWidget {
),
child: value
? const Icon(
Icons.check,
FontAwesomeIcons.check,
size: 14,
color: AppColors.white,
)

View File

@@ -5,6 +5,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/theme/colors.dart';
@@ -69,7 +70,7 @@ class CheckoutDatePickerField extends HookWidget {
),
),
const Icon(
Icons.calendar_today,
FontAwesomeIcons.calendar,
size: 20,
color: AppColors.grey500,
),

View File

@@ -7,6 +7,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/theme/colors.dart';
@@ -66,7 +67,7 @@ class PaymentMethodSection extends HookWidget {
),
const SizedBox(width: 12),
const Icon(
Icons.account_balance_outlined,
FontAwesomeIcons.buildingColumns,
color: AppColors.grey500,
size: 24,
),
@@ -117,7 +118,7 @@ class PaymentMethodSection extends HookWidget {
),
const SizedBox(width: 12),
const Icon(
Icons.payments_outlined,
FontAwesomeIcons.creditCard,
color: AppColors.grey500,
size: 24,
),

View File

@@ -6,6 +6,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:shimmer/shimmer.dart';
import 'package:worker/core/constants/ui_constants.dart';
@@ -82,7 +83,7 @@ class FavoritesPage extends ConsumerWidget {
backgroundColor: const Color(0xFFF4F6F8),
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
onPressed: () => context.pop(),
),
title: const Text('Yêu thích', style: TextStyle(color: Colors.black)),
@@ -110,7 +111,7 @@ class FavoritesPage extends ConsumerWidget {
// Clear all button
if (favoriteCount > 0)
IconButton(
icon: const Icon(Icons.delete_outline, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.trashCan, color: Colors.black, size: 20),
tooltip: 'Xóa tất cả',
onPressed: () => _showClearAllDialog(context, ref, favoriteCount),
),
@@ -165,8 +166,8 @@ class _EmptyState extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Large icon
Icon(
Icons.favorite_border,
FaIcon(
FontAwesomeIcons.heart,
size: 80.0,
color: AppColors.grey500.withValues(alpha: 0.5),
),
@@ -360,8 +361,8 @@ class _ErrorState extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Error icon
Icon(
Icons.error_outline,
FaIcon(
FontAwesomeIcons.circleExclamation,
size: 80.0,
color: AppColors.danger.withValues(alpha: 0.7),
),
@@ -406,7 +407,7 @@ class _ErrorState extends StatelessWidget {
borderRadius: BorderRadius.circular(AppRadius.button),
),
),
icon: const Icon(Icons.refresh),
icon: const FaIcon(FontAwesomeIcons.arrowsRotate, size: 18),
label: const Text(
'Thử lại',
style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.w600),

View File

@@ -7,6 +7,7 @@ library;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:shimmer/shimmer.dart';
@@ -106,8 +107,8 @@ class FavoriteProductCard extends ConsumerWidget {
),
errorWidget: (context, url, error) => Container(
color: AppColors.grey100,
child: const Icon(
Icons.image_not_supported,
child: const FaIcon(
FontAwesomeIcons.image,
size: 48.0,
color: AppColors.grey500,
),
@@ -132,10 +133,10 @@ class FavoriteProductCard extends ConsumerWidget {
],
),
child: IconButton(
icon: const Icon(
Icons.favorite,
icon: const FaIcon(
FontAwesomeIcons.solidHeart,
color: AppColors.danger,
size: 20.0,
size: 18.0,
),
padding: const EdgeInsets.all(AppSpacing.sm),
constraints: const BoxConstraints(

View File

@@ -6,6 +6,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:worker/core/router/app_router.dart';
import 'package:worker/core/theme/colors.dart';
@@ -90,8 +91,8 @@ class _HomePageState extends ConsumerState<HomePage> {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
Icons.error_outline,
const FaIcon(
FontAwesomeIcons.circleExclamation,
color: AppColors.danger,
size: 48,
),
@@ -149,18 +150,18 @@ class _HomePageState extends ConsumerState<HomePage> {
title: 'Sản phẩm & Giỏ hàng',
actions: [
QuickAction(
icon: Icons.grid_view,
icon: FontAwesomeIcons.grip,
label: 'Sản phẩm',
onTap: () => context.pushNamed(RouteNames.products),
),
QuickAction(
icon: Icons.shopping_cart,
icon: FontAwesomeIcons.cartShopping,
label: 'Giỏ hàng',
badge: cartItemCount > 0 ? '$cartItemCount' : null,
onTap: () => context.push(RouteNames.cart),
),
QuickAction(
icon: Icons.favorite,
icon: FontAwesomeIcons.heart,
label: 'Yêu thích',
onTap: () => context.push(RouteNames.favorites),
),
@@ -172,17 +173,17 @@ class _HomePageState extends ConsumerState<HomePage> {
title: 'Đơn hàng & thanh toán',
actions: [
QuickAction(
icon: Icons.description,
icon: FontAwesomeIcons.fileLines,
label: 'Chính sách giá',
onTap: () => context.push(RouteNames.pricePolicy),
),
QuickAction(
icon: Icons.inventory_2,
icon: FontAwesomeIcons.boxesStacked,
label: 'Đơn hàng',
onTap: () => context.push(RouteNames.orders),
),
QuickAction(
icon: Icons.receipt_long,
icon: FontAwesomeIcons.receipt,
label: 'Thanh toán',
onTap: () => context.push(RouteNames.payments),
),
@@ -194,18 +195,18 @@ class _HomePageState extends ConsumerState<HomePage> {
title: 'Khách hàng thân thiết',
actions: [
QuickAction(
icon: Icons.add_circle_outline,
icon: FontAwesomeIcons.circlePlus,
label: 'Ghi nhận điểm',
onTap: () =>
_showComingSoon(context, 'Ghi nhận điểm', l10n),
),
QuickAction(
icon: Icons.card_giftcard,
icon: FontAwesomeIcons.gift,
label: 'Đổi quà',
onTap: () => context.push('/loyalty/rewards'),
),
QuickAction(
icon: Icons.history,
icon: FontAwesomeIcons.clockRotateLeft,
label: 'Lịch sử điểm',
onTap: () => context.push(RouteNames.pointsHistory),
),
@@ -217,12 +218,12 @@ class _HomePageState extends ConsumerState<HomePage> {
title: 'Nhà mẫu, dự án & tin tức',
actions: [
QuickAction(
icon: Icons.home_work,
icon: FontAwesomeIcons.houseCircleCheck,
label: 'Nhà mẫu',
onTap: () => context.push(RouteNames.modelHouses),
),
QuickAction(
icon: Icons.business,
icon: FontAwesomeIcons.building,
label: 'Đăng ký dự án',
onTap: () =>
_showComingSoon(context, 'Đăng ký dự án', l10n),

View File

@@ -6,6 +6,7 @@ library;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:worker/core/router/app_router.dart';
import 'package:worker/core/theme/colors.dart';
@@ -127,8 +128,8 @@ class _PromotionCard extends StatelessWidget {
errorWidget: (context, url, error) => Container(
height: 140,
color: AppColors.grey100,
child: const Icon(
Icons.image_not_supported,
child: const FaIcon(
FontAwesomeIcons.image,
size: 48,
color: AppColors.grey500,
),

View File

@@ -5,6 +5,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:worker/core/constants/ui_constants.dart';
@@ -282,37 +283,37 @@ class LoyaltyPage extends ConsumerWidget {
List<Widget> _buildLoyaltyMenu(BuildContext context) {
final menuItems = [
{
'icon': Icons.card_giftcard,
'icon': FontAwesomeIcons.gift,
'title': 'Đổi quà tặng',
'subtitle': 'Sử dụng điểm để đổi quà hấp dẫn',
'route': '/loyalty/rewards',
},
{
'icon': Icons.add_circle_outline,
'icon': FontAwesomeIcons.circlePlus,
'title': 'Ghi nhận điểm',
'subtitle': 'Gửi hóa đơn để nhận điểm thưởng',
'route': null,
},
{
'icon': Icons.history,
'icon': FontAwesomeIcons.clockRotateLeft,
'title': 'Lịch sử điểm',
'subtitle': 'Xem chi tiết cộng/trừ điểm',
'route': '/loyalty/points-history',
},
{
'icon': Icons.person_add,
'icon': FontAwesomeIcons.userPlus,
'title': 'Giới thiệu bạn bè',
'subtitle': 'Nhận thưởng khi giới thiệu thành công',
'route': null,
},
{
'icon': Icons.inventory_2_outlined,
'icon': FontAwesomeIcons.boxOpen,
'title': 'Quà của tôi',
'subtitle': 'Xem voucher và quà tặng đã đổi',
'route': null,
},
{
'icon': Icons.diamond_outlined,
'icon': FontAwesomeIcons.gem,
'title': 'Quyền lợi hội viên',
'subtitle': 'Xem các ưu đãi dành cho hạng của bạn',
'route': null,
@@ -386,7 +387,7 @@ class LoyaltyPage extends ConsumerWidget {
// Arrow
const Icon(
Icons.chevron_right,
FontAwesomeIcons.chevronRight,
color: AppColors.grey500,
size: 20,
),
@@ -440,7 +441,7 @@ class LoyaltyPage extends ConsumerWidget {
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Icon(Icons.check_circle, size: 20, color: Color(0xFF4A00E0)),
const FaIcon(FontAwesomeIcons.solidCircleCheck, size: 18, color: Color(0xFF4A00E0)),
const SizedBox(width: 12),
Expanded(
child: Text(

View File

@@ -5,6 +5,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:worker/core/constants/ui_constants.dart';
@@ -32,7 +33,7 @@ class PointsHistoryPage extends ConsumerWidget {
backgroundColor: const Color(0xFFF4F6F8),
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
onPressed: () => context.pop(),
),
title: const Text(
@@ -101,7 +102,7 @@ class PointsHistoryPage extends ConsumerWidget {
color: AppColors.grey900,
),
),
Icon(Icons.filter_list, color: AppColors.primaryBlue, size: 20),
FaIcon(FontAwesomeIcons.sliders, color: AppColors.primaryBlue, size: 18),
],
),
const SizedBox(height: 8),
@@ -263,8 +264,8 @@ class PointsHistoryPage extends ConsumerWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.history,
FaIcon(
FontAwesomeIcons.clockRotateLeft,
size: 80,
color: AppColors.grey500.withValues(alpha: 0.5),
),
@@ -294,8 +295,8 @@ class PointsHistoryPage extends ConsumerWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.error_outline,
FaIcon(
FontAwesomeIcons.circleExclamation,
size: 80,
color: AppColors.danger.withValues(alpha: 0.7),
),

View File

@@ -5,6 +5,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:worker/core/constants/ui_constants.dart';
@@ -34,7 +35,7 @@ class RewardsPage extends ConsumerWidget {
backgroundColor: const Color(0xFFF4F6F8),
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
onPressed: () => context.pop(),
),
title: const Text(
@@ -47,7 +48,7 @@ class RewardsPage extends ConsumerWidget {
centerTitle: false,
actions: [
IconButton(
icon: const Icon(Icons.info_outline, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.circleInfo, color: Colors.black, size: 20),
onPressed: () => _showInfoDialog(context),
),
const SizedBox(width: AppSpacing.sm),
@@ -168,7 +169,7 @@ class RewardsPage extends ConsumerWidget {
children: [
const Padding(
padding: EdgeInsets.only(top: 6),
child: Icon(Icons.circle, size: 6, color: AppColors.grey500),
child: FaIcon(FontAwesomeIcons.solidCircle, size: 6, color: AppColors.grey500),
),
const SizedBox(width: 12),
Expanded(
@@ -299,8 +300,8 @@ class RewardsPage extends ConsumerWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.card_giftcard_outlined,
FaIcon(
FontAwesomeIcons.gift,
size: 64,
color: AppColors.grey500,
),
@@ -434,7 +435,7 @@ class RewardsPage extends ConsumerWidget {
SnackBar(
content: Row(
children: [
const Icon(Icons.check_circle, color: Colors.white),
const FaIcon(FontAwesomeIcons.solidCircleCheck, color: Colors.white, size: 20),
const SizedBox(width: 12),
Expanded(child: Text('Đổi quà "${gift.name}" thành công!')),
],

View File

@@ -5,6 +5,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
import 'package:worker/core/theme/colors.dart';
import 'package:worker/features/loyalty/presentation/providers/loyalty_points_provider.dart';
@@ -75,8 +76,8 @@ class PointsBalanceCard extends ConsumerWidget {
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.info_outline,
FaIcon(
FontAwesomeIcons.circleInfo,
size: 14,
color: Colors.white.withValues(alpha: 0.8),
),

View File

@@ -6,6 +6,7 @@ library;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
import 'package:worker/core/theme/colors.dart';
import 'package:worker/features/loyalty/domain/entities/gift_catalog.dart';
@@ -96,9 +97,9 @@ class RewardCard extends ConsumerWidget {
onPressed: hasEnoughPoints && gift.isAvailable
? onRedeem
: null,
icon: Icon(
Icons.card_giftcard,
size: 16,
icon: FaIcon(
FontAwesomeIcons.gift,
size: 14,
color: hasEnoughPoints && gift.isAvailable
? Colors.white
: AppColors.grey500,
@@ -155,8 +156,8 @@ class RewardCard extends ConsumerWidget {
),
errorWidget: (context, url, error) => Container(
color: AppColors.grey100,
child: const Icon(
Icons.card_giftcard,
child: const FaIcon(
FontAwesomeIcons.gift,
size: 48,
color: AppColors.grey500,
),
@@ -164,8 +165,8 @@ class RewardCard extends ConsumerWidget {
)
: Container(
color: AppColors.grey100,
child: const Icon(
Icons.card_giftcard,
child: const FaIcon(
FontAwesomeIcons.gift,
size: 48,
color: AppColors.grey500,
),

View File

@@ -9,6 +9,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:share_plus/share_plus.dart';
import 'package:worker/core/constants/api_constants.dart';
@@ -77,20 +78,21 @@ class _NewsDetailPageState extends ConsumerState<NewsDetailPage> {
),
centerTitle: false,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
onPressed: () => context.pop(),
),
actions: [
// Share button
IconButton(
icon: const Icon(Icons.share, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.shareNodes, color: Colors.black, size: 20),
onPressed: _onShareTap,
),
// Bookmark button
IconButton(
icon: Icon(
_isBookmarked ? Icons.bookmark : Icons.bookmark_border,
icon: FaIcon(
_isBookmarked ? FontAwesomeIcons.solidBookmark : FontAwesomeIcons.bookmark,
color: _isBookmarked ? AppColors.warning : Colors.black,
size: 20,
),
onPressed: _onBookmarkTap,
),
@@ -126,8 +128,8 @@ class _NewsDetailPageState extends ConsumerState<NewsDetailPage> {
errorWidget: (context, url, error) => Container(
height: 250,
color: AppColors.grey100,
child: const Icon(
Icons.image_outlined,
child: const FaIcon(
FontAwesomeIcons.image,
size: 48,
color: AppColors.grey500,
),
@@ -276,7 +278,7 @@ class _NewsDetailPageState extends ConsumerState<NewsDetailPage> {
),
// Date
_buildMetaItem(Icons.calendar_today, article.formattedDate),
_buildMetaItem(FontAwesomeIcons.calendar, article.formattedDate),
// Reading time
// _buildMetaItem(Icons.schedule, article.readingTimeText),
@@ -295,7 +297,7 @@ class _NewsDetailPageState extends ConsumerState<NewsDetailPage> {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 12, color: const Color(0xFF64748B)),
FaIcon(icon, size: 12, color: const Color(0xFF64748B)),
const SizedBox(width: 4),
Text(
text,
@@ -369,18 +371,18 @@ class _NewsDetailPageState extends ConsumerState<NewsDetailPage> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildActionButton(
icon: _isLiked ? Icons.favorite : Icons.favorite_border,
icon: _isLiked ? FontAwesomeIcons.solidHeart : FontAwesomeIcons.heart,
onPressed: _onLikeTap,
color: _isLiked ? Colors.red : null,
),
const SizedBox(width: 8),
_buildActionButton(
icon: _isBookmarked ? Icons.bookmark : Icons.bookmark_border,
icon: _isBookmarked ? FontAwesomeIcons.solidBookmark : FontAwesomeIcons.bookmark,
onPressed: _onBookmarkTap,
color: _isBookmarked ? AppColors.warning : null,
),
const SizedBox(width: 8),
_buildActionButton(icon: Icons.share, onPressed: _onShareTap),
_buildActionButton(icon: FontAwesomeIcons.shareNodes, onPressed: _onShareTap),
],
),
);
@@ -414,7 +416,7 @@ class _NewsDetailPageState extends ConsumerState<NewsDetailPage> {
side: BorderSide(color: color ?? const Color(0xFFE2E8F0), width: 2),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
child: Icon(icon, size: 20, color: color ?? const Color(0xFF64748B)),
child: FaIcon(icon, size: 18, color: color ?? const Color(0xFF64748B)),
);
}
@@ -458,7 +460,7 @@ class _NewsDetailPageState extends ConsumerState<NewsDetailPage> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.article_outlined, size: 64, color: AppColors.grey500),
FaIcon(FontAwesomeIcons.fileLines, size: 64, color: AppColors.grey500),
const SizedBox(height: 16),
const Text(
'Không tìm thấy bài viết',
@@ -490,7 +492,7 @@ class _NewsDetailPageState extends ConsumerState<NewsDetailPage> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.error_outline, size: 64, color: AppColors.danger),
FaIcon(FontAwesomeIcons.circleExclamation, size: 64, color: AppColors.danger),
const SizedBox(height: 16),
const Text(
'Không thể tải bài viết',

View File

@@ -6,6 +6,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/theme/colors.dart';
@@ -111,9 +112,9 @@ class _NewsListPageState extends ConsumerState<NewsListPage> {
padding: EdgeInsets.symmetric(horizontal: AppSpacing.md),
child: Row(
children: [
Icon(
Icons.newspaper,
size: 18,
FaIcon(
FontAwesomeIcons.newspaper,
size: 16,
color: AppColors.primaryBlue,
),
SizedBox(width: 8),
@@ -194,7 +195,7 @@ class _NewsListPageState extends ConsumerState<NewsListPage> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.newspaper_outlined, size: 64, color: AppColors.grey500),
FaIcon(FontAwesomeIcons.newspaper, size: 64, color: AppColors.grey500),
const SizedBox(height: 16),
const Text(
'Chưa có tin tức',
@@ -221,7 +222,7 @@ class _NewsListPageState extends ConsumerState<NewsListPage> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.error_outline, size: 64, color: AppColors.danger),
FaIcon(FontAwesomeIcons.circleExclamation, size: 64, color: AppColors.danger),
const SizedBox(height: 16),
const Text(
'Không thể tải tin tức',

View File

@@ -7,6 +7,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/theme/colors.dart';
import 'package:worker/features/news/domain/entities/blog_category.dart';
@@ -121,7 +122,7 @@ class CategoryFilterChips extends ConsumerWidget {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.error_outline, size: 16, color: AppColors.grey500),
FaIcon(FontAwesomeIcons.circleExclamation, size: 16, color: AppColors.grey500),
const SizedBox(width: AppSpacing.xs),
Text(
'Lỗi tải danh mục',
@@ -133,7 +134,7 @@ class CategoryFilterChips extends ConsumerWidget {
const SizedBox(width: AppSpacing.xs),
GestureDetector(
onTap: () => ref.refresh(blogCategoriesProvider),
child: Icon(Icons.refresh, size: 16, color: AppColors.primaryBlue),
child: FaIcon(FontAwesomeIcons.arrowsRotate, size: 14, color: AppColors.primaryBlue),
),
],
),

View File

@@ -6,6 +6,7 @@ library;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/theme/colors.dart';
import 'package:worker/features/news/domain/entities/news_article.dart';
@@ -68,8 +69,8 @@ class FeaturedNewsCard extends StatelessWidget {
errorWidget: (context, url, error) => Container(
height: 200,
color: AppColors.grey100,
child: const Icon(
Icons.image_outlined,
child: const FaIcon(
FontAwesomeIcons.image,
size: 48,
color: AppColors.grey500,
),
@@ -122,7 +123,7 @@ class FeaturedNewsCard extends StatelessWidget {
children: [
// Date
_buildMetaItem(
icon: Icons.calendar_today,
icon: FontAwesomeIcons.calendar,
text: article.formattedDate,
),
@@ -176,7 +177,7 @@ class FeaturedNewsCard extends StatelessWidget {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 12, color: const Color(0xFF64748B)),
FaIcon(icon, size: 12, color: const Color(0xFF64748B)),
const SizedBox(width: 4),
Text(
text,

View File

@@ -5,6 +5,7 @@
library;
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/constants/ui_constants.dart';
/// Highlight type enum
@@ -65,7 +66,7 @@ class HighlightBox extends StatelessWidget {
// Title with icon
Row(
children: [
Icon(_getIcon(), size: 20, color: const Color(0xFF92400E)),
FaIcon(_getIcon(), size: 18, color: const Color(0xFF92400E)),
const SizedBox(width: 8),
Text(
title,
@@ -98,9 +99,9 @@ class HighlightBox extends StatelessWidget {
IconData _getIcon() {
switch (type) {
case HighlightType.tip:
return Icons.lightbulb;
return FontAwesomeIcons.lightbulb;
case HighlightType.warning:
return Icons.error_outline;
return FontAwesomeIcons.circleExclamation;
}
}
}

View File

@@ -6,6 +6,7 @@ library;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/theme/colors.dart';
import 'package:worker/features/news/domain/entities/news_article.dart';
@@ -67,8 +68,8 @@ class NewsCard extends StatelessWidget {
width: 80,
height: 80,
color: AppColors.grey100,
child: const Icon(
Icons.image_outlined,
child: const FaIcon(
FontAwesomeIcons.image,
size: 24,
color: AppColors.grey500,
),
@@ -116,8 +117,8 @@ class NewsCard extends StatelessWidget {
Row(
children: [
// Date
const Icon(
Icons.calendar_today,
const FaIcon(
FontAwesomeIcons.calendar,
size: 12,
color: Color(0xFF64748B),
),

View File

@@ -6,6 +6,7 @@ library;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/theme/colors.dart';
import 'package:worker/features/news/domain/entities/news_article.dart';
@@ -66,8 +67,8 @@ class RelatedArticleCard extends StatelessWidget {
width: 60,
height: 60,
color: AppColors.grey100,
child: const Icon(
Icons.image_outlined,
child: const FaIcon(
FontAwesomeIcons.image,
size: 20,
color: AppColors.grey500,
),

View File

@@ -5,6 +5,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/database/models/enums.dart';
@@ -57,7 +58,7 @@ class _OrdersPageState extends ConsumerState<OrdersPage> {
backgroundColor: const Color(0xFFF4F6F8),
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
onPressed: () => context.pop(),
),
title: const Text(
@@ -137,17 +138,17 @@ class _OrdersPageState extends ConsumerState<OrdersPage> {
decoration: InputDecoration(
hintText: 'Mã đơn hàng',
hintStyle: const TextStyle(color: AppColors.grey500, fontSize: 14),
prefixIcon: const Icon(
Icons.search,
prefixIcon: const FaIcon(
FontAwesomeIcons.magnifyingGlass,
color: AppColors.grey500,
size: 20,
size: 18,
),
suffixIcon: _searchController.text.isNotEmpty
? IconButton(
icon: const Icon(
Icons.clear,
icon: const FaIcon(
FontAwesomeIcons.xmark,
color: AppColors.grey500,
size: 20,
size: 18,
),
onPressed: () {
_searchController.clear();
@@ -283,8 +284,8 @@ class _OrdersPageState extends ConsumerState<OrdersPage> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.receipt_long_outlined,
FaIcon(
FontAwesomeIcons.receipt,
size: 80,
color: AppColors.grey500.withValues(alpha: 0.5),
),
@@ -322,8 +323,8 @@ class _OrdersPageState extends ConsumerState<OrdersPage> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.error_outline,
FaIcon(
FontAwesomeIcons.circleExclamation,
size: 80,
color: AppColors.danger.withValues(alpha: 0.7),
),

View File

@@ -5,6 +5,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/database/models/enums.dart';
@@ -140,7 +141,7 @@ class _PaymentsPageState extends ConsumerState<PaymentsPage>
backgroundColor: const Color(0xFFF4F6F8),
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
onPressed: () => context.pop(),
),
title: const Text(
@@ -256,7 +257,7 @@ class _PaymentsPageState extends ConsumerState<PaymentsPage>
backgroundColor: const Color(0xFFF4F6F8),
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
onPressed: () => context.pop(),
),
title: const Text(
@@ -274,7 +275,7 @@ class _PaymentsPageState extends ConsumerState<PaymentsPage>
backgroundColor: const Color(0xFFF4F6F8),
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
onPressed: () => context.pop(),
),
title: const Text(
@@ -290,8 +291,8 @@ class _PaymentsPageState extends ConsumerState<PaymentsPage>
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.error_outline,
FaIcon(
FontAwesomeIcons.circleExclamation,
size: 80,
color: AppColors.danger.withValues(alpha: 0.7),
),
@@ -325,19 +326,19 @@ class _PaymentsPageState extends ConsumerState<PaymentsPage>
switch (tabLabel) {
case 'Chưa thanh toán':
message = 'Không có hóa đơn chưa thanh toán';
icon = Icons.receipt_long_outlined;
icon = FontAwesomeIcons.receipt;
break;
case 'Quá hạn':
message = 'Không có hóa đơn quá hạn';
icon = Icons.warning_amber_outlined;
icon = FontAwesomeIcons.triangleExclamation;
break;
case 'Đã thanh toán':
message = 'Không có hóa đơn đã thanh toán';
icon = Icons.check_circle_outline;
icon = FontAwesomeIcons.circleCheck;
break;
default:
message = 'Không có hóa đơn nào';
icon = Icons.receipt_long_outlined;
icon = FontAwesomeIcons.receipt;
}
return SliverFillRemaining(
@@ -345,7 +346,7 @@ class _PaymentsPageState extends ConsumerState<PaymentsPage>
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
FaIcon(
icon,
size: 80,
color: AppColors.grey500.withValues(alpha: 0.5),

View File

@@ -4,6 +4,7 @@
library;
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
import 'package:worker/core/database/models/enums.dart';
import 'package:worker/core/theme/colors.dart';
@@ -241,7 +242,7 @@ class InvoiceCard extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center,
spacing: 8,
children: [
Icon(Icons.credit_card),
FaIcon(FontAwesomeIcons.creditCard, size: 18),
Text(
buttonText,
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600),

View File

@@ -5,6 +5,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/theme/colors.dart';
@@ -112,7 +113,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
// Share options
ListTile(
leading: const Icon(Icons.chat, color: AppColors.primaryBlue),
leading: const FaIcon(FontAwesomeIcons.message, color: AppColors.primaryBlue, size: 20),
title: const Text('Chia sẻ qua tin nhắn'),
onTap: () {
Navigator.pop(context);
@@ -124,7 +125,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
},
),
ListTile(
leading: const Icon(Icons.share, color: AppColors.primaryBlue),
leading: const FaIcon(FontAwesomeIcons.shareNodes, color: AppColors.primaryBlue, size: 20),
title: const Text('Chia sẻ khác'),
onTap: () {
Navigator.pop(context);
@@ -132,7 +133,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
},
),
ListTile(
leading: const Icon(Icons.copy, color: AppColors.primaryBlue),
leading: const FaIcon(FontAwesomeIcons.copy, color: AppColors.primaryBlue, size: 20),
title: const Text('Sao chép link'),
onTap: () {
Navigator.pop(context);
@@ -178,7 +179,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
backgroundColor: const Color(0xFFF4F6F8),
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
onPressed: () => context.pop(),
),
title: const Text(
@@ -192,7 +193,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
actions: [
// Share button
IconButton(
icon: const Icon(Icons.share, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.shareNodes, color: Colors.black, size: 20),
onPressed: () {
productAsync.whenData((product) {
_shareProduct(product);
@@ -202,7 +203,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
// Favorite button
IconButton(
icon: Icon(
isFavorite ? Icons.favorite : Icons.favorite_border,
isFavorite ? FontAwesomeIcons.solidHeart : FontAwesomeIcons.heart,
color: isFavorite ? AppColors.danger : Colors.black,
),
onPressed: _toggleFavorite,
@@ -265,7 +266,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.error_outline,
FontAwesomeIcons.circleExclamation,
size: 80,
color: AppColors.danger,
),
@@ -290,7 +291,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
// Invalidate to trigger refetch
ref.invalidate(productDetailProvider(productId: widget.productId));
},
icon: const Icon(Icons.refresh),
icon: const FaIcon(FontAwesomeIcons.arrowsRotate, size: 18),
label: const Text('Thử lại'),
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryBlue,

View File

@@ -5,6 +5,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/router/app_router.dart';
@@ -45,7 +46,7 @@ class ProductsPage extends ConsumerWidget {
endDrawer: const ProductFilterDrawer(),
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
onPressed: () => context.pop(),
),
title: const Text('Sản phẩm', style: TextStyle(color: Colors.black)),
@@ -61,7 +62,7 @@ class ProductsPage extends ConsumerWidget {
backgroundColor: AppColors.danger,
textColor: AppColors.white,
isLabelVisible: cartItemCount > 0,
child: const Icon(Icons.shopping_cart_outlined, color: Colors.black),
child: const FaIcon(FontAwesomeIcons.cartShopping, color: Colors.black, size: 20),
),
onPressed: () => context.push(RouteNames.cart),
),
@@ -88,7 +89,7 @@ class ProductsPage extends ConsumerWidget {
// Open filter drawer from right
Scaffold.of(scaffoldContext).openEndDrawer();
},
icon: const Icon(Icons.filter_list, size: 20),
icon: const FaIcon(FontAwesomeIcons.sliders, size: 18),
label: const Text('Lọc', style: TextStyle(fontSize: 12)),
style: OutlinedButton.styleFrom(
foregroundColor: AppColors.grey900,
@@ -160,7 +161,7 @@ class ProductsPage extends ConsumerWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.inventory_2_outlined, size: 80.0, color: AppColors.grey500.withAlpha(128)),
FaIcon(FontAwesomeIcons.boxOpen, size: 80.0, color: AppColors.grey500.withAlpha(128)),
const SizedBox(height: AppSpacing.lg),
Text(
l10n.noProductsFound,
@@ -186,7 +187,7 @@ class ProductsPage extends ConsumerWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.error_outline, size: 80.0, color: AppColors.danger.withAlpha(128)),
FaIcon(FontAwesomeIcons.circleExclamation, size: 80.0, color: AppColors.danger.withAlpha(128)),
const SizedBox(height: AppSpacing.lg),
Text(
l10n.error,
@@ -203,7 +204,7 @@ class ProductsPage extends ConsumerWidget {
onPressed: () async {
await ref.read(productsProvider.notifier).refresh();
},
icon: const Icon(Icons.refresh),
icon: const FaIcon(FontAwesomeIcons.arrowsRotate, size: 18),
label: Text(l10n.tryAgain),
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryBlue,

View File

@@ -6,6 +6,7 @@ library;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
import 'package:shimmer/shimmer.dart';
import 'package:worker/core/constants/ui_constants.dart';
@@ -75,7 +76,7 @@ class ProductCard extends ConsumerWidget {
errorWidget: (context, url, error) => Container(
color: AppColors.grey100,
child: const Icon(
Icons.image_not_supported,
FontAwesomeIcons.image,
size: 48.0,
color: AppColors.grey500,
),
@@ -254,7 +255,7 @@ class ProductCard extends ConsumerWidget {
horizontal: AppSpacing.sm,
),
),
icon: const Icon(Icons.shopping_cart, size: 16.0),
icon: const FaIcon(FontAwesomeIcons.cartShopping, size: 14.0),
label: Text(
!product.inStock ? 'Thêm vào giỏ' : l10n.outOfStock,
style: const TextStyle(
@@ -299,7 +300,7 @@ class ProductCard extends ConsumerWidget {
horizontal: AppSpacing.sm,
),
),
icon: const Icon(Icons.threed_rotation, size: 16.0),
icon: const FaIcon(FontAwesomeIcons.cube, size: 14.0),
label: const Text(
'Phối cảnh 360°',
style: TextStyle(

View File

@@ -5,6 +5,7 @@ library;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:shimmer/shimmer.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/theme/colors.dart';
@@ -108,7 +109,7 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
errorWidget: (context, url, error) => Container(
color: AppColors.grey100,
child: const Icon(
Icons.image_not_supported,
FontAwesomeIcons.image,
size: 64,
color: AppColors.grey500,
),
@@ -144,7 +145,7 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
return Transform.rotate(
angle: value * 2 * 3.14159,
child: const Icon(
Icons.sync,
FontAwesomeIcons.arrowsRotate,
size: 10,
color: AppColors.white,
),
@@ -234,7 +235,7 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
errorWidget: (context, url, error) => Container(
color: AppColors.grey100,
child: const Icon(
Icons.image_not_supported,
FontAwesomeIcons.image,
size: 20,
color: AppColors.grey500,
),
@@ -312,7 +313,7 @@ class _ImageLightboxState extends State<_ImageLightbox> {
foregroundColor: AppColors.white,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.close, size: 32),
icon: const FaIcon(FontAwesomeIcons.xmark, size: 28),
onPressed: () => Navigator.of(context).pop(),
),
title: Text(
@@ -340,7 +341,7 @@ class _ImageLightboxState extends State<_ImageLightbox> {
imageUrl: widget.images[index],
fit: BoxFit.contain,
errorWidget: (context, url, error) => const Icon(
Icons.error_outline,
FontAwesomeIcons.circleExclamation,
color: AppColors.white,
size: 64,
),
@@ -361,7 +362,7 @@ class _ImageLightboxState extends State<_ImageLightbox> {
child: Center(
child: IconButton(
icon: const Icon(
Icons.chevron_left,
FontAwesomeIcons.chevronLeft,
color: AppColors.white,
size: 32,
),
@@ -382,7 +383,7 @@ class _ImageLightboxState extends State<_ImageLightbox> {
child: Center(
child: IconButton(
icon: const Icon(
Icons.chevron_right,
FontAwesomeIcons.chevronRight,
color: AppColors.white,
size: 32,
),

View File

@@ -4,6 +4,7 @@
library;
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/theme/colors.dart';
import 'package:worker/features/products/domain/entities/product.dart';
@@ -152,7 +153,7 @@ class _DescriptionTab extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Icon(
Icons.check_circle,
FontAwesomeIcons.circleCheck,
size: 18,
color: AppColors.success,
),
@@ -328,7 +329,7 @@ class _ReviewsTab extends StatelessWidget {
children: List.generate(
5,
(index) => Icon(
index < 4 ? Icons.star : Icons.star_half,
index < 4 ? FontAwesomeIcons.solidStar : FontAwesomeIcons.starHalfStroke,
color: const Color(0xFFffc107),
size: 18,
),
@@ -387,7 +388,7 @@ class _ReviewItem extends StatelessWidget {
color: Color(0xFFF4F6F8),
),
child: const Icon(
Icons.person,
FontAwesomeIcons.solidUser,
color: AppColors.grey500,
size: 20,
),
@@ -428,8 +429,8 @@ class _ReviewItem extends StatelessWidget {
5,
(index) => Icon(
index < (review['rating'] as num? ?? 0).toInt()
? Icons.star
: Icons.star_border,
? FontAwesomeIcons.solidStar
: FontAwesomeIcons.star,
color: const Color(0xFFffc107),
size: 14,
),

View File

@@ -5,6 +5,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/theme/colors.dart';
@@ -89,7 +90,7 @@ class StickyActionBar extends StatelessWidget {
children: [
// Decrease Button
_QuantityButton(
icon: Icons.remove,
icon: FontAwesomeIcons.minus,
onPressed: quantity > 1 ? onDecrease : null,
),
@@ -122,7 +123,7 @@ class StickyActionBar extends StatelessWidget {
),
// Increase Button
_QuantityButton(icon: Icons.add, onPressed: onIncrease),
_QuantityButton(icon: FontAwesomeIcons.plus, onPressed: onIncrease),
],
),
),
@@ -160,7 +161,7 @@ class StickyActionBar extends StatelessWidget {
borderRadius: BorderRadius.circular(8),
),
),
icon: const Icon(Icons.shopping_cart, size: 20),
icon: const FaIcon(FontAwesomeIcons.cartShopping, size: 18),
label: Text(
isOutOfStock ? 'Hết hàng' : 'Thêm vào giỏ hàng',
style: const TextStyle(

View File

@@ -5,6 +5,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/theme/colors.dart';
import 'package:worker/features/products/presentation/providers/product_filters_provider.dart';
@@ -51,7 +52,7 @@ class ProductFilterDrawer extends ConsumerWidget {
),
),
IconButton(
icon: const Icon(Icons.close),
icon: const FaIcon(FontAwesomeIcons.xmark, size: 20),
onPressed: () => Navigator.of(context).pop(),
color: AppColors.grey500,
),
@@ -208,7 +209,7 @@ class ProductFilterDrawer extends ConsumerWidget {
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.error_outline,
FontAwesomeIcons.circleExclamation,
size: 48,
color: AppColors.danger,
),

View File

@@ -5,6 +5,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/theme/colors.dart';
import 'package:worker/features/products/presentation/providers/search_query_provider.dart';
@@ -67,14 +68,14 @@ class _ProductSearchBarState extends ConsumerState<ProductSearchBar> {
color: AppColors.grey500,
),
prefixIcon: const Icon(
Icons.search,
FontAwesomeIcons.magnifyingGlass,
color: AppColors.grey500,
size: AppIconSize.md,
),
suffixIcon: _controller.text.isNotEmpty
? IconButton(
icon: const Icon(
Icons.clear,
FontAwesomeIcons.xmark,
color: AppColors.grey500,
size: AppIconSize.md,
),

View File

@@ -11,6 +11,7 @@ library;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/router/app_router.dart';
@@ -56,7 +57,7 @@ class _PromotionDetailPageState extends ConsumerState<PromotionDetailPage> {
loading: () => Scaffold(
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
onPressed: () => context.pop(),
),
title: const Text(
@@ -73,7 +74,7 @@ class _PromotionDetailPageState extends ConsumerState<PromotionDetailPage> {
error: (error, stack) => Scaffold(
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
onPressed: () => context.pop(),
),
title: const Text(
@@ -89,8 +90,8 @@ class _PromotionDetailPageState extends ConsumerState<PromotionDetailPage> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.error_outline,
const FaIcon(
FontAwesomeIcons.circleExclamation,
size: 64,
color: AppColors.danger,
),
@@ -127,7 +128,7 @@ class _PromotionDetailPageState extends ConsumerState<PromotionDetailPage> {
foregroundColor: AppColors.grey900,
elevation: AppBarSpecs.elevation,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
onPressed: () => context.pop(),
),
title: const Text(
@@ -138,15 +139,16 @@ class _PromotionDetailPageState extends ConsumerState<PromotionDetailPage> {
actions: [
// Share Button
IconButton(
icon: const Icon(Icons.share, color: Colors.black),
icon: const FaIcon(FontAwesomeIcons.shareNodes, color: Colors.black, size: 20),
onPressed: _handleShare,
),
// Bookmark Button
IconButton(
icon: Icon(
_isBookmarked ? Icons.bookmark : Icons.bookmark_border,
icon: FaIcon(
_isBookmarked ? FontAwesomeIcons.solidBookmark : FontAwesomeIcons.bookmark,
color: Colors.black,
size: 20,
),
onPressed: _handleBookmark,
),
@@ -205,8 +207,8 @@ class _PromotionDetailPageState extends ConsumerState<PromotionDetailPage> {
height: 200,
color: AppColors.grey100,
child: const Center(
child: Icon(
Icons.image_not_supported,
child: FaIcon(
FontAwesomeIcons.image,
size: 64,
color: AppColors.grey500,
),
@@ -243,9 +245,9 @@ class _PromotionDetailPageState extends ConsumerState<PromotionDetailPage> {
crossAxisAlignment: WrapCrossAlignment.center,
children: [
// Clock icon and date
const Icon(
Icons.access_time,
size: 18,
const FaIcon(
FontAwesomeIcons.clock,
size: 16,
color: Color(0xFFF59E0B), // warning color
),
Text(
@@ -270,8 +272,8 @@ class _PromotionDetailPageState extends ConsumerState<PromotionDetailPage> {
child: const Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.local_fire_department,
FaIcon(
FontAwesomeIcons.fire,
size: 14,
color: Colors.white,
),
@@ -298,7 +300,7 @@ class _PromotionDetailPageState extends ConsumerState<PromotionDetailPage> {
Widget _buildProgramContentSection() {
return const PromotionSection(
title: 'Nội dung chương trình',
icon: Icons.card_giftcard,
icon: FontAwesomeIcons.gift,
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -345,7 +347,7 @@ class _PromotionDetailPageState extends ConsumerState<PromotionDetailPage> {
Widget _buildTermsSection() {
return const PromotionSection(
title: 'Điều kiện áp dụng',
icon: Icons.description,
icon: FontAwesomeIcons.fileLines,
content: PromotionBulletList(
items: [
'Áp dụng cho tất cả khách hàng là thợ xây dựng đã đăng ký tài khoản',
@@ -365,7 +367,7 @@ class _PromotionDetailPageState extends ConsumerState<PromotionDetailPage> {
Widget _buildContactSection() {
return const PromotionSection(
title: 'Thông tin liên hệ',
icon: Icons.phone,
icon: FontAwesomeIcons.phone,
isLast: true,
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -414,7 +416,7 @@ class _PromotionDetailPageState extends ConsumerState<PromotionDetailPage> {
child: const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.visibility, size: 20),
FaIcon(FontAwesomeIcons.eye, size: 18),
SizedBox(width: 8),
Text(
'Xem sản phẩm áp dụng',

View File

@@ -6,6 +6,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:worker/core/theme/colors.dart';
import 'package:worker/features/home/domain/entities/promotion.dart';
@@ -47,8 +48,8 @@ class PromotionsPage extends ConsumerWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.error_outline,
const FaIcon(
FontAwesomeIcons.circleExclamation,
color: AppColors.danger,
size: 48,
),
@@ -117,8 +118,8 @@ class PromotionsPage extends ConsumerWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.local_offer_outlined,
FaIcon(
FontAwesomeIcons.tag,
size: 64,
color: AppColors.grey500,
),

View File

@@ -5,6 +5,7 @@
library;
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/theme/colors.dart';
/// Featured Promotion Card
@@ -90,9 +91,9 @@ class FeaturedPromotionCard extends StatelessWidget {
const SizedBox(height: 12),
Row(
children: [
Icon(
Icons.access_time,
size: 14,
FaIcon(
FontAwesomeIcons.clock,
size: 12,
color: Colors.white.withValues(alpha: 0.8),
),
const SizedBox(width: 4),
@@ -112,8 +113,8 @@ class FeaturedPromotionCard extends StatelessWidget {
// Right side - Icon
const SizedBox(width: 16),
Icon(
Icons.percent,
FaIcon(
FontAwesomeIcons.percent,
size: 48,
color: Colors.white.withValues(alpha: 0.9),
),

View File

@@ -6,6 +6,7 @@ library;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:worker/core/router/app_router.dart';
import 'package:worker/core/theme/colors.dart';
@@ -62,8 +63,8 @@ class PromotionCard extends StatelessWidget {
height: 150,
color: AppColors.grey100,
child: const Center(
child: Icon(
Icons.image_not_supported,
child: FaIcon(
FontAwesomeIcons.image,
size: 48,
color: AppColors.grey500,
),
@@ -109,8 +110,8 @@ class PromotionCard extends StatelessWidget {
Expanded(
child: Row(
children: [
const Icon(
Icons.calendar_today,
const FaIcon(
FontAwesomeIcons.calendar,
size: 12,
color: AppColors.primaryBlue,
),

View File

@@ -4,6 +4,7 @@
library;
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import '../../core/constants/ui_constants.dart';
/// Custom app bar with consistent styling
@@ -112,7 +113,7 @@ class SearchAppBar extends StatelessWidget implements PreferredSizeWidget {
leading:
leading ??
IconButton(
icon: const Icon(Icons.arrow_back),
icon: const FaIcon(FontAwesomeIcons.arrowLeft, size: 20),
onPressed: () => Navigator.of(context).pop(),
),
title: TextField(
@@ -127,7 +128,7 @@ class SearchAppBar extends StatelessWidget implements PreferredSizeWidget {
border: InputBorder.none,
suffixIcon: controller?.text.isNotEmpty ?? false
? IconButton(
icon: const Icon(Icons.clear, color: Colors.white),
icon: const FaIcon(FontAwesomeIcons.xmark, color: Colors.white, size: 18),
onPressed: () {
controller?.clear();
onClear?.call();

View File

@@ -5,6 +5,7 @@
library;
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import '../../core/utils/formatters.dart';
import '../../core/utils/validators.dart';
import '../../core/constants/ui_constants.dart';
@@ -118,7 +119,7 @@ class _DatePickerFieldState extends State<DatePickerField> {
InputDecoration(
labelText: widget.labelText ?? 'Ngày',
hintText: widget.hintText ?? 'dd/MM/yyyy',
prefixIcon: widget.prefixIcon ?? const Icon(Icons.calendar_today),
prefixIcon: widget.prefixIcon ?? const FaIcon(FontAwesomeIcons.calendar, size: 20),
suffixIcon: widget.suffixIcon,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(InputFieldSpecs.borderRadius),
@@ -219,7 +220,7 @@ class _DateRangePickerFieldState extends State<DateRangePickerField> {
decoration: InputDecoration(
labelText: widget.labelText ?? 'Khoảng thời gian',
hintText: widget.hintText ?? 'Chọn khoảng thời gian',
prefixIcon: widget.prefixIcon ?? const Icon(Icons.date_range),
prefixIcon: widget.prefixIcon ?? const FaIcon(FontAwesomeIcons.calendarDays, size: 20),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(InputFieldSpecs.borderRadius),
),
@@ -266,7 +267,7 @@ class DateOfBirthField extends StatelessWidget {
onDateSelected: onDateSelected,
validator: validator ?? (value) => Validators.age(value, minAge: minAge),
enabled: enabled,
prefixIcon: const Icon(Icons.cake),
prefixIcon: const FaIcon(FontAwesomeIcons.cakeCandles, size: 20),
);
}
}
@@ -364,7 +365,7 @@ class _TimePickerFieldState extends State<TimePickerField> {
decoration: InputDecoration(
labelText: widget.labelText ?? 'Thời gian',
hintText: widget.hintText ?? 'HH:mm',
prefixIcon: widget.prefixIcon ?? const Icon(Icons.access_time),
prefixIcon: widget.prefixIcon ?? const FaIcon(FontAwesomeIcons.clock, size: 20),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(InputFieldSpecs.borderRadius),
),

View File

@@ -6,6 +6,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/utils/formatters.dart';
import 'package:worker/core/utils/validators.dart';
@@ -89,7 +90,7 @@ class _VietnamesePhoneFieldState extends State<VietnamesePhoneField> {
decoration: InputDecoration(
labelText: widget.labelText ?? 'Số điện thoại',
hintText: widget.hintText ?? '0xxx xxx xxx',
prefixIcon: widget.prefixIcon ?? const Icon(Icons.phone),
prefixIcon: widget.prefixIcon ?? const FaIcon(FontAwesomeIcons.phone, size: 20),
suffixIcon: widget.suffixIcon,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(InputFieldSpecs.borderRadius),
@@ -158,8 +159,8 @@ class PhoneDisplayField extends StatelessWidget {
onTap: onTap,
decoration: InputDecoration(
labelText: labelText ?? 'Số điện thoại',
prefixIcon: prefixIcon ?? const Icon(Icons.phone),
suffixIcon: onTap != null ? const Icon(Icons.edit) : null,
prefixIcon: prefixIcon ?? const FaIcon(FontAwesomeIcons.phone, size: 20),
suffixIcon: onTap != null ? const FaIcon(FontAwesomeIcons.penToSquare, size: 18) : null,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(InputFieldSpecs.borderRadius),
),

View File

@@ -578,6 +578,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
font_awesome_flutter:
dependency: "direct main"
description:
name: font_awesome_flutter
sha256: b9011df3a1fa02993630b8fb83526368cf2206a711259830325bab2f1d2a4eb0
url: "https://pub.dev"
source: hosted
version: "10.12.0"
freezed:
dependency: "direct dev"
description:

View File

@@ -62,6 +62,7 @@ dependencies:
lottie: ^3.1.2
qr_flutter: ^4.1.0
mobile_scanner: ^5.2.3
font_awesome_flutter: ^10.7.0
# Utilities