update theme
This commit is contained in:
@@ -14,6 +14,8 @@ import 'package:intl/intl.dart';
|
||||
import 'package:worker/core/constants/ui_constants.dart';
|
||||
import 'package:worker/core/theme/colors.dart';
|
||||
import 'package:worker/features/showrooms/presentation/providers/design_request_provider.dart';
|
||||
import 'package:worker/features/showrooms/presentation/widgets/file_preview_item.dart';
|
||||
import 'package:worker/features/showrooms/presentation/widgets/form_field_widget.dart';
|
||||
|
||||
/// Design Request Create Page
|
||||
///
|
||||
@@ -27,6 +29,7 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final formKey = useMemoized(() => GlobalKey<FormState>());
|
||||
final projectNameController = useTextEditingController();
|
||||
final areaController = useTextEditingController();
|
||||
@@ -227,19 +230,19 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.grey50,
|
||||
backgroundColor: colorScheme.surfaceContainerLowest,
|
||||
appBar: AppBar(
|
||||
backgroundColor: AppColors.white,
|
||||
backgroundColor: colorScheme.surface,
|
||||
elevation: AppBarSpecs.elevation,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back, color: Colors.black),
|
||||
icon: Icon(Icons.arrow_back, color: colorScheme.onSurface),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
centerTitle: false,
|
||||
title: const Text(
|
||||
title: Text(
|
||||
'Tạo yêu cầu thiết kế mới',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
color: colorScheme.onSurface,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
@@ -268,16 +271,16 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
children: [
|
||||
Icon(
|
||||
Icons.info_outline,
|
||||
color: AppColors.primaryBlue,
|
||||
color: colorScheme.primary,
|
||||
size: 20,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
Text(
|
||||
'Thông tin cơ bản',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.grey900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -286,7 +289,7 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Project Name
|
||||
_FormField(
|
||||
FormFieldWidget(
|
||||
label: 'Tên dự án/Khách hàng',
|
||||
required: true,
|
||||
controller: projectNameController,
|
||||
@@ -302,7 +305,7 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Area
|
||||
_FormField(
|
||||
FormFieldWidget(
|
||||
label: 'Diện tích (m²)',
|
||||
required: true,
|
||||
controller: areaController,
|
||||
@@ -323,7 +326,7 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Location
|
||||
_FormField(
|
||||
FormFieldWidget(
|
||||
label: 'Khu vực (Tỉnh/ Thành phố)',
|
||||
required: true,
|
||||
controller: locationController,
|
||||
@@ -343,14 +346,14 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
RichText(
|
||||
text: const TextSpan(
|
||||
text: TextSpan(
|
||||
text: 'Phong cách mong muốn',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.grey900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
children: [
|
||||
children: const [
|
||||
TextSpan(
|
||||
text: ' *',
|
||||
style: TextStyle(color: AppColors.danger),
|
||||
@@ -367,22 +370,22 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
hintText: '-- Chọn phong cách --',
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(
|
||||
color: AppColors.grey100,
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(
|
||||
color: AppColors.grey100,
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(
|
||||
color: AppColors.primaryBlue,
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.primary,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
@@ -444,12 +447,12 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'Ngân sách dự kiến',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.grey900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
@@ -461,22 +464,22 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
hintText: '-- Chọn ngân sách --',
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(
|
||||
color: AppColors.grey100,
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(
|
||||
color: AppColors.grey100,
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(
|
||||
color: AppColors.primaryBlue,
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.primary,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
@@ -525,14 +528,14 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
RichText(
|
||||
text: const TextSpan(
|
||||
text: TextSpan(
|
||||
text: 'Thời hạn mong muốn',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.grey900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
children: [
|
||||
children: const [
|
||||
TextSpan(
|
||||
text: ' *',
|
||||
style: TextStyle(color: AppColors.danger),
|
||||
@@ -550,22 +553,22 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
suffixIcon: const Icon(Icons.calendar_today, size: 20),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(
|
||||
color: AppColors.grey100,
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(
|
||||
color: AppColors.grey100,
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(
|
||||
color: AppColors.primaryBlue,
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.primary,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
@@ -606,16 +609,16 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
children: [
|
||||
Icon(
|
||||
Icons.edit_outlined,
|
||||
color: AppColors.primaryBlue,
|
||||
color: colorScheme.primary,
|
||||
size: 20,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
Text(
|
||||
'Yêu cầu chi tiết',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.grey900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -628,14 +631,14 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
RichText(
|
||||
text: const TextSpan(
|
||||
text: TextSpan(
|
||||
text: 'Ghi chú chi tiết',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.grey900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
children: [
|
||||
children: const [
|
||||
TextSpan(
|
||||
text: ' *',
|
||||
style: TextStyle(color: AppColors.danger),
|
||||
@@ -652,22 +655,22 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
'Mô tả chi tiết về yêu cầu thiết kế, số phòng, công năng sử dụng, sở thích cá nhân...',
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(
|
||||
color: AppColors.grey100,
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(
|
||||
color: AppColors.grey100,
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(
|
||||
color: AppColors.primaryBlue,
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.primary,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
@@ -706,16 +709,16 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
children: [
|
||||
Icon(
|
||||
Icons.cloud_upload_outlined,
|
||||
color: AppColors.primaryBlue,
|
||||
color: colorScheme.primary,
|
||||
size: 20,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
Text(
|
||||
'Đính kèm tài liệu',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.grey900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -730,34 +733,34 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
padding: const EdgeInsets.all(24),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: AppColors.grey100,
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
width: 2,
|
||||
style: BorderStyle.solid,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
color: AppColors.grey50,
|
||||
color: colorScheme.surfaceContainerLowest,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.cloud_upload_outlined,
|
||||
size: 32,
|
||||
color: AppColors.grey500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const Text(
|
||||
Text(
|
||||
'Nhấn để chọn file hoặc kéo thả vào đây',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: AppColors.grey500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const Text(
|
||||
Text(
|
||||
'Hỗ trợ: JPG, PNG, PDF (Tối đa 10MB mỗi file)',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: AppColors.grey500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -771,7 +774,7 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
...selectedFiles.value.asMap().entries.map((entry) {
|
||||
final index = entry.key;
|
||||
final file = entry.value;
|
||||
return _FilePreviewItem(
|
||||
return FilePreviewItem(
|
||||
file: file,
|
||||
onRemove: () => removeFile(index),
|
||||
);
|
||||
@@ -790,10 +793,10 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
child: ElevatedButton(
|
||||
onPressed: isSubmitting.value ? null : submitForm,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppColors.primaryBlue,
|
||||
foregroundColor: AppColors.white,
|
||||
disabledBackgroundColor: AppColors.primaryBlue.withValues(alpha: 0.7),
|
||||
disabledForegroundColor: AppColors.white,
|
||||
backgroundColor: colorScheme.primary,
|
||||
foregroundColor: colorScheme.surface,
|
||||
disabledBackgroundColor: colorScheme.primary.withValues(alpha: 0.7),
|
||||
disabledForegroundColor: colorScheme.surface,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
@@ -804,12 +807,12 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(
|
||||
SizedBox(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: AppColors.white,
|
||||
color: colorScheme.surface,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
@@ -850,167 +853,3 @@ class DesignRequestCreatePage extends HookConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// Progress Step Widget
|
||||
|
||||
/// Form Field Widget
|
||||
class _FormField extends StatelessWidget {
|
||||
final String label;
|
||||
final bool required;
|
||||
final TextEditingController controller;
|
||||
final String hint;
|
||||
final TextInputType? keyboardType;
|
||||
final String? Function(String?)? validator;
|
||||
|
||||
const _FormField({
|
||||
required this.label,
|
||||
this.required = false,
|
||||
required this.controller,
|
||||
required this.hint,
|
||||
this.keyboardType,
|
||||
this.validator,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
text: label,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.grey900,
|
||||
),
|
||||
children: required
|
||||
? const [
|
||||
TextSpan(
|
||||
text: ' *',
|
||||
style: TextStyle(color: AppColors.danger),
|
||||
),
|
||||
]
|
||||
: null,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
TextFormField(
|
||||
controller: controller,
|
||||
keyboardType: keyboardType,
|
||||
decoration: InputDecoration(
|
||||
hintText: hint,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(color: AppColors.grey100, width: 2),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(color: AppColors.grey100, width: 2),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(
|
||||
color: AppColors.primaryBlue,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(color: AppColors.danger, width: 2),
|
||||
),
|
||||
focusedErrorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(color: AppColors.danger, width: 2),
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 12,
|
||||
),
|
||||
),
|
||||
validator: validator,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// File Preview Item Widget
|
||||
class _FilePreviewItem extends StatelessWidget {
|
||||
final PlatformFile file;
|
||||
final VoidCallback onRemove;
|
||||
|
||||
const _FilePreviewItem({required this.file, required this.onRemove});
|
||||
|
||||
IconData _getFileIcon() {
|
||||
final extension = file.extension?.toLowerCase();
|
||||
if (extension == 'pdf') return Icons.picture_as_pdf;
|
||||
if (extension == 'jpg' || extension == 'jpeg' || extension == 'png') {
|
||||
return Icons.image;
|
||||
}
|
||||
return Icons.insert_drive_file;
|
||||
}
|
||||
|
||||
String _formatFileSize(int bytes) {
|
||||
if (bytes < 1024) return '$bytes B';
|
||||
if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(1)} KB';
|
||||
return '${(bytes / (1024 * 1024)).toStringAsFixed(1)} MB';
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 8),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.grey100,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.primaryBlue,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Icon(_getFileIcon(), color: AppColors.white, size: 20),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
file.name,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.grey900,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
_formatFileSize(file.size),
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: AppColors.grey500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.close, size: 20),
|
||||
color: AppColors.danger,
|
||||
onPressed: onRemove,
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(minWidth: 24, minHeight: 24),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,9 @@ import 'package:worker/core/theme/colors.dart';
|
||||
import 'package:worker/features/showrooms/domain/entities/design_request.dart';
|
||||
import 'package:worker/features/showrooms/domain/entities/sample_project.dart';
|
||||
import 'package:worker/features/showrooms/presentation/providers/design_request_provider.dart';
|
||||
import 'package:worker/features/showrooms/presentation/widgets/description_item.dart';
|
||||
import 'package:worker/features/showrooms/presentation/widgets/file_item.dart';
|
||||
import 'package:worker/features/showrooms/presentation/widgets/image_viewer_dialog.dart';
|
||||
|
||||
/// Design Request Detail Page
|
||||
///
|
||||
@@ -161,7 +164,7 @@ class DesignRequestDetailPage extends ConsumerWidget {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
barrierColor: Colors.black87,
|
||||
builder: (context) => _ImageViewerDialog(
|
||||
builder: (context) => ImageViewerDialog(
|
||||
images: images,
|
||||
initialIndex: initialIndex,
|
||||
),
|
||||
@@ -171,21 +174,22 @@ class DesignRequestDetailPage extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final detailAsync = ref.watch(designRequestDetailProvider(requestId));
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.grey50,
|
||||
backgroundColor: colorScheme.surfaceContainerLowest,
|
||||
appBar: AppBar(
|
||||
backgroundColor: AppColors.white,
|
||||
backgroundColor: colorScheme.surface,
|
||||
elevation: AppBarSpecs.elevation,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back, color: Colors.black),
|
||||
icon: Icon(Icons.arrow_back, color: colorScheme.onSurface),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
centerTitle: false,
|
||||
title: const Text(
|
||||
title: Text(
|
||||
'Chi tiết Yêu cầu',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
color: colorScheme.onSurface,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
@@ -193,7 +197,7 @@ class DesignRequestDetailPage extends ConsumerWidget {
|
||||
actions: [
|
||||
detailAsync.maybeWhen(
|
||||
data: (request) => IconButton(
|
||||
icon: const Icon(Icons.share, color: Colors.black),
|
||||
icon: Icon(Icons.share, color: colorScheme.onSurface),
|
||||
onPressed: () => _shareRequest(context, request),
|
||||
),
|
||||
orElse: () => const SizedBox.shrink(),
|
||||
@@ -226,10 +230,10 @@ class DesignRequestDetailPage extends ConsumerWidget {
|
||||
// Request ID
|
||||
Text(
|
||||
'#${request.id}',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.grey900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
@@ -238,9 +242,9 @@ class DesignRequestDetailPage extends ConsumerWidget {
|
||||
if (request.dateline != null)
|
||||
Text(
|
||||
'Ngày gửi: ${request.dateline}',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: AppColors.grey500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
@@ -269,7 +273,7 @@ class DesignRequestDetailPage extends ConsumerWidget {
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
const Divider(height: 1, color: AppColors.grey100),
|
||||
Divider(height: 1, color: colorScheme.surfaceContainerHighest),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Design Information Section
|
||||
@@ -277,16 +281,16 @@ class DesignRequestDetailPage extends ConsumerWidget {
|
||||
children: [
|
||||
Icon(
|
||||
Icons.info_outline,
|
||||
color: AppColors.primaryBlue,
|
||||
color: colorScheme.primary,
|
||||
size: 20,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
Text(
|
||||
'Thông tin thiết kế',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.grey900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -295,14 +299,14 @@ class DesignRequestDetailPage extends ConsumerWidget {
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Description List
|
||||
_DescriptionItem(
|
||||
DescriptionItem(
|
||||
label: 'Tên công trình:',
|
||||
value: request.subject,
|
||||
),
|
||||
|
||||
if (request.plainDescription.isNotEmpty) ...[
|
||||
const SizedBox(height: 12),
|
||||
_DescriptionItem(
|
||||
DescriptionItem(
|
||||
label: 'Mô tả chi tiết:',
|
||||
value: request.plainDescription,
|
||||
isMultiLine: true,
|
||||
@@ -439,16 +443,16 @@ class DesignRequestDetailPage extends ConsumerWidget {
|
||||
children: [
|
||||
Icon(
|
||||
Icons.attach_file,
|
||||
color: AppColors.primaryBlue,
|
||||
color: colorScheme.primary,
|
||||
size: 20,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
Text(
|
||||
'Tài liệu đính kèm',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.grey900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -468,8 +472,8 @@ class DesignRequestDetailPage extends ConsumerWidget {
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () => _contactSupport(context),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppColors.primaryBlue,
|
||||
foregroundColor: Colors.white,
|
||||
backgroundColor: colorScheme.primary,
|
||||
foregroundColor: colorScheme.onPrimary,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
@@ -505,9 +509,9 @@ class DesignRequestDetailPage extends ConsumerWidget {
|
||||
Text(
|
||||
'Lỗi tải dữ liệu: ${error.toString().replaceAll('Exception: ', '')}',
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: AppColors.grey500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
@@ -524,6 +528,7 @@ class DesignRequestDetailPage extends ConsumerWidget {
|
||||
}
|
||||
|
||||
Widget _buildFilesSection(BuildContext context, List<ProjectFile> files) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
// Separate images and other files
|
||||
final images = files.where((f) => _isImageFile(f.fileUrl)).toList();
|
||||
final otherFiles = files.where((f) => !_isImageFile(f.fileUrl)).toList();
|
||||
@@ -553,13 +558,13 @@ class DesignRequestDetailPage extends ConsumerWidget {
|
||||
imageUrl: image.fileUrl,
|
||||
fit: BoxFit.cover,
|
||||
placeholder: (context, url) => Container(
|
||||
color: AppColors.grey100,
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
child: const Center(
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
),
|
||||
),
|
||||
errorWidget: (context, url, error) => Container(
|
||||
color: AppColors.grey100,
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
child: const Icon(Icons.error),
|
||||
),
|
||||
),
|
||||
@@ -575,7 +580,7 @@ class DesignRequestDetailPage extends ConsumerWidget {
|
||||
|
||||
// Other Files as file items
|
||||
...otherFiles.map(
|
||||
(file) => _FileItem(
|
||||
(file) => FileItem(
|
||||
fileUrl: file.fileUrl,
|
||||
icon: _getFileIcon(file.fileUrl),
|
||||
),
|
||||
@@ -584,7 +589,7 @@ class DesignRequestDetailPage extends ConsumerWidget {
|
||||
// Show image files as file items too (for download/naming)
|
||||
if (images.isNotEmpty && otherFiles.isEmpty)
|
||||
...images.map(
|
||||
(file) => _FileItem(
|
||||
(file) => FileItem(
|
||||
fileUrl: file.fileUrl,
|
||||
icon: Icons.image,
|
||||
),
|
||||
@@ -593,246 +598,3 @@ class DesignRequestDetailPage extends ConsumerWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Description Item Widget
|
||||
class _DescriptionItem extends StatelessWidget {
|
||||
const _DescriptionItem({
|
||||
required this.label,
|
||||
required this.value,
|
||||
this.isMultiLine = false,
|
||||
});
|
||||
|
||||
final String label;
|
||||
final String value;
|
||||
final bool isMultiLine;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (isMultiLine) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
color: AppColors.grey500,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
color: AppColors.grey900,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1.6,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(bottom: BorderSide(color: AppColors.grey100)),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 120,
|
||||
child: Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
color: AppColors.grey500,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
color: AppColors.grey900,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1.6,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// File Item Widget
|
||||
class _FileItem extends StatelessWidget {
|
||||
const _FileItem({required this.fileUrl, required this.icon});
|
||||
|
||||
final String fileUrl;
|
||||
final IconData icon;
|
||||
|
||||
String get fileName {
|
||||
final uri = Uri.parse(fileUrl);
|
||||
return uri.pathSegments.isNotEmpty ? uri.pathSegments.last : fileUrl;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 8),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.grey100,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 32,
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.primaryBlue,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Icon(icon, color: Colors.white, size: 14),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
fileName,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.grey900,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Image Viewer Dialog with Swipe Navigation
|
||||
class _ImageViewerDialog extends StatefulWidget {
|
||||
const _ImageViewerDialog({
|
||||
required this.images,
|
||||
required this.initialIndex,
|
||||
});
|
||||
|
||||
final List<ProjectFile> images;
|
||||
final int initialIndex;
|
||||
|
||||
@override
|
||||
State<_ImageViewerDialog> createState() => _ImageViewerDialogState();
|
||||
}
|
||||
|
||||
class _ImageViewerDialogState extends State<_ImageViewerDialog> {
|
||||
late PageController _pageController;
|
||||
late int _currentIndex;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_currentIndex = widget.initialIndex;
|
||||
_pageController = PageController(initialPage: widget.initialIndex);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_pageController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
backgroundColor: Colors.transparent,
|
||||
insetPadding: EdgeInsets.zero,
|
||||
child: Container(
|
||||
color: Colors.black,
|
||||
child: Stack(
|
||||
children: [
|
||||
// Main PageView
|
||||
Center(
|
||||
child: PageView.builder(
|
||||
controller: _pageController,
|
||||
onPageChanged: (index) {
|
||||
setState(() {
|
||||
_currentIndex = index;
|
||||
});
|
||||
},
|
||||
itemCount: widget.images.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Center(
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: widget.images[index].fileUrl,
|
||||
fit: BoxFit.contain,
|
||||
placeholder: (context, url) => const Center(
|
||||
child: CircularProgressIndicator(color: Colors.white),
|
||||
),
|
||||
errorWidget: (context, url, error) => const Icon(
|
||||
Icons.error,
|
||||
color: Colors.white,
|
||||
size: 48,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
// Top bar with counter and close button
|
||||
Positioned(
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: SafeArea(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 12,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Colors.black.withValues(alpha: 0.7),
|
||||
Colors.transparent,
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${_currentIndex + 1} / ${widget.images.length}',
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.close, color: Colors.white),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,29 +26,30 @@ class ModelHouseDetailPage extends ConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final detailAsync = ref.watch(sampleProjectDetailProvider(modelId));
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF4F6F8),
|
||||
backgroundColor: colorScheme.surfaceContainerLowest,
|
||||
appBar: AppBar(
|
||||
leading: IconButton(
|
||||
icon: const FaIcon(
|
||||
icon: FaIcon(
|
||||
FontAwesomeIcons.arrowLeft,
|
||||
color: Colors.black,
|
||||
color: colorScheme.onSurface,
|
||||
size: 20,
|
||||
),
|
||||
onPressed: () => context.pop(),
|
||||
),
|
||||
title: const Text(
|
||||
title: Text(
|
||||
'Chi tiết Nhà mẫu',
|
||||
style: TextStyle(color: Colors.black),
|
||||
style: TextStyle(color: colorScheme.onSurface),
|
||||
),
|
||||
actions: [
|
||||
detailAsync.maybeWhen(
|
||||
data: (project) => IconButton(
|
||||
icon: const FaIcon(
|
||||
icon: FaIcon(
|
||||
FontAwesomeIcons.shareNodes,
|
||||
color: Colors.black,
|
||||
color: colorScheme.onSurface,
|
||||
size: 20,
|
||||
),
|
||||
onPressed: () => _shareModel(context, project),
|
||||
@@ -58,7 +59,7 @@ class ModelHouseDetailPage extends ConsumerWidget {
|
||||
const SizedBox(width: AppSpacing.sm),
|
||||
],
|
||||
elevation: AppBarSpecs.elevation,
|
||||
backgroundColor: AppColors.white,
|
||||
backgroundColor: colorScheme.surface,
|
||||
centerTitle: false,
|
||||
),
|
||||
body: detailAsync.when(
|
||||
@@ -72,7 +73,7 @@ class ModelHouseDetailPage extends ConsumerWidget {
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Project Information
|
||||
_buildProjectInfo(project),
|
||||
_buildProjectInfo(context, project),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
@@ -102,9 +103,9 @@ class ModelHouseDetailPage extends ConsumerWidget {
|
||||
Text(
|
||||
'Lỗi tải dữ liệu: ${error.toString().replaceAll('Exception: ', '')}',
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: AppColors.grey500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
@@ -299,12 +300,13 @@ class ModelHouseDetailPage extends ConsumerWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildProjectInfo(SampleProject project) {
|
||||
Widget _buildProjectInfo(BuildContext context, SampleProject project) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 4),
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.white,
|
||||
color: colorScheme.surface,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
@@ -320,10 +322,10 @@ class ModelHouseDetailPage extends ConsumerWidget {
|
||||
// Title
|
||||
Text(
|
||||
project.projectName,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.grey900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
if (project.plainDescription.isNotEmpty) ...[
|
||||
@@ -331,9 +333,9 @@ class ModelHouseDetailPage extends ConsumerWidget {
|
||||
// Description
|
||||
Text(
|
||||
project.plainDescription,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Color(0xFF4b5563),
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
height: 1.6,
|
||||
),
|
||||
),
|
||||
@@ -344,13 +346,14 @@ class ModelHouseDetailPage extends ConsumerWidget {
|
||||
}
|
||||
|
||||
Widget _buildImageGallery(BuildContext context, SampleProject project) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final images = project.filesList;
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 4),
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.white,
|
||||
color: colorScheme.surface,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
@@ -366,18 +369,18 @@ class ModelHouseDetailPage extends ConsumerWidget {
|
||||
// Gallery Title
|
||||
Row(
|
||||
children: [
|
||||
const FaIcon(
|
||||
FaIcon(
|
||||
FontAwesomeIcons.images,
|
||||
size: 18,
|
||||
color: AppColors.grey900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'Thư viện Hình ảnh (${images.length})',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.grey900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -405,13 +408,13 @@ class ModelHouseDetailPage extends ConsumerWidget {
|
||||
imageUrl: image.fileUrl,
|
||||
fit: BoxFit.cover,
|
||||
placeholder: (context, url) => Container(
|
||||
color: AppColors.grey100,
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
child: const Center(
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
),
|
||||
),
|
||||
errorWidget: (context, url, error) => Container(
|
||||
color: AppColors.grey100,
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
child: const Icon(Icons.error),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -92,41 +92,43 @@ class _ModelHousesPageState extends ConsumerState<ModelHousesPage>
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.grey50,
|
||||
backgroundColor: colorScheme.surfaceContainerLowest,
|
||||
appBar: AppBar(
|
||||
backgroundColor: AppColors.white,
|
||||
backgroundColor: colorScheme.surface,
|
||||
elevation: AppBarSpecs.elevation,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back, color: Colors.black),
|
||||
icon: Icon(Icons.arrow_back, color: colorScheme.onSurface),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
centerTitle: false,
|
||||
title: const Text(
|
||||
title: Text(
|
||||
'Nhà mẫu',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
color: colorScheme.onSurface,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.info_outline, color: Colors.black),
|
||||
icon: Icon(Icons.info_outline, color: colorScheme.onSurface),
|
||||
onPressed: _showInfoDialog,
|
||||
),
|
||||
const SizedBox(width: AppSpacing.sm),
|
||||
],
|
||||
bottom: TabBar(
|
||||
controller: _tabController,
|
||||
indicatorColor: AppColors.primaryBlue,
|
||||
indicatorColor: colorScheme.primary,
|
||||
indicatorWeight: 3,
|
||||
labelColor: AppColors.primaryBlue,
|
||||
labelColor: colorScheme.primary,
|
||||
labelStyle: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
unselectedLabelColor: AppColors.grey500,
|
||||
unselectedLabelColor: colorScheme.onSurfaceVariant,
|
||||
unselectedLabelStyle: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -148,11 +150,11 @@ class _ModelHousesPageState extends ConsumerState<ModelHousesPage>
|
||||
return _tabController.index == 1
|
||||
? FloatingActionButton(
|
||||
onPressed: _createNewRequest,
|
||||
backgroundColor: AppColors.primaryBlue,
|
||||
backgroundColor: colorScheme.primary,
|
||||
elevation: 4,
|
||||
child: const Icon(
|
||||
child: Icon(
|
||||
Icons.add,
|
||||
color: AppColors.white,
|
||||
color: colorScheme.onPrimary,
|
||||
size: 28,
|
||||
),
|
||||
)
|
||||
@@ -169,28 +171,29 @@ class _LibraryTab extends ConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final sampleProjectsAsync = ref.watch(sampleProjectsListProvider);
|
||||
|
||||
return sampleProjectsAsync.when(
|
||||
data: (projects) {
|
||||
if (projects.isEmpty) {
|
||||
return const Center(
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(40),
|
||||
padding: const EdgeInsets.all(40),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.home_work_outlined,
|
||||
size: 64,
|
||||
color: AppColors.grey500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Chưa có mẫu nhà nào',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: AppColors.grey500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -229,9 +232,9 @@ class _LibraryTab extends ConsumerWidget {
|
||||
Text(
|
||||
'Lỗi tải dữ liệu: ${error.toString().replaceAll('Exception: ', '')}',
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: AppColors.grey500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
@@ -255,6 +258,8 @@ class _LibraryCard extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return Card(
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
@@ -282,26 +287,26 @@ class _LibraryCard 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 Icon(
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
child: Icon(
|
||||
Icons.image_not_supported,
|
||||
size: 48,
|
||||
color: AppColors.grey500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Container(
|
||||
height: 200,
|
||||
color: AppColors.grey100,
|
||||
child: const Icon(
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
child: Icon(
|
||||
Icons.home_work,
|
||||
size: 48,
|
||||
color: AppColors.grey500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -315,13 +320,13 @@ class _LibraryCard extends StatelessWidget {
|
||||
vertical: 6,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.primaryBlue.withValues(alpha: 0.9),
|
||||
color: colorScheme.primary.withValues(alpha: 0.9),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: const Text(
|
||||
child: Text(
|
||||
'Xem 360°',
|
||||
style: TextStyle(
|
||||
color: AppColors.white,
|
||||
color: colorScheme.onPrimary,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
@@ -340,10 +345,10 @@ class _LibraryCard extends StatelessWidget {
|
||||
// Title
|
||||
Text(
|
||||
project.projectName,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.grey900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -352,9 +357,9 @@ class _LibraryCard extends StatelessWidget {
|
||||
// Description
|
||||
Text(
|
||||
project.plainDescription,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: AppColors.grey500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
height: 1.5,
|
||||
),
|
||||
maxLines: 3,
|
||||
@@ -377,28 +382,29 @@ class _DesignRequestsTab extends ConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final requestsAsync = ref.watch(designRequestsListProvider);
|
||||
|
||||
return requestsAsync.when(
|
||||
data: (requests) {
|
||||
if (requests.isEmpty) {
|
||||
return const Center(
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(40),
|
||||
padding: const EdgeInsets.all(40),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.design_services_outlined,
|
||||
size: 64,
|
||||
color: AppColors.grey500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Chưa có yêu cầu thiết kế nào',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: AppColors.grey500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -437,9 +443,9 @@ class _DesignRequestsTab extends ConsumerWidget {
|
||||
Text(
|
||||
'Lỗi tải dữ liệu: ${error.toString().replaceAll('Exception: ', '')}',
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: AppColors.grey500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
@@ -489,6 +495,8 @@ class _RequestCard extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return Card(
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
@@ -510,10 +518,10 @@ class _RequestCard extends StatelessWidget {
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Mã yêu cầu: #${request.id}',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.grey900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
@@ -546,7 +554,7 @@ class _RequestCard extends StatelessWidget {
|
||||
if (request.dateline != null)
|
||||
Text(
|
||||
'Deadline: ${request.dateline}',
|
||||
style: const TextStyle(fontSize: 14, color: AppColors.grey500),
|
||||
style: TextStyle(fontSize: 14, color: colorScheme.onSurfaceVariant),
|
||||
),
|
||||
|
||||
const SizedBox(height: 8),
|
||||
@@ -554,10 +562,10 @@ class _RequestCard extends StatelessWidget {
|
||||
// Subject
|
||||
Text(
|
||||
request.subject,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.grey900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -566,7 +574,7 @@ class _RequestCard extends StatelessWidget {
|
||||
// Description
|
||||
Text(
|
||||
request.plainDescription,
|
||||
style: const TextStyle(fontSize: 14, color: AppColors.grey500),
|
||||
style: TextStyle(fontSize: 14, color: colorScheme.onSurfaceVariant),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user