update theme

This commit is contained in:
Phuoc Nguyen
2025-12-02 15:20:54 +07:00
parent 12bd70479c
commit 49a41d24eb
78 changed files with 3263 additions and 2756 deletions

View File

@@ -79,14 +79,16 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
}
void _shareProduct(Product product) {
final colorScheme = Theme.of(context).colorScheme;
// Show share options
showModalBottomSheet(
context: context,
backgroundColor: Colors.transparent,
builder: (context) => Container(
decoration: const BoxDecoration(
color: AppColors.white,
borderRadius: BorderRadius.vertical(
decoration: BoxDecoration(
color: colorScheme.surface,
borderRadius: const BorderRadius.vertical(
top: Radius.circular(AppRadius.xl),
),
),
@@ -99,7 +101,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
width: 40,
height: 4,
decoration: BoxDecoration(
color: AppColors.grey100,
color: colorScheme.outlineVariant,
borderRadius: BorderRadius.circular(2),
),
),
@@ -114,7 +116,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
// Share options
ListTile(
leading: const FaIcon(FontAwesomeIcons.message, color: AppColors.primaryBlue, size: 20),
leading: FaIcon(FontAwesomeIcons.message, color: colorScheme.primary, size: 20),
title: const Text('Chia sẻ qua tin nhắn'),
onTap: () {
Navigator.pop(context);
@@ -127,7 +129,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
},
),
ListTile(
leading: const FaIcon(FontAwesomeIcons.shareNodes, color: AppColors.primaryBlue, size: 20),
leading: FaIcon(FontAwesomeIcons.shareNodes, color: colorScheme.primary, size: 20),
title: const Text('Chia sẻ khác'),
onTap: () {
Navigator.pop(context);
@@ -135,7 +137,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
},
),
ListTile(
leading: const FaIcon(FontAwesomeIcons.copy, color: AppColors.primaryBlue, size: 20),
leading: FaIcon(FontAwesomeIcons.copy, color: colorScheme.primary, size: 20),
title: const Text('Sao chép link'),
onTap: () {
Navigator.pop(context);
@@ -171,6 +173,8 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
// Use productDetailProvider with productId parameter
final productAsync = ref.watch(productDetailProvider(productId: widget.productId));
@@ -178,24 +182,24 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
final isFavorite = ref.watch(isFavoriteProvider(widget.productId));
return Scaffold(
backgroundColor: const Color(0xFFF4F6F8),
backgroundColor: colorScheme.surfaceContainerLowest,
appBar: AppBar(
leading: IconButton(
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
icon: FaIcon(FontAwesomeIcons.arrowLeft, color: colorScheme.onSurface, size: 20),
onPressed: () => context.pop(),
),
title: const Text(
title: Text(
'Chi tiết sản phẩm',
style: TextStyle(color: Colors.black),
style: TextStyle(color: colorScheme.onSurface),
),
elevation: AppBarSpecs.elevation,
backgroundColor: AppColors.white,
foregroundColor: AppColors.grey900,
backgroundColor: colorScheme.surface,
foregroundColor: colorScheme.onSurface,
centerTitle: false,
actions: [
// Share button
IconButton(
icon: const FaIcon(FontAwesomeIcons.shareNodes, color: Colors.black, size: 20),
icon: FaIcon(FontAwesomeIcons.shareNodes, color: colorScheme.onSurface, size: 20),
onPressed: () {
productAsync.whenData((product) {
_shareProduct(product);
@@ -206,7 +210,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
IconButton(
icon: Icon(
isFavorite ? FontAwesomeIcons.solidHeart : FontAwesomeIcons.heart,
color: isFavorite ? AppColors.danger : Colors.black,
color: isFavorite ? AppColors.danger : colorScheme.onSurface,
),
onPressed: _toggleFavorite,
),
@@ -258,8 +262,8 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
],
);
},
loading: () => const Center(
child: CircularProgressIndicator(color: AppColors.primaryBlue),
loading: () => Center(
child: CircularProgressIndicator(color: colorScheme.primary),
),
error: (error, stack) => Center(
child: Padding(
@@ -281,9 +285,9 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
const SizedBox(height: AppSpacing.sm),
Text(
error.toString(),
style: const TextStyle(
style: TextStyle(
fontSize: 14,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
textAlign: TextAlign.center,
),
@@ -296,8 +300,8 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
icon: const FaIcon(FontAwesomeIcons.arrowsRotate, size: 18),
label: const Text('Thử lại'),
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryBlue,
foregroundColor: AppColors.white,
backgroundColor: colorScheme.primary,
foregroundColor: colorScheme.onPrimary,
),
),
],

View File

@@ -32,6 +32,7 @@ class ProductsPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final colorScheme = Theme.of(context).colorScheme;
final l10n = AppLocalizations.of(context);
final productsAsync = ref.watch(productsProvider);
@@ -39,17 +40,17 @@ class ProductsPage extends ConsumerWidget {
ref.watch(productFilterOptionsProvider);
return Scaffold(
backgroundColor: const Color(0xFFF4F6F8), // Match HTML background
backgroundColor: colorScheme.surfaceContainerLowest,
endDrawer: const ProductFilterDrawer(),
appBar: AppBar(
leading: IconButton(
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
icon: FaIcon(FontAwesomeIcons.arrowLeft, color: colorScheme.onSurface, size: 20),
onPressed: () => context.pop(),
),
title: const Text('Sản phẩm', style: TextStyle(color: Colors.black)),
title: Text('Sản phẩm', style: TextStyle(color: colorScheme.onSurface)),
elevation: AppBarSpecs.elevation,
backgroundColor: AppColors.white,
foregroundColor: AppColors.grey900,
backgroundColor: colorScheme.surface,
foregroundColor: colorScheme.onSurface,
centerTitle: false,
actions: [
// Cart Icon with Badge (extracted to Consumer to prevent full page rebuild)
@@ -60,9 +61,9 @@ class ProductsPage extends ConsumerWidget {
icon: Badge(
label: Text('$cartItemCount'),
backgroundColor: AppColors.danger,
textColor: AppColors.white,
textColor: colorScheme.surface,
isLabelVisible: cartItemCount > 0,
child: const FaIcon(FontAwesomeIcons.cartShopping, color: Colors.black, size: 20),
child: FaIcon(FontAwesomeIcons.cartShopping, color: colorScheme.onSurface, size: 20),
),
onPressed: () => context.push(RouteNames.cart),
);
@@ -88,7 +89,7 @@ class ProductsPage extends ConsumerWidget {
height: InputFieldSpecs.height,
width: InputFieldSpecs.height,
decoration: BoxDecoration(
color: AppColors.white,
color: colorScheme.surface,
borderRadius: BorderRadius.circular(InputFieldSpecs.borderRadius),
),
child: IconButton(
@@ -97,7 +98,7 @@ class ProductsPage extends ConsumerWidget {
Scaffold.of(scaffoldContext).openEndDrawer();
},
icon: const FaIcon(FontAwesomeIcons.sliders, size: 18),
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
],
@@ -112,7 +113,7 @@ class ProductsPage extends ConsumerWidget {
child: productsAsync.when(
data: (products) {
if (products.isEmpty) {
return _buildEmptyState(context, l10n);
return _buildEmptyState(context, l10n, colorScheme);
}
final productsNotifier = ref.read(productsProvider.notifier);
@@ -159,8 +160,8 @@ class ProductsPage extends ConsumerWidget {
},
);
},
loading: () => _buildLoadingState(),
error: (error, stack) => _buildErrorState(context, l10n, error, ref),
loading: () => _buildLoadingState(colorScheme),
error: (error, stack) => _buildErrorState(context, l10n, error, ref, colorScheme),
),
),
],
@@ -171,31 +172,31 @@ class ProductsPage extends ConsumerWidget {
}
/// Build empty state
Widget _buildEmptyState(BuildContext context, AppLocalizations l10n) {
Widget _buildEmptyState(BuildContext context, AppLocalizations l10n, ColorScheme colorScheme) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FaIcon(FontAwesomeIcons.boxOpen, size: 80.0, color: AppColors.grey500.withAlpha(128)),
FaIcon(FontAwesomeIcons.boxOpen, size: 80.0, color: colorScheme.onSurfaceVariant.withAlpha(128)),
const SizedBox(height: AppSpacing.lg),
Text(
l10n.noProductsFound,
style: const TextStyle(fontSize: 18.0, fontWeight: FontWeight.w500, color: AppColors.grey900),
style: TextStyle(fontSize: 18.0, fontWeight: FontWeight.w500, color: colorScheme.onSurface),
),
const SizedBox(height: AppSpacing.sm),
Text(l10n.noResults, style: const TextStyle(fontSize: 14.0, color: AppColors.grey500)),
Text(l10n.noResults, style: TextStyle(fontSize: 14.0, color: colorScheme.onSurfaceVariant)),
],
),
);
}
/// Build loading state
Widget _buildLoadingState() {
return const Center(child: CircularProgressIndicator(color: AppColors.primaryBlue));
Widget _buildLoadingState(ColorScheme colorScheme) {
return Center(child: CircularProgressIndicator(color: colorScheme.primary));
}
/// Build error state
Widget _buildErrorState(BuildContext context, AppLocalizations l10n, Object error, WidgetRef ref) {
Widget _buildErrorState(BuildContext context, AppLocalizations l10n, Object error, WidgetRef ref, ColorScheme colorScheme) {
return Center(
child: Padding(
padding: const EdgeInsets.all(AppSpacing.xl),
@@ -206,12 +207,12 @@ class ProductsPage extends ConsumerWidget {
const SizedBox(height: AppSpacing.lg),
Text(
l10n.error,
style: const TextStyle(fontSize: 18.0, fontWeight: FontWeight.w600, color: AppColors.grey900),
style: TextStyle(fontSize: 18.0, fontWeight: FontWeight.w600, color: colorScheme.onSurface),
),
const SizedBox(height: AppSpacing.sm),
Text(
error.toString(),
style: const TextStyle(fontSize: 14.0, color: AppColors.grey500),
style: TextStyle(fontSize: 14.0, color: colorScheme.onSurfaceVariant),
textAlign: TextAlign.center,
),
const SizedBox(height: AppSpacing.lg),
@@ -222,8 +223,8 @@ class ProductsPage extends ConsumerWidget {
icon: const FaIcon(FontAwesomeIcons.arrowsRotate, size: 18),
label: Text(l10n.tryAgain),
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryBlue,
foregroundColor: AppColors.white,
backgroundColor: colorScheme.primary,
foregroundColor: colorScheme.onPrimary,
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.lg, vertical: AppSpacing.md),
),
),

View File

@@ -102,14 +102,16 @@ class _WriteReviewPageState extends ConsumerState<WriteReviewPage> {
);
if (mounted) {
final colorScheme = Theme.of(context).colorScheme;
// Show success message
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
SnackBar(
content: Row(
children: [
Icon(FontAwesomeIcons.circleCheck, color: AppColors.white),
SizedBox(width: 12),
Expanded(
Icon(FontAwesomeIcons.circleCheck, color: colorScheme.onPrimary),
const SizedBox(width: 12),
const Expanded(
child: Text('Đánh giá của bạn đã được gửi thành công!'),
),
],
@@ -128,15 +130,16 @@ class _WriteReviewPageState extends ConsumerState<WriteReviewPage> {
} catch (e) {
if (mounted) {
setState(() => _isSubmitting = false);
final colorScheme = Theme.of(context).colorScheme;
// Show error message
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Row(
children: [
const Icon(
Icon(
FontAwesomeIcons.triangleExclamation,
color: AppColors.white,
color: colorScheme.onPrimary,
),
const SizedBox(width: 12),
Expanded(
@@ -154,26 +157,27 @@ class _WriteReviewPageState extends ConsumerState<WriteReviewPage> {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
final productAsync = ref.watch(productDetailProvider(productId: widget.productId));
return Scaffold(
backgroundColor: AppColors.white,
backgroundColor: colorScheme.surface,
// Standard AppBar
appBar: AppBar(
backgroundColor: AppColors.white,
backgroundColor: colorScheme.surface,
elevation: AppBarSpecs.elevation,
centerTitle: false,
leading: IconButton(
icon: const Icon(
icon: Icon(
Icons.arrow_back,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
onPressed: () => context.pop(),
),
title: const Text(
title: Text(
'Viết đánh giá sản phẩm',
style: TextStyle(
color: AppColors.grey900,
color: colorScheme.onSurface,
fontSize: 18,
fontWeight: FontWeight.w600,
),
@@ -187,17 +191,17 @@ class _WriteReviewPageState extends ConsumerState<WriteReviewPage> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icon(
FontAwesomeIcons.circleExclamation,
size: 48,
color: AppColors.danger,
color: colorScheme.error,
),
const SizedBox(height: 16),
Text(
'Không thể tải thông tin sản phẩm',
style: const TextStyle(
style: TextStyle(
fontSize: 16,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
const SizedBox(height: 24),
@@ -213,6 +217,8 @@ class _WriteReviewPageState extends ConsumerState<WriteReviewPage> {
}
Widget _buildForm(Product product) {
final colorScheme = Theme.of(context).colorScheme;
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16),
@@ -223,8 +229,8 @@ class _WriteReviewPageState extends ConsumerState<WriteReviewPage> {
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppColors.white,
border: Border.all(color: const Color(0xFFe0e0e0), width: 2),
color: colorScheme.surface,
border: Border.all(color: colorScheme.outlineVariant, width: 2),
borderRadius: BorderRadius.circular(12),
),
child: Row(
@@ -242,7 +248,7 @@ class _WriteReviewPageState extends ConsumerState<WriteReviewPage> {
placeholder: (context, url) => Container(
width: 80,
height: 80,
color: AppColors.grey100,
color: colorScheme.surfaceContainerLowest,
child: const Center(
child: CircularProgressIndicator(strokeWidth: 2),
),
@@ -250,10 +256,10 @@ class _WriteReviewPageState extends ConsumerState<WriteReviewPage> {
errorWidget: (context, url, error) => Container(
width: 80,
height: 80,
color: AppColors.grey100,
child: const Icon(
color: colorScheme.surfaceContainerLowest,
child: Icon(
FontAwesomeIcons.image,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
),
@@ -268,10 +274,10 @@ class _WriteReviewPageState extends ConsumerState<WriteReviewPage> {
children: [
Text(
product.name,
style: const TextStyle(
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
@@ -279,9 +285,9 @@ class _WriteReviewPageState extends ConsumerState<WriteReviewPage> {
const SizedBox(height: 6),
Text(
'Mã: ${product.productId}',
style: const TextStyle(
style: TextStyle(
fontSize: 13,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
],
@@ -298,27 +304,27 @@ class _WriteReviewPageState extends ConsumerState<WriteReviewPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RichText(
text: const TextSpan(
text: TextSpan(
text: 'Xếp hạng của bạn',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
children: [
TextSpan(
text: ' *',
style: TextStyle(color: AppColors.danger),
style: TextStyle(color: colorScheme.error),
),
],
),
),
const SizedBox(height: 8),
const Text(
Text(
'Bấm vào ngôi sao để chọn đánh giá',
style: TextStyle(
fontSize: 14,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
const SizedBox(height: 16),
@@ -339,17 +345,17 @@ class _WriteReviewPageState extends ConsumerState<WriteReviewPage> {
const SizedBox(height: 8),
Row(
children: [
const Icon(
Icon(
FontAwesomeIcons.triangleExclamation,
size: 14,
color: AppColors.danger,
color: colorScheme.error,
),
const SizedBox(width: 6),
Text(
_ratingError!,
style: const TextStyle(
style: TextStyle(
fontSize: 13,
color: AppColors.danger,
color: colorScheme.error,
),
),
],
@@ -365,17 +371,17 @@ class _WriteReviewPageState extends ConsumerState<WriteReviewPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RichText(
text: const TextSpan(
text: TextSpan(
text: 'Nội dung đánh giá',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
children: [
TextSpan(
text: ' *',
style: TextStyle(color: AppColors.danger),
style: TextStyle(color: colorScheme.error),
),
],
),
@@ -390,38 +396,38 @@ class _WriteReviewPageState extends ConsumerState<WriteReviewPage> {
decoration: InputDecoration(
hintText:
'Chia sẻ trải nghiệm của bạn về sản phẩm này...',
hintStyle: const TextStyle(
hintStyle: TextStyle(
fontSize: 15,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(
color: Color(0xFFe0e0e0),
borderSide: BorderSide(
color: colorScheme.outlineVariant,
width: 2,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(
color: Color(0xFFe0e0e0),
borderSide: BorderSide(
color: colorScheme.outlineVariant,
width: 2,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(
color: AppColors.primaryBlue,
borderSide: BorderSide(
color: colorScheme.primary,
width: 2,
),
),
contentPadding: const EdgeInsets.all(14),
counterText: '', // Hide default counter
),
style: const TextStyle(
style: TextStyle(
fontSize: 15,
height: 1.6,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
onChanged: (value) {
setState(() {
@@ -441,15 +447,15 @@ class _WriteReviewPageState extends ConsumerState<WriteReviewPage> {
style: TextStyle(
fontSize: 13,
color: _contentController.text.length < _minContentLength
? AppColors.danger
: AppColors.grey500,
? colorScheme.error
: colorScheme.onSurfaceVariant,
),
),
Text(
' / $_maxContentLength ký tự',
style: const TextStyle(
style: TextStyle(
fontSize: 13,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
],
@@ -460,18 +466,18 @@ class _WriteReviewPageState extends ConsumerState<WriteReviewPage> {
const SizedBox(height: 6),
Row(
children: [
const Icon(
Icon(
FontAwesomeIcons.triangleExclamation,
size: 14,
color: AppColors.danger,
color: colorScheme.error,
),
const SizedBox(width: 6),
Expanded(
child: Text(
_contentError!,
style: const TextStyle(
style: TextStyle(
fontSize: 13,
color: AppColors.danger,
color: colorScheme.error,
),
),
),
@@ -494,8 +500,9 @@ class _WriteReviewPageState extends ConsumerState<WriteReviewPage> {
child: ElevatedButton(
onPressed: _isSubmitting ? null : _submitReview,
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryBlue,
disabledBackgroundColor: const Color(0xFFe0e0e0),
backgroundColor: colorScheme.primary,
disabledBackgroundColor: colorScheme.outlineVariant,
foregroundColor: colorScheme.onPrimary,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
@@ -503,30 +510,30 @@ class _WriteReviewPageState extends ConsumerState<WriteReviewPage> {
elevation: 0,
),
child: _isSubmitting
? const SizedBox(
? SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor:
AlwaysStoppedAnimation<Color>(AppColors.white),
AlwaysStoppedAnimation<Color>(colorScheme.onPrimary),
),
)
: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icon(
FontAwesomeIcons.paperPlane,
size: 16,
color: AppColors.white,
color: colorScheme.onPrimary,
),
const SizedBox(width: 10),
const Text(
Text(
'Gửi đánh giá',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.white,
color: colorScheme.onPrimary,
),
),
],

View File

@@ -6,7 +6,6 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/theme/colors.dart';
import 'package:worker/features/products/presentation/providers/product_filter_options_provider.dart';
import 'package:worker/features/products/presentation/providers/product_filters_provider.dart';
@@ -20,6 +19,7 @@ class BrandFilterChips extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final colorScheme = Theme.of(context).colorScheme;
final filtersState = ref.watch(productFiltersProvider);
final filterOptionsAsync = ref.watch(productFilterOptionsProvider);
@@ -55,7 +55,7 @@ class BrandFilterChips extends ConsumerWidget {
style: TextStyle(
fontSize: 14.0,
fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
color: isSelected ? AppColors.white : AppColors.grey900,
color: colorScheme.onSurface,
),
),
selected: isSelected,
@@ -84,11 +84,11 @@ class BrandFilterChips extends ConsumerWidget {
}
}
},
backgroundColor: AppColors.white,
selectedColor: AppColors.primaryBlue,
checkmarkColor: AppColors.white,
backgroundColor: colorScheme.surface,
selectedColor: colorScheme.primary,
checkmarkColor: colorScheme.onPrimary,
side: BorderSide(
color: isSelected ? AppColors.primaryBlue : AppColors.grey100,
color: isSelected ? colorScheme.primary : colorScheme.surfaceContainerHighest,
width: isSelected ? 2.0 : 1.0,
),
shape: RoundedRectangleBorder(

View File

@@ -38,7 +38,7 @@ class ProductCard extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = AppLocalizations.of(context);
// final isFavorited = ref.watch(isFavoriteProvider(product.productId));
final colorScheme = Theme.of(context).colorScheme;
return Card(
elevation: ProductCardSpecs.elevation,
@@ -62,23 +62,25 @@ class ProductCard extends ConsumerWidget {
top: Radius.circular(ProductCardSpecs.borderRadius),
),
child: CachedNetworkImage(
imageUrl: product.thumbnail ?? '',
imageUrl: product.thumbnail,
width: double.infinity,
height: double.infinity,
fit: BoxFit.cover,
memCacheWidth: ImageSpecs.productImageCacheWidth,
memCacheHeight: ImageSpecs.productImageCacheHeight,
placeholder: (context, url) => Shimmer.fromColors(
baseColor: AppColors.grey100,
highlightColor: AppColors.grey50,
child: Container(color: AppColors.grey100),
baseColor: colorScheme.surfaceContainerHighest,
highlightColor: colorScheme.surfaceContainerLowest,
child: Container(
color: colorScheme.surfaceContainerHighest,
),
),
errorWidget: (context, url, error) => Container(
color: AppColors.grey100,
child: const Icon(
color: colorScheme.surfaceContainerHighest,
child: Icon(
FontAwesomeIcons.image,
size: 48.0,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
),
@@ -170,7 +172,7 @@ class ProductCard extends ConsumerWidget {
// width: 36,
// height: 36,
// decoration: BoxDecoration(
// color: AppColors.white,
// color: colorScheme.surface,
// shape: BoxShape.circle,
// boxShadow: [
// BoxShadow(
@@ -186,7 +188,7 @@ class ProductCard extends ConsumerWidget {
// : Icons.favorite_border,
// color: isFavorited
// ? AppColors.danger
// : AppColors.grey500,
// : colorScheme.onSurfaceVariant,
// size: 20,
// ),
// ),
@@ -221,10 +223,10 @@ class ProductCard extends ConsumerWidget {
// Price
Text(
'${_formatPrice(product.effectivePrice)}/m²',
style: const TextStyle(
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
color: AppColors.primaryBlue,
color: colorScheme.primary,
),
),
@@ -241,8 +243,8 @@ class ProductCard extends ConsumerWidget {
child: ElevatedButton.icon(
onPressed: onAddToCart,
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryBlue,
foregroundColor: AppColors.white,
backgroundColor: colorScheme.primary,
foregroundColor: colorScheme.onPrimary,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
@@ -254,11 +256,12 @@ class ProductCard extends ConsumerWidget {
),
),
icon: const FaIcon(FontAwesomeIcons.cartShopping, size: 14.0),
label: const Text(
label: Text(
'Thêm vào giỏ',
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.w600,
color: colorScheme.surface
),
),
),
@@ -283,9 +286,9 @@ class ProductCard extends ConsumerWidget {
);
},
style: OutlinedButton.styleFrom(
foregroundColor: AppColors.primaryBlue,
side: const BorderSide(
color: AppColors.primaryBlue,
foregroundColor: colorScheme.primary,
side: BorderSide(
color: colorScheme.primary,
width: 1.5,
),
elevation: 0,
@@ -299,11 +302,12 @@ class ProductCard extends ConsumerWidget {
),
),
icon: const FaIcon(FontAwesomeIcons.cube, size: 14.0),
label: const Text(
label: Text(
'Phối cảnh 360°',
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.w600,
color: colorScheme.onSurface
),
),
),

View File

@@ -8,7 +8,6 @@ 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';
import 'package:worker/features/products/domain/entities/product.dart';
/// Image Gallery Section
@@ -75,10 +74,11 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
final images = widget.product.images;
return Container(
color: AppColors.white,
color: colorScheme.surface,
child: Column(
children: [
// Main Image with PageView
@@ -102,16 +102,16 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
imageUrl: images[index],
fit: BoxFit.cover,
placeholder: (context, url) => Shimmer.fromColors(
baseColor: AppColors.grey100,
highlightColor: AppColors.grey50,
child: Container(color: AppColors.grey100),
baseColor: colorScheme.surfaceContainerHighest,
highlightColor: colorScheme.surface,
child: Container(color: colorScheme.surfaceContainerHighest),
),
errorWidget: (context, url, error) => Container(
color: AppColors.grey100,
child: const Icon(
color: colorScheme.surfaceContainerHighest,
child: Icon(
FontAwesomeIcons.image,
size: 64,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
),
@@ -144,10 +144,10 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
builder: (context, double value, child) {
return Transform.rotate(
angle: value * 2 * 3.14159,
child: const Icon(
child: Icon(
FontAwesomeIcons.arrowsRotate,
size: 10,
color: AppColors.white,
color: colorScheme.surface,
),
);
},
@@ -157,10 +157,10 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
},
),
const SizedBox(width: 6),
const Text(
Text(
'360°',
style: TextStyle(
color: AppColors.white,
color: colorScheme.surface,
fontSize: 12,
fontWeight: FontWeight.w600,
),
@@ -189,8 +189,8 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _currentImageIndex == index
? AppColors.white
: AppColors.white.withAlpha(128),
? colorScheme.surface
: colorScheme.surface.withAlpha(128),
),
),
),
@@ -228,10 +228,10 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
padding: const EdgeInsets.only(bottom: 4),
child: Text(
imageName,
style: const TextStyle(
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w600,
color: AppColors.primaryBlue,
color: colorScheme.primary,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
@@ -246,7 +246,7 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: isActive
? AppColors.primaryBlue
? colorScheme.primary
: Colors.transparent,
width: 2,
),
@@ -257,13 +257,13 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
imageUrl: imageUrl,
fit: BoxFit.cover,
placeholder: (context, url) =>
Container(color: AppColors.grey100),
Container(color: colorScheme.surfaceContainerHighest),
errorWidget: (context, url, error) => Container(
color: AppColors.grey100,
child: const Icon(
color: colorScheme.surfaceContainerHighest,
child: Icon(
FontAwesomeIcons.image,
size: 20,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
),
@@ -336,11 +336,13 @@ class _ImageLightboxState extends State<_ImageLightbox> {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
backgroundColor: Colors.transparent,
foregroundColor: AppColors.white,
foregroundColor: colorScheme.surface,
elevation: 0,
leading: IconButton(
icon: const FaIcon(FontAwesomeIcons.xmark, size: 28),
@@ -348,7 +350,7 @@ class _ImageLightboxState extends State<_ImageLightbox> {
),
title: Text(
'${_currentIndex + 1} / ${widget.images.length}',
style: const TextStyle(color: AppColors.white, fontSize: 16),
style: TextStyle(color: colorScheme.surface, fontSize: 16),
),
),
body: Stack(
@@ -370,9 +372,9 @@ class _ImageLightboxState extends State<_ImageLightbox> {
child: CachedNetworkImage(
imageUrl: widget.images[index],
fit: BoxFit.contain,
errorWidget: (context, url, error) => const Icon(
errorWidget: (context, url, error) => Icon(
FontAwesomeIcons.circleExclamation,
color: AppColors.white,
color: colorScheme.surface,
size: 64,
),
),
@@ -391,9 +393,9 @@ class _ImageLightboxState extends State<_ImageLightbox> {
bottom: 0,
child: Center(
child: IconButton(
icon: const Icon(
icon: Icon(
FontAwesomeIcons.chevronLeft,
color: AppColors.white,
color: colorScheme.surface,
size: 32,
),
onPressed: _previousImage,
@@ -412,9 +414,9 @@ class _ImageLightboxState extends State<_ImageLightbox> {
bottom: 0,
child: Center(
child: IconButton(
icon: const Icon(
icon: Icon(
FontAwesomeIcons.chevronRight,
color: AppColors.white,
color: colorScheme.surface,
size: 32,
),
onPressed: _nextImage,
@@ -443,7 +445,7 @@ class _ImageLightboxState extends State<_ImageLightbox> {
),
child: Text(
widget.imageCaptions[widget.images[_currentIndex]] ?? '',
style: const TextStyle(color: AppColors.white, fontSize: 16),
style: TextStyle(color: colorScheme.surface, fontSize: 16),
textAlign: TextAlign.center,
),
),

View File

@@ -29,8 +29,10 @@ class ProductInfoSection extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Container(
color: AppColors.white,
color: colorScheme.surface,
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -38,7 +40,7 @@ class ProductInfoSection extends StatelessWidget {
// SKU
Text(
'SKU: ${product.erpnextItemCode ?? product.productId}',
style: const TextStyle(fontSize: 12, color: AppColors.grey500),
style: TextStyle(fontSize: 12, color: colorScheme.onSurfaceVariant),
),
const SizedBox(height: 8),
@@ -46,10 +48,10 @@ class ProductInfoSection extends StatelessWidget {
// Product Title
Text(
product.name,
style: const TextStyle(
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w700,
color: AppColors.grey900,
color: colorScheme.onSurface,
height: 1.3,
),
),
@@ -62,10 +64,10 @@ class ProductInfoSection extends StatelessWidget {
// Current Price
Text(
'${_formatPrice(product.basePrice)}/m²',
style: const TextStyle(
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.w700,
color: AppColors.primaryBlue,
color: colorScheme.primary,
),
),
@@ -74,9 +76,9 @@ class ProductInfoSection extends StatelessWidget {
const SizedBox(width: 12),
Text(
_formatPrice(product.basePrice * 1.12), // Mock original price
style: const TextStyle(
style: TextStyle(
fontSize: 16,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
decoration: TextDecoration.lineThrough,
),
),
@@ -95,8 +97,8 @@ class ProductInfoSection extends StatelessWidget {
),
child: Text(
'-${product.discountPercentage}%',
style: const TextStyle(
color: AppColors.white,
style: TextStyle(
color: colorScheme.surface,
fontSize: 12,
fontWeight: FontWeight.w600,
),
@@ -109,10 +111,10 @@ class ProductInfoSection extends StatelessWidget {
const SizedBox(height: 16),
// Rating & Reviews Section
const Row(
Row(
children: [
// Rating Stars
Row(
const Row(
children: [
Icon(FontAwesomeIcons.solidStar, color: Color(0xFFffc107), size: 16),
SizedBox(width: 2),
@@ -126,14 +128,14 @@ class ProductInfoSection extends StatelessWidget {
],
),
SizedBox(width: 12),
const SizedBox(width: 12),
// Rating Text
Text(
'4.8 (125 đánh giá)',
style: TextStyle(
fontSize: 14,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
],
@@ -142,9 +144,9 @@ class ProductInfoSection extends StatelessWidget {
const SizedBox(height: 16),
// Intro attributes quick info cards (dynamic based on non-null values)
if (_buildIntroAttributeCards(product).isNotEmpty)
if (_buildIntroAttributeCards(product, colorScheme).isNotEmpty)
Row(
children: _buildIntroAttributeCards(product),
children: _buildIntroAttributeCards(product, colorScheme),
),
],
),
@@ -152,7 +154,7 @@ class ProductInfoSection extends StatelessWidget {
}
/// Build intro attribute cards dynamically based on non-null values
List<Widget> _buildIntroAttributeCards(Product product) {
List<Widget> _buildIntroAttributeCards(Product product, ColorScheme colorScheme) {
final cards = <Widget>[];
// Define available intro attributes with their display info
@@ -184,6 +186,7 @@ class ProductInfoSection extends StatelessWidget {
icon: attr['icon'] as IconData,
label: attr['label'] as String,
value: value,
colorScheme: colorScheme,
),
),
);
@@ -210,30 +213,32 @@ class _QuickInfoCard extends StatelessWidget {
required this.icon,
required this.label,
required this.value,
required this.colorScheme,
});
final IconData icon;
final String label;
final String value;
final ColorScheme colorScheme;
@override
Widget build(BuildContext context) {
return Column(
children: [
Icon(icon, color: AppColors.primaryBlue, size: 24),
Icon(icon, color: colorScheme.primary, size: 24),
const SizedBox(height: 4),
Text(
label,
style: const TextStyle(fontSize: 12, color: AppColors.grey500),
style: TextStyle(fontSize: 12, color: colorScheme.onSurfaceVariant),
textAlign: TextAlign.center,
),
const SizedBox(height: 2),
Text(
value,
style: const TextStyle(
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
textAlign: TextAlign.center,
),

View File

@@ -50,21 +50,23 @@ class _ProductTabsSectionState extends State<ProductTabsSection>
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Container(
color: AppColors.white,
color: colorScheme.surface,
child: Column(
children: [
// Tab Navigation
Container(
decoration: const BoxDecoration(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Color(0xFFe0e0e0), width: 1),
bottom: BorderSide(color: colorScheme.outlineVariant, width: 1),
),
),
child: TabBar(
controller: _tabController,
labelColor: AppColors.primaryBlue,
unselectedLabelColor: AppColors.grey500,
labelColor: colorScheme.primary,
unselectedLabelColor: colorScheme.onSurfaceVariant,
labelStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
@@ -73,7 +75,7 @@ class _ProductTabsSectionState extends State<ProductTabsSection>
fontSize: 14,
fontWeight: FontWeight.w500,
),
indicatorColor: AppColors.primaryBlue,
indicatorColor: colorScheme.primary,
indicatorWeight: 2,
tabs: const [
Tab(text: 'Thông số'),
@@ -104,18 +106,20 @@ class _DescriptionTab extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Main description
const Text(
Text(
'Bộ sưu tập Cao cấp',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
const SizedBox(height: 12),
@@ -123,22 +127,22 @@ class _DescriptionTab extends StatelessWidget {
Text(
product.description ??
'Sản phẩm gạch cao cấp với chất lượng vượt trội, mang đến vẻ đẹp tự nhiên và sang trọng cho không gian của bạn. Với bề mặt có texture tinh tế, sản phẩm tạo nên những đường vân tự nhiên chân thực.',
style: const TextStyle(
style: TextStyle(
fontSize: 14,
height: 1.6,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
const SizedBox(height: 20),
// Features heading
const Text(
Text(
'Đặc điểm nổi bật:',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
const SizedBox(height: 12),
@@ -165,9 +169,9 @@ class _DescriptionTab extends StatelessWidget {
Expanded(
child: Text(
feature,
style: const TextStyle(
style: TextStyle(
fontSize: 14,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
),
@@ -179,22 +183,22 @@ class _DescriptionTab extends StatelessWidget {
const SizedBox(height: 20),
// Application section
const Text(
Text(
'Ứng dụng:',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
const SizedBox(height: 12),
const Text(
Text(
'Phù hợp cho phòng khách, phòng ngủ, hành lang, văn phòng và các không gian thương mại. Đặc biệt phù hợp với phong cách nội thất hiện đại, tối giản và Scandinavian.',
style: TextStyle(
fontSize: 14,
height: 1.6,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
],
@@ -211,6 +215,8 @@ class _SpecificationsTab extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
// Default specifications if not available
final specs = product.specifications.isNotEmpty
? product.specifications
@@ -230,15 +236,15 @@ class _SpecificationsTab extends StatelessWidget {
return Container(
margin: const EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border.all(color: const Color(0xFFe0e0e0)),
border: Border.all(color: colorScheme.outlineVariant),
borderRadius: BorderRadius.circular(8),
),
child: Column(
children: [
Container(
decoration: const BoxDecoration(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Color(0xFFe0e0e0)),
bottom: BorderSide(color: colorScheme.outlineVariant),
),
),
child: IntrinsicHeight(
@@ -249,15 +255,15 @@ class _SpecificationsTab extends StatelessWidget {
Expanded(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
color: const Color(0xFFF4F6F8),
color: colorScheme.surface,
child: Align(
alignment: Alignment.centerLeft,
child: Text(
"Thương hiệu",
style: const TextStyle(
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColors.grey900,
color: colorScheme.onSurface,
height: 1.5,
),
),
@@ -268,7 +274,7 @@ class _SpecificationsTab extends StatelessWidget {
// Divider
Container(
width: 1,
color: const Color(0xFFe0e0e0),
color: colorScheme.outlineVariant,
),
// Value
@@ -277,9 +283,9 @@ class _SpecificationsTab extends StatelessWidget {
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
child: Text(
'${product.brand}',
style: const TextStyle(
style: TextStyle(
fontSize: 14,
color: AppColors.grey900,
color: colorScheme.onSurface,
height: 1.5,
),
softWrap: true,
@@ -291,9 +297,9 @@ class _SpecificationsTab extends StatelessWidget {
),
),
Container(
decoration: const BoxDecoration(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Color(0xFFe0e0e0)),
bottom: BorderSide(color: colorScheme.outlineVariant),
),
),
child: IntrinsicHeight(
@@ -304,15 +310,15 @@ class _SpecificationsTab extends StatelessWidget {
Expanded(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
color: const Color(0xFFF4F6F8),
child: const Align(
color: colorScheme.surface,
child: Align(
alignment: Alignment.centerLeft,
child: Text(
"Dòng sản phẩm",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColors.grey900,
color: colorScheme.onSurface,
height: 1.5,
),
),
@@ -323,7 +329,7 @@ class _SpecificationsTab extends StatelessWidget {
// Divider
Container(
width: 1,
color: const Color(0xFFe0e0e0),
color: colorScheme.outlineVariant,
),
// Value
@@ -332,9 +338,9 @@ class _SpecificationsTab extends StatelessWidget {
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
child: Text(
'${product.itemGroupName}',
style: const TextStyle(
style: TextStyle(
fontSize: 14,
color: AppColors.grey900,
color: colorScheme.onSurface,
height: 1.5,
),
softWrap: true,
@@ -351,8 +357,8 @@ class _SpecificationsTab extends StatelessWidget {
decoration: BoxDecoration(
border: isLast
? null
: const Border(
bottom: BorderSide(color: Color(0xFFe0e0e0)),
: Border(
bottom: BorderSide(color: colorScheme.outlineVariant),
),
),
child: IntrinsicHeight(
@@ -363,15 +369,15 @@ class _SpecificationsTab extends StatelessWidget {
Expanded(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
color: const Color(0xFFF4F6F8),
color: colorScheme.surface,
child: Align(
alignment: Alignment.centerLeft,
child: Text(
entry.key,
style: const TextStyle(
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColors.grey900,
color: colorScheme.onSurface,
height: 1.5,
),
),
@@ -382,7 +388,7 @@ class _SpecificationsTab extends StatelessWidget {
// Divider
Container(
width: 1,
color: const Color(0xFFe0e0e0),
color: colorScheme.outlineVariant,
),
// Value
@@ -391,9 +397,9 @@ class _SpecificationsTab extends StatelessWidget {
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
child: Text(
'${entry.value}',
style: const TextStyle(
style: TextStyle(
fontSize: 14,
color: AppColors.grey900,
color: colorScheme.onSurface,
height: 1.5,
),
softWrap: true,
@@ -419,6 +425,7 @@ class _ReviewsTab extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final colorScheme = Theme.of(context).colorScheme;
final reviewsAsync = ref.watch(productReviewsProvider(productId));
final avgRatingAsync = ref.watch(productAverageRatingProvider(productId));
@@ -437,7 +444,7 @@ class _ReviewsTab extends ConsumerWidget {
data: (reviews) {
if (reviews.isEmpty) {
// Empty state
return _buildEmptyState();
return _buildEmptyState(colorScheme);
}
return Column(
@@ -445,9 +452,9 @@ class _ReviewsTab extends ConsumerWidget {
children: [
// Rating Overview
avgRatingAsync.when(
data: (avgRating) => _buildRatingOverview(reviews, avgRating),
loading: () => _buildRatingOverview(reviews, 0),
error: (_, __) => _buildRatingOverview(reviews, 0),
data: (avgRating) => _buildRatingOverview(colorScheme, reviews, avgRating),
loading: () => _buildRatingOverview(colorScheme, reviews, 0),
error: (_, __) => _buildRatingOverview(colorScheme, reviews, 0),
),
const SizedBox(height: 24),
@@ -459,22 +466,22 @@ class _ReviewsTab extends ConsumerWidget {
],
);
},
loading: () => const Center(
loading: () => Center(
child: Padding(
padding: EdgeInsets.all(40),
padding: const EdgeInsets.all(40),
child: CircularProgressIndicator(
color: AppColors.primaryBlue,
color: colorScheme.primary,
),
),
),
error: (error, stack) => _buildErrorState(error.toString()),
error: (error, stack) => _buildErrorState(colorScheme, error.toString()),
),
],
),
);
}
Widget _buildRatingOverview(List<Review> reviews, double avgRating) {
Widget _buildRatingOverview(ColorScheme colorScheme, List<Review> reviews, double avgRating) {
return Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
@@ -486,10 +493,10 @@ class _ReviewsTab extends ConsumerWidget {
// Rating Score
Text(
avgRating.toStringAsFixed(2),
style: const TextStyle(
style: TextStyle(
fontSize: 36,
fontWeight: FontWeight.w700,
color: AppColors.primaryBlue,
color: colorScheme.primary,
),
),
@@ -505,19 +512,19 @@ class _ReviewsTab extends ConsumerWidget {
if (index < avgRating.floor()) {
return const Icon(
FontAwesomeIcons.solidStar,
color: Color(0xFFffc107),
color: AppColors.warning,
size: 18,
);
} else if (index < avgRating) {
return const Icon(
FontAwesomeIcons.starHalfStroke,
color: Color(0xFFffc107),
color: AppColors.warning,
size: 18,
);
} else {
return const Icon(
FontAwesomeIcons.star,
color: Color(0xFFffc107),
color: AppColors.warning,
size: 18,
);
}
@@ -529,9 +536,9 @@ class _ReviewsTab extends ConsumerWidget {
// Review count
Text(
'${reviews.length} đánh giá',
style: const TextStyle(
style: TextStyle(
fontSize: 14,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
],
@@ -541,33 +548,33 @@ class _ReviewsTab extends ConsumerWidget {
);
}
Widget _buildEmptyState() {
return const Center(
Widget _buildEmptyState(ColorScheme colorScheme) {
return Center(
child: Padding(
padding: EdgeInsets.all(40),
padding: const EdgeInsets.all(40),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
FontAwesomeIcons.commentSlash,
size: 48,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
SizedBox(height: 16),
const SizedBox(height: 16),
Text(
'Chưa có đánh giá nào',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
SizedBox(height: 8),
const SizedBox(height: 8),
Text(
'Hãy là người đầu tiên đánh giá sản phẩm này',
style: TextStyle(
fontSize: 14,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
textAlign: TextAlign.center,
),
@@ -577,7 +584,7 @@ class _ReviewsTab extends ConsumerWidget {
);
}
Widget _buildErrorState(String error) {
Widget _buildErrorState(ColorScheme colorScheme, String error) {
return Center(
child: Padding(
padding: const EdgeInsets.all(40),
@@ -590,20 +597,20 @@ class _ReviewsTab extends ConsumerWidget {
color: AppColors.danger,
),
const SizedBox(height: 16),
const Text(
Text(
'Không thể tải đánh giá',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
const SizedBox(height: 8),
Text(
error.length > 100 ? '${error.substring(0, 100)}...' : error,
style: const TextStyle(
style: TextStyle(
fontSize: 13,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
textAlign: TextAlign.center,
),
@@ -622,11 +629,13 @@ class _ReviewItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Container(
padding: const EdgeInsets.only(bottom: 16),
margin: const EdgeInsets.only(bottom: 16),
decoration: const BoxDecoration(
border: Border(bottom: BorderSide(color: Color(0xFFe0e0e0))),
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: colorScheme.outlineVariant)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -642,9 +651,9 @@ class _ReviewItem extends StatelessWidget {
shape: BoxShape.circle,
color: Color(0xFFF4F6F8),
),
child: const Icon(
child: Icon(
FontAwesomeIcons.solidUser,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
size: 20,
),
),
@@ -658,17 +667,17 @@ class _ReviewItem extends StatelessWidget {
children: [
Text(
review.reviewerName ?? 'Người dùng',
style: const TextStyle(
style: TextStyle(
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
if (review.reviewDate != null)
Text(
_formatDate(review.reviewDate!),
style: const TextStyle(
style: TextStyle(
fontSize: 12,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
],
@@ -687,7 +696,7 @@ class _ReviewItem extends StatelessWidget {
index < review.starsRating
? FontAwesomeIcons.solidStar
: FontAwesomeIcons.star,
color: const Color(0xFFffc107),
color: AppColors.warning,
size: 14,
),
),
@@ -698,10 +707,10 @@ class _ReviewItem extends StatelessWidget {
// Review Text
Text(
review.comment,
style: const TextStyle(
style: TextStyle(
fontSize: 14,
height: 1.5,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
],

View File

@@ -7,7 +7,6 @@ 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';
/// Sticky Action Bar
///
@@ -61,11 +60,13 @@ class StickyActionBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Container(
decoration: BoxDecoration(
color: AppColors.white,
border: const Border(
top: BorderSide(color: Color(0xFFe0e0e0), width: 1),
color: colorScheme.surface,
border: Border(
top: BorderSide(color: colorScheme.outlineVariant, width: 1),
),
boxShadow: [
BoxShadow(
@@ -88,9 +89,9 @@ class StickyActionBar extends StatelessWidget {
// Label
Text(
'Số lượng ($unit)',
style: const TextStyle(
style: TextStyle(
fontSize: 12,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
fontWeight: FontWeight.w500,
),
),
@@ -101,7 +102,7 @@ class StickyActionBar extends StatelessWidget {
Container(
width: 142,
decoration: BoxDecoration(
border: Border.all(color: const Color(0xFFe0e0e0)),
border: Border.all(color: colorScheme.outlineVariant),
borderRadius: BorderRadius.circular(8),
),
child: Row(
@@ -152,9 +153,9 @@ class StickyActionBar extends StatelessWidget {
if (_getConversionText().isNotEmpty)
Text(
_getConversionText(),
style: const TextStyle(
style: TextStyle(
fontSize: 11,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
],
@@ -167,8 +168,8 @@ class StickyActionBar extends StatelessWidget {
child: ElevatedButton.icon(
onPressed: onAddToCart,
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryBlue,
foregroundColor: AppColors.white,
backgroundColor: colorScheme.primary,
foregroundColor: colorScheme.onPrimary,
elevation: 0,
padding: const EdgeInsets.symmetric(
horizontal: 12,
@@ -179,11 +180,12 @@ class StickyActionBar extends StatelessWidget {
),
),
icon: const FaIcon(FontAwesomeIcons.cartShopping, size: 18),
label: const Text(
label: Text(
'Thêm vào giỏ hàng',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: colorScheme.onSurface
),
),
),
@@ -204,17 +206,19 @@ class _QuantityButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return SizedBox(
width: 40,
height: 40,
child: Material(
color: const Color(0xFFF4F6F8),
color: colorScheme.surfaceContainerHighest,
child: InkWell(
onTap: onPressed,
child: Icon(
icon,
size: 20,
color: onPressed != null ? AppColors.grey900 : AppColors.grey500,
color: onPressed != null ? colorScheme.onSurface : colorScheme.onSurfaceVariant,
),
),
),

View File

@@ -6,12 +6,11 @@ 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/theme/colors.dart';
/// Write Review Button
///
/// Displays a prominent button for users to write a review:
/// - Primary blue background
/// - Primary background from theme
/// - Edit icon
/// - Text: "Viết đánh giá của bạn"
/// - Navigates to WriteReviewPage with productId
@@ -26,6 +25,8 @@ class WriteReviewButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Container(
width: double.infinity,
margin: const EdgeInsets.only(bottom: 20),
@@ -35,28 +36,28 @@ class WriteReviewButton extends StatelessWidget {
context.push('/products/$productId/write-review');
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryBlue,
backgroundColor: colorScheme.primary,
padding: const EdgeInsets.symmetric(vertical: 14, horizontal: 28),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
elevation: 0,
),
child: const Row(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
FontAwesomeIcons.penToSquare,
size: 16,
color: AppColors.white,
color: colorScheme.onPrimary,
),
SizedBox(width: 10),
const SizedBox(width: 10),
Text(
'Viết đánh giá của bạn',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.white,
color: colorScheme.onPrimary,
),
),
],

View File

@@ -24,6 +24,7 @@ class ProductFilterDrawer extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final colorScheme = Theme.of(context).colorScheme;
final filtersState = ref.watch(productFiltersProvider);
final filterOptionsAsync = ref.watch(productFilterOptionsProvider);
@@ -35,26 +36,26 @@ class ProductFilterDrawer extends ConsumerWidget {
// Header
Container(
padding: const EdgeInsets.all(AppSpacing.lg),
decoration: const BoxDecoration(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: AppColors.grey100, width: 1),
bottom: BorderSide(color: colorScheme.outlineVariant, width: 1),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
Text(
'Bộ lọc sản phẩm',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
IconButton(
icon: const FaIcon(FontAwesomeIcons.xmark, size: 20),
onPressed: () => Navigator.of(context).pop(),
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
],
),
@@ -69,6 +70,7 @@ class ProductFilterDrawer extends ConsumerWidget {
children: [
// Nhóm sản phẩm (Item Groups) - from API
_buildFilterGroup(
context: context,
title: 'Nhóm sản phẩm',
options: filterOptions.groups,
initiallyExpanded: true,
@@ -82,6 +84,7 @@ class ProductFilterDrawer extends ConsumerWidget {
// Thương hiệu (Brands) - from API
_buildFilterGroup(
context: context,
title: 'Thương hiệu',
options: filterOptions.brands,
selectedValues: filtersState.brands,
@@ -103,6 +106,7 @@ class ProductFilterDrawer extends ConsumerWidget {
return Column(
children: [
_buildAttributeGroup(
context: context,
title: attrGroup.attributeName,
attributeGroup: attrGroup,
selectedValues: selectedValues,
@@ -126,9 +130,9 @@ class ProductFilterDrawer extends ConsumerWidget {
// Footer Buttons
Container(
padding: const EdgeInsets.all(AppSpacing.lg),
decoration: const BoxDecoration(
decoration: BoxDecoration(
border: Border(
top: BorderSide(color: AppColors.grey100, width: 1),
top: BorderSide(color: colorScheme.outlineVariant, width: 1),
),
),
child: Row(
@@ -140,9 +144,9 @@ class ProductFilterDrawer extends ConsumerWidget {
ref.read(productFiltersProvider.notifier).reset();
},
style: OutlinedButton.styleFrom(
foregroundColor: AppColors.grey900,
side: const BorderSide(
color: AppColors.grey100,
foregroundColor: colorScheme.onSurface,
side: BorderSide(
color: colorScheme.outlineVariant,
width: 1,
),
padding: const EdgeInsets.symmetric(
@@ -181,8 +185,8 @@ class ProductFilterDrawer extends ConsumerWidget {
}
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryBlue,
foregroundColor: AppColors.white,
backgroundColor: colorScheme.primary,
foregroundColor: colorScheme.onPrimary,
elevation: 0,
padding: const EdgeInsets.symmetric(
vertical: AppSpacing.md,
@@ -205,9 +209,9 @@ class ProductFilterDrawer extends ConsumerWidget {
),
],
),
loading: () => const Center(
loading: () => Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(AppColors.primaryBlue),
valueColor: AlwaysStoppedAnimation<Color>(colorScheme.primary),
),
),
error: (error, stack) => Center(
@@ -222,20 +226,20 @@ class ProductFilterDrawer extends ConsumerWidget {
color: AppColors.danger,
),
const SizedBox(height: AppSpacing.md),
const Text(
Text(
'Không thể tải bộ lọc',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
const SizedBox(height: AppSpacing.sm),
Text(
error.toString(),
style: const TextStyle(
style: TextStyle(
fontSize: 14,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
textAlign: TextAlign.center,
),
@@ -245,8 +249,8 @@ class ProductFilterDrawer extends ConsumerWidget {
ref.invalidate(productFilterOptionsProvider);
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryBlue,
foregroundColor: AppColors.white,
backgroundColor: colorScheme.primary,
foregroundColor: colorScheme.onPrimary,
),
child: const Text('Thử lại'),
),
@@ -260,12 +264,15 @@ class ProductFilterDrawer extends ConsumerWidget {
}
Widget _buildFilterGroup({
required BuildContext context,
required String title,
required List<FilterOption> options,
required Set<String> selectedValues,
required Function(String) onToggle,
bool initiallyExpanded = false,
}) {
final colorScheme = Theme.of(context).colorScheme;
return Theme(
data: ThemeData(
dividerColor: Colors.transparent,
@@ -277,10 +284,10 @@ class ProductFilterDrawer extends ConsumerWidget {
childrenPadding: const EdgeInsets.only(left: 8),
title: Text(
title,
style: const TextStyle(
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
initiallyExpanded: initiallyExpanded,
@@ -288,9 +295,9 @@ class ProductFilterDrawer extends ConsumerWidget {
return CheckboxListTile(
title: Text(
option.label,
style: const TextStyle(
style: TextStyle(
fontSize: 14,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
value: selectedValues.contains(option.value),
@@ -300,7 +307,7 @@ class ProductFilterDrawer extends ConsumerWidget {
controlAffinity: ListTileControlAffinity.leading,
contentPadding: EdgeInsets.zero,
dense: true,
activeColor: AppColors.primaryBlue,
activeColor: colorScheme.primary,
);
}).toList(),
),
@@ -308,11 +315,14 @@ class ProductFilterDrawer extends ConsumerWidget {
}
Widget _buildAttributeGroup({
required BuildContext context,
required String title,
required AttributeGroup attributeGroup,
required Set<String> selectedValues,
required Function(String) onToggle,
}) {
final colorScheme = Theme.of(context).colorScheme;
return Theme(
data: ThemeData(
dividerColor: Colors.transparent,
@@ -324,10 +334,10 @@ class ProductFilterDrawer extends ConsumerWidget {
childrenPadding: const EdgeInsets.only(left: 8),
title: Text(
title,
style: const TextStyle(
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
initiallyExpanded: false,
@@ -335,17 +345,17 @@ class ProductFilterDrawer extends ConsumerWidget {
return CheckboxListTile(
title: Text(
value.attributeValue,
style: const TextStyle(
style: TextStyle(
fontSize: 14,
color: AppColors.grey900,
color: colorScheme.onSurface,
),
),
// subtitle: value.abbr != null
// ? Text(
// 'Mã: ${value.abbr}',
// style: const TextStyle(
// style: TextStyle(
// fontSize: 12,
// color: AppColors.grey500,
// color: colorScheme.onSurfaceVariant,
// ),
// )
// : null,
@@ -356,7 +366,7 @@ class ProductFilterDrawer extends ConsumerWidget {
controlAffinity: ListTileControlAffinity.leading,
contentPadding: EdgeInsets.zero,
dense: true,
activeColor: AppColors.primaryBlue,
activeColor: colorScheme.primary,
);
}).toList(),
),

View File

@@ -11,6 +11,7 @@ import 'package:worker/features/products/presentation/widgets/product_card.dart'
/// Product Grid Widget
///
/// Displays products in a 2-column grid layout with scroll-to-load-more.
/// Fully theme-compliant using Material 3 ColorScheme.
class ProductGrid extends StatefulWidget {
final List<Product> products;
final void Function(Product)? onProductTap;
@@ -61,6 +62,8 @@ class _ProductGridState extends State<ProductGrid> {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return GridView.builder(
controller: _scrollController,
padding: const EdgeInsets.all(AppSpacing.xs),
@@ -74,10 +77,12 @@ class _ProductGridState extends State<ProductGrid> {
itemBuilder: (context, index) {
// Show loading indicator at the end
if (index == widget.products.length) {
return const Center(
return Center(
child: Padding(
padding: EdgeInsets.all(AppSpacing.md),
child: CircularProgressIndicator(),
padding: const EdgeInsets.all(AppSpacing.md),
child: CircularProgressIndicator(
color: colorScheme.primary,
),
),
);
}

View File

@@ -7,7 +7,6 @@ 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';
import 'package:worker/generated/l10n/app_localizations.dart';
@@ -62,6 +61,7 @@ class _ProductSearchBarState extends ConsumerState<ProductSearchBar> {
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context);
final colorScheme = Theme.of(context).colorScheme;
return SizedBox(
height: InputFieldSpecs.height,
@@ -71,27 +71,27 @@ class _ProductSearchBarState extends ConsumerState<ProductSearchBar> {
onChanged: _onSearchChanged,
decoration: InputDecoration(
hintText: l10n.searchProducts,
hintStyle: const TextStyle(
hintStyle: TextStyle(
fontSize: InputFieldSpecs.hintFontSize,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
prefixIcon: const Icon(
prefixIcon: Icon(
FontAwesomeIcons.magnifyingGlass,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
size: AppIconSize.md,
),
suffixIcon: _hasText
? IconButton(
icon: const Icon(
icon: Icon(
FontAwesomeIcons.xmark,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
size: AppIconSize.md,
),
onPressed: _onClearSearch,
)
: null,
filled: true,
fillColor: Colors.white,
fillColor: colorScheme.surface,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(InputFieldSpecs.borderRadius),
borderSide: BorderSide.none,
@@ -102,8 +102,8 @@ class _ProductSearchBarState extends ConsumerState<ProductSearchBar> {
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(InputFieldSpecs.borderRadius),
borderSide: const BorderSide(
color: AppColors.primaryBlue,
borderSide: BorderSide(
color: colorScheme.primary,
width: 2.0,
),
),

View File

@@ -5,21 +5,17 @@ library;
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/theme/colors.dart';
/// Review Guidelines Card Widget
///
/// Displays helpful tips for writing product reviews:
/// - Light blue background (#f0f7ff)
/// - Blue left border
/// - Light blue background (colorScheme.primaryContainer)
/// - Blue left border (colorScheme.primary)
/// - Lightbulb icon
/// - 4 bullet points with guidelines
class ReviewGuidelinesCard extends StatelessWidget {
const ReviewGuidelinesCard({super.key});
// Guidelines background color
static const Color _backgroundColor = Color(0xFFF0F7FF);
// Guidelines list
static const List<String> _guidelines = [
'Chia sẻ trải nghiệm thực tế của bạn về sản phẩm',
@@ -30,14 +26,16 @@ class ReviewGuidelinesCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: _backgroundColor,
color: colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(8),
border: const Border(
border: Border(
left: BorderSide(
color: AppColors.primaryBlue,
color: colorScheme.primary,
width: 4,
),
),
@@ -46,20 +44,20 @@ class ReviewGuidelinesCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header
const Row(
Row(
children: [
Icon(
FontAwesomeIcons.lightbulb,
size: 16,
color: AppColors.primaryBlue,
color: colorScheme.primary,
),
SizedBox(width: 8),
const SizedBox(width: 8),
Text(
'Gợi ý viết đánh giá tốt',
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
color: AppColors.primaryBlue,
color: colorScheme.primary,
),
),
],
@@ -76,20 +74,20 @@ class ReviewGuidelinesCard extends StatelessWidget {
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
Text(
'',
style: TextStyle(
fontSize: 14,
color: AppColors.grey900,
color: colorScheme.onSurface,
height: 1.6,
),
),
Expanded(
child: Text(
_guidelines[index],
style: const TextStyle(
style: TextStyle(
fontSize: 14,
color: AppColors.grey900,
color: colorScheme.onSurface,
height: 1.6,
),
),

View File

@@ -6,7 +6,6 @@ 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';
/// Star Rating Selector Widget
///
@@ -44,7 +43,7 @@ class _StarRatingSelectorState extends State<StarRatingSelector> {
5: 'Rất hài lòng',
};
// Colors
// Star colors (semantic - keep as AppColors)
static const Color _starUnselected = Color(0xFFe0e0e0);
static const Color _starHover = Color(0xFFffc107);
static const Color _starSelected = Color(0xFFff9800);
@@ -54,6 +53,8 @@ class _StarRatingSelectorState extends State<StarRatingSelector> {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Column(
children: [
// Stars Row
@@ -99,7 +100,7 @@ class _StarRatingSelectorState extends State<StarRatingSelector> {
decoration: BoxDecoration(
color: widget.rating > 0
? _labelBackgroundSelected
: AppColors.grey50,
: colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(20),
),
child: Text(
@@ -107,7 +108,7 @@ class _StarRatingSelectorState extends State<StarRatingSelector> {
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
color: widget.rating > 0 ? _starSelected : AppColors.grey500,
color: widget.rating > 0 ? _starSelected : colorScheme.onSurfaceVariant,
),
),
),