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

@@ -9,7 +9,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/news/domain/entities/blog_category.dart';
import 'package:worker/features/news/presentation/providers/news_provider.dart';
@@ -42,14 +41,14 @@ class CategoryFilterChips extends ConsumerWidget {
final categoriesAsync = ref.watch(blogCategoriesProvider);
return categoriesAsync.when(
data: (categories) => _buildCategoryChips(categories),
loading: () => _buildLoadingState(),
error: (error, stack) => _buildErrorState(error, ref),
data: (categories) => _buildCategoryChips(context, categories),
loading: () => _buildLoadingState(context),
error: (error, stack) => _buildErrorState(context, error, ref),
);
}
/// Build category chips with data
Widget _buildCategoryChips(List<BlogCategory> categories) {
Widget _buildCategoryChips(BuildContext context, List<BlogCategory> categories) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.md),
@@ -57,6 +56,7 @@ class CategoryFilterChips extends ConsumerWidget {
children: [
// "Tất cả" chip
_buildCategoryChip(
context,
label: 'Tất cả',
isSelected: selectedCategoryName == null,
onTap: () => onCategorySelected(null),
@@ -69,6 +69,7 @@ class CategoryFilterChips extends ConsumerWidget {
return Padding(
padding: const EdgeInsets.only(right: AppSpacing.sm),
child: _buildCategoryChip(
context,
label: category.title,
isSelected: selectedCategoryName == category.name,
onTap: () => onCategorySelected(category.name),
@@ -81,7 +82,9 @@ class CategoryFilterChips extends ConsumerWidget {
}
/// Build loading state with shimmer placeholders
Widget _buildLoadingState() {
Widget _buildLoadingState(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.md),
@@ -93,7 +96,7 @@ class CategoryFilterChips extends ConsumerWidget {
width: 80,
height: 32,
decoration: BoxDecoration(
color: AppColors.grey100,
color: colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(24),
),
),
@@ -104,7 +107,9 @@ class CategoryFilterChips extends ConsumerWidget {
}
/// Build error state with retry
Widget _buildErrorState(Object error, WidgetRef ref) {
Widget _buildErrorState(BuildContext context, Object error, WidgetRef ref) {
final colorScheme = Theme.of(context).colorScheme;
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.md),
@@ -116,25 +121,25 @@ class CategoryFilterChips extends ConsumerWidget {
vertical: AppSpacing.sm,
),
decoration: BoxDecoration(
color: AppColors.grey100,
color: colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(24),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
FaIcon(FontAwesomeIcons.circleExclamation, size: 16, color: AppColors.grey500),
FaIcon(FontAwesomeIcons.circleExclamation, size: 16, color: colorScheme.onSurfaceVariant),
const SizedBox(width: AppSpacing.xs),
Text(
'Lỗi tải danh mục',
style: TextStyle(
fontSize: 14,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
const SizedBox(width: AppSpacing.xs),
GestureDetector(
onTap: () => ref.refresh(blogCategoriesProvider),
child: FaIcon(FontAwesomeIcons.arrowsRotate, size: 14, color: AppColors.primaryBlue),
child: FaIcon(FontAwesomeIcons.arrowsRotate, size: 14, color: colorScheme.primary),
),
],
),
@@ -145,11 +150,14 @@ class CategoryFilterChips extends ConsumerWidget {
}
/// Build individual category chip
Widget _buildCategoryChip({
Widget _buildCategoryChip(
BuildContext context, {
required String label,
required bool isSelected,
required VoidCallback onTap,
}) {
final colorScheme = Theme.of(context).colorScheme;
return GestureDetector(
onTap: onTap,
child: Container(
@@ -158,7 +166,7 @@ class CategoryFilterChips extends ConsumerWidget {
vertical: AppSpacing.sm,
),
decoration: BoxDecoration(
color: isSelected ? AppColors.primaryBlue : AppColors.grey100,
color: isSelected ? colorScheme.primary : colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(24),
),
child: Text(
@@ -166,7 +174,7 @@ class CategoryFilterChips extends ConsumerWidget {
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: isSelected ? Colors.white : AppColors.grey500,
color: isSelected ? colorScheme.onPrimary : colorScheme.onSurfaceVariant,
),
),
),

View File

@@ -8,7 +8,6 @@ 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';
/// Featured News Card
@@ -32,14 +31,16 @@ class FeaturedNewsCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return GestureDetector(
onTap: onTap,
child: Container(
margin: const EdgeInsets.symmetric(horizontal: AppSpacing.md),
decoration: BoxDecoration(
color: Colors.white,
color: colorScheme.surface,
borderRadius: BorderRadius.circular(AppRadius.xl),
border: Border.all(color: const Color(0xFFE2E8F0)),
border: Border.all(color: colorScheme.outlineVariant),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.08),
@@ -63,16 +64,16 @@ class FeaturedNewsCard extends StatelessWidget {
fit: BoxFit.cover,
placeholder: (context, url) => Container(
height: 200,
color: AppColors.grey100,
color: colorScheme.surfaceContainerHighest,
child: const Center(child: CircularProgressIndicator()),
),
errorWidget: (context, url, error) => Container(
height: 200,
color: AppColors.grey100,
child: const FaIcon(
color: colorScheme.surfaceContainerHighest,
child: FaIcon(
FontAwesomeIcons.image,
size: 48,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
),
@@ -87,10 +88,10 @@ class FeaturedNewsCard extends StatelessWidget {
// Title
Text(
article.title,
style: const TextStyle(
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Color(0xFF1E293B),
color: colorScheme.onSurface,
height: 1.4,
),
),
@@ -100,9 +101,9 @@ class FeaturedNewsCard extends StatelessWidget {
// Excerpt
Text(
article.excerpt,
style: const TextStyle(
style: TextStyle(
fontSize: 14,
color: Color(0xFF64748B),
color: colorScheme.onSurfaceVariant,
height: 1.5,
),
maxLines: 3,
@@ -123,18 +124,21 @@ class FeaturedNewsCard extends StatelessWidget {
children: [
// Date
_buildMetaItem(
context,
icon: FontAwesomeIcons.calendar,
text: article.formattedDate,
),
// // Views
// _buildMetaItem(
// context,
// icon: Icons.visibility,
// text: '${article.formattedViewCount} lượt xem',
// ),
//
// // Reading time
// _buildMetaItem(
// context,
// icon: Icons.schedule,
// text: article.readingTimeText,
// ),
@@ -149,15 +153,15 @@ class FeaturedNewsCard extends StatelessWidget {
vertical: 4,
),
decoration: BoxDecoration(
color: AppColors.primaryBlue,
color: colorScheme.primary,
borderRadius: BorderRadius.circular(16),
),
child: Text(
article.category.displayName,
style: const TextStyle(
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Colors.white,
color: colorScheme.onPrimary,
),
),
),
@@ -173,15 +177,17 @@ class FeaturedNewsCard extends StatelessWidget {
}
/// Build metadata item
Widget _buildMetaItem({required IconData icon, required String text}) {
Widget _buildMetaItem(BuildContext context, {required IconData icon, required String text}) {
final colorScheme = Theme.of(context).colorScheme;
return Row(
mainAxisSize: MainAxisSize.min,
children: [
FaIcon(icon, size: 12, color: const Color(0xFF64748B)),
FaIcon(icon, size: 12, color: colorScheme.onSurfaceVariant),
const SizedBox(width: 4),
Text(
text,
style: const TextStyle(fontSize: 12, color: Color(0xFF64748B)),
style: TextStyle(fontSize: 12, color: colorScheme.onSurfaceVariant),
),
],
);

View File

@@ -8,7 +8,6 @@ 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';
/// News Card
@@ -31,15 +30,17 @@ class NewsCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return GestureDetector(
onTap: onTap,
child: Container(
margin: const EdgeInsets.only(bottom: AppSpacing.md),
padding: const EdgeInsets.all(AppSpacing.md),
decoration: BoxDecoration(
color: Colors.white,
color: colorScheme.surface,
borderRadius: BorderRadius.circular(AppRadius.card),
border: Border.all(color: const Color(0xFFE2E8F0)),
border: Border.all(color: colorScheme.outlineVariant),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -55,7 +56,7 @@ class NewsCard extends StatelessWidget {
placeholder: (context, url) => Container(
width: 80,
height: 80,
color: AppColors.grey100,
color: colorScheme.surfaceContainerHighest,
child: const Center(
child: SizedBox(
width: 20,
@@ -67,11 +68,11 @@ class NewsCard extends StatelessWidget {
errorWidget: (context, url, error) => Container(
width: 80,
height: 80,
color: AppColors.grey100,
child: const FaIcon(
color: colorScheme.surfaceContainerHighest,
child: FaIcon(
FontAwesomeIcons.image,
size: 24,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
),
@@ -87,10 +88,10 @@ class NewsCard extends StatelessWidget {
// Title (max 2 lines)
Text(
article.title,
style: const TextStyle(
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Color(0xFF1E293B),
color: colorScheme.onSurface,
height: 1.3,
),
maxLines: 2,
@@ -102,9 +103,9 @@ class NewsCard extends StatelessWidget {
// Excerpt (max 2 lines)
Text(
article.excerpt,
style: const TextStyle(
style: TextStyle(
fontSize: 12,
color: Color(0xFF64748B),
color: colorScheme.onSurfaceVariant,
height: 1.4,
),
maxLines: 2,
@@ -117,17 +118,17 @@ class NewsCard extends StatelessWidget {
Row(
children: [
// Date
const FaIcon(
FaIcon(
FontAwesomeIcons.calendar,
size: 12,
color: Color(0xFF64748B),
color: colorScheme.onSurfaceVariant,
),
const SizedBox(width: 4),
Text(
article.formattedDate,
style: const TextStyle(
style: TextStyle(
fontSize: 12,
color: Color(0xFF64748B),
color: colorScheme.onSurfaceVariant,
),
),
@@ -137,14 +138,14 @@ class NewsCard extends StatelessWidget {
// Icon(
// Icons.visibility,
// size: 12,
// color: const Color(0xFF64748B),
// color: colorScheme.onSurfaceVariant,
// ),
// const SizedBox(width: 4),
// Text(
// '${article.formattedViewCount} lượt xem',
// style: const TextStyle(
// style: TextStyle(
// fontSize: 12,
// color: Color(0xFF64748B),
// color: colorScheme.onSurfaceVariant,
// ),
// ),
],

View File

@@ -8,7 +8,6 @@ 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';
/// Related Article Card
@@ -31,15 +30,17 @@ class RelatedArticleCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return GestureDetector(
onTap: onTap,
child: Container(
margin: const EdgeInsets.only(bottom: AppSpacing.md),
padding: const EdgeInsets.all(AppSpacing.md),
decoration: BoxDecoration(
color: Colors.white,
color: colorScheme.surface,
borderRadius: BorderRadius.circular(AppRadius.lg),
border: Border.all(color: const Color(0xFFE2E8F0)),
border: Border.all(color: colorScheme.outlineVariant),
),
child: Row(
children: [
@@ -54,7 +55,7 @@ class RelatedArticleCard extends StatelessWidget {
placeholder: (context, url) => Container(
width: 60,
height: 60,
color: AppColors.grey100,
color: colorScheme.surfaceContainerHighest,
child: const Center(
child: SizedBox(
width: 16,
@@ -66,11 +67,11 @@ class RelatedArticleCard extends StatelessWidget {
errorWidget: (context, url, error) => Container(
width: 60,
height: 60,
color: AppColors.grey100,
child: const FaIcon(
color: colorScheme.surfaceContainerHighest,
child: FaIcon(
FontAwesomeIcons.image,
size: 20,
color: AppColors.grey500,
color: colorScheme.onSurfaceVariant,
),
),
),
@@ -86,10 +87,10 @@ class RelatedArticleCard extends StatelessWidget {
// Title (max 2 lines)
Text(
article.title,
style: const TextStyle(
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Color(0xFF1E293B),
color: colorScheme.onSurface,
height: 1.3,
),
maxLines: 2,
@@ -101,9 +102,9 @@ class RelatedArticleCard extends StatelessWidget {
// Metadata
Text(
'${article.formattedDate}${article.formattedViewCount} lượt xem',
style: const TextStyle(
style: TextStyle(
fontSize: 12,
color: Color(0xFF64748B),
color: colorScheme.onSurfaceVariant,
),
),
],