price policy
This commit is contained in:
@@ -1,7 +1,12 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:open_file/open_file.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import '../../../../core/constants/ui_constants.dart';
|
||||
import '../../../../core/network/dio_client.dart';
|
||||
import '../../../../core/theme/colors.dart';
|
||||
import '../../domain/entities/price_document.dart';
|
||||
import '../providers/price_documents_provider.dart';
|
||||
@@ -55,36 +60,55 @@ class _PricePolicyPageState extends ConsumerState<PricePolicyPage>
|
||||
),
|
||||
const SizedBox(width: AppSpacing.sm),
|
||||
],
|
||||
bottom: TabBar(
|
||||
controller: _tabController,
|
||||
labelColor: AppColors.white,
|
||||
unselectedLabelColor: AppColors.grey900,
|
||||
indicatorSize: TabBarIndicatorSize.tab,
|
||||
indicator: BoxDecoration(
|
||||
color: AppColors.primaryBlue,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
labelStyle: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
unselectedLabelStyle: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
tabs: const [
|
||||
Tab(text: 'Chính sách giá'),
|
||||
Tab(text: 'Bảng giá'),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: TabBarView(
|
||||
controller: _tabController,
|
||||
body: Column(
|
||||
children: [
|
||||
// Policy tab
|
||||
_buildDocumentList(DocumentCategory.policy),
|
||||
// Price list tab
|
||||
_buildDocumentList(DocumentCategory.priceList),
|
||||
// TabBar with padding
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Container(
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.grey100,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: TabBar(
|
||||
controller: _tabController,
|
||||
labelColor: AppColors.white,
|
||||
unselectedLabelColor: AppColors.grey900,
|
||||
indicatorSize: TabBarIndicatorSize.tab,
|
||||
indicator: BoxDecoration(
|
||||
color: AppColors.primaryBlue,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
dividerColor: Colors.transparent,
|
||||
labelStyle: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
unselectedLabelStyle: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
tabs: const [
|
||||
Tab(text: 'Chính sách giá'),
|
||||
Tab(text: 'Bảng giá'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
// TabBarView
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
controller: _tabController,
|
||||
children: [
|
||||
// Policy tab
|
||||
_buildDocumentList(DocumentCategory.policy),
|
||||
// Price list tab
|
||||
_buildDocumentList(DocumentCategory.priceList),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -96,7 +120,7 @@ class _PricePolicyPageState extends ConsumerState<PricePolicyPage>
|
||||
return documentsAsync.when(
|
||||
data: (documents) {
|
||||
if (documents.isEmpty) {
|
||||
return Center(
|
||||
return const Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
@@ -105,7 +129,7 @@ class _PricePolicyPageState extends ConsumerState<PricePolicyPage>
|
||||
size: 64,
|
||||
color: AppColors.grey500,
|
||||
),
|
||||
const SizedBox(height: AppSpacing.md),
|
||||
SizedBox(height: AppSpacing.md),
|
||||
Text(
|
||||
'Chưa có tài liệu',
|
||||
style: TextStyle(fontSize: 16, color: AppColors.grey500),
|
||||
@@ -118,8 +142,9 @@ class _PricePolicyPageState extends ConsumerState<PricePolicyPage>
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
// Refresh documents from repository
|
||||
ref.invalidate(filteredPriceDocumentsProvider(category));
|
||||
await Future<void>.delayed(const Duration(milliseconds: 500));
|
||||
await ref
|
||||
.read(filteredPriceDocumentsProvider(category).notifier)
|
||||
.refresh();
|
||||
},
|
||||
child: ListView.separated(
|
||||
padding: const EdgeInsets.all(AppSpacing.md),
|
||||
@@ -130,7 +155,7 @@ class _PricePolicyPageState extends ConsumerState<PricePolicyPage>
|
||||
final document = documents[index];
|
||||
return DocumentCard(
|
||||
document: document,
|
||||
onDownload: () => _handleDownload(document),
|
||||
onDownload: () => _handleDownload(document, category),
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -150,7 +175,9 @@ class _PricePolicyPageState extends ConsumerState<PricePolicyPage>
|
||||
const SizedBox(height: AppSpacing.sm),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
ref.invalidate(filteredPriceDocumentsProvider(category));
|
||||
ref
|
||||
.read(filteredPriceDocumentsProvider(category).notifier)
|
||||
.refresh();
|
||||
},
|
||||
child: const Text('Thử lại'),
|
||||
),
|
||||
@@ -160,22 +187,95 @@ class _PricePolicyPageState extends ConsumerState<PricePolicyPage>
|
||||
);
|
||||
}
|
||||
|
||||
void _handleDownload(PriceDocument document) {
|
||||
// In real app, this would trigger actual download
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Đang tải: ${document.title}'),
|
||||
duration: const Duration(seconds: 2),
|
||||
backgroundColor: AppColors.primaryBlue,
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
);
|
||||
Future<void> _handleDownload(
|
||||
PriceDocument document,
|
||||
DocumentCategory category,
|
||||
) async {
|
||||
try {
|
||||
// Check if file already downloaded and exists
|
||||
if (document.filePath != null) {
|
||||
final file = File(document.filePath!);
|
||||
if (await file.exists()) {
|
||||
// File exists, just open it
|
||||
final result = await OpenFile.open(document.filePath!);
|
||||
if (result.type != ResultType.done && mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Không thể mở file: ${result.message}'),
|
||||
backgroundColor: AppColors.danger,
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Simulate download
|
||||
// TODO: Implement actual file download functionality
|
||||
// - Use url_launcher or dio to download file
|
||||
// - Show progress indicator
|
||||
// - Save to device storage
|
||||
// File not downloaded yet, show loading snackbar
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Đang tải: ${document.title}'),
|
||||
duration: const Duration(seconds: 2),
|
||||
backgroundColor: AppColors.primaryBlue,
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
);
|
||||
|
||||
// Get DioClient
|
||||
final dioClient = await ref.read(dioClientProvider.future);
|
||||
|
||||
// Get download directory
|
||||
final directory = await getApplicationDocumentsDirectory();
|
||||
|
||||
// Extract filename from URL or use title
|
||||
final uri = Uri.parse(document.fileUrl);
|
||||
final filename = uri.pathSegments.isNotEmpty
|
||||
? uri.pathSegments.last
|
||||
: '${document.title}.${document.documentType == DocumentType.pdf ? "pdf" : "xlsx"}';
|
||||
|
||||
final savePath = '${directory.path}/$filename';
|
||||
|
||||
// Download file with authentication headers (automatically added by AuthInterceptor)
|
||||
await dioClient.downloadFile(
|
||||
document.fileUrl,
|
||||
savePath,
|
||||
onReceiveProgress: (received, total) {
|
||||
// Progress tracking available here if needed: (received / total * 100)
|
||||
},
|
||||
);
|
||||
|
||||
// Update document with file path in provider
|
||||
ref
|
||||
.read(filteredPriceDocumentsProvider(category).notifier)
|
||||
.updateDocumentFilePath(document.title, savePath);
|
||||
|
||||
// Show success message
|
||||
if (mounted) {
|
||||
// Clear any existing snackbars
|
||||
ScaffoldMessenger.of(context).clearSnackBars();
|
||||
|
||||
// Show success message
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Tải thành công: ${document.title}'),
|
||||
backgroundColor: AppColors.success,
|
||||
behavior: SnackBarBehavior.floating,
|
||||
duration: const Duration(seconds: 2),
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
// Show error message
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Lỗi tải file: ${e.toString()}'),
|
||||
backgroundColor: AppColors.danger,
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _showInfoDialog() {
|
||||
|
||||
Reference in New Issue
Block a user