465 lines
15 KiB
Dart
465 lines
15 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:auto_route/auto_route.dart';
|
|
|
|
import '../../../common/theme/theme.dart';
|
|
import '../../components/appbar/appbar.dart';
|
|
import '../../components/field/date_range_picker_field.dart';
|
|
|
|
@RoutePage()
|
|
class DownloadReportPage extends StatefulWidget {
|
|
const DownloadReportPage({super.key});
|
|
|
|
@override
|
|
State<DownloadReportPage> createState() => _DownloadReportPageState();
|
|
}
|
|
|
|
class _DownloadReportPageState extends State<DownloadReportPage>
|
|
with TickerProviderStateMixin {
|
|
late AnimationController _fadeController;
|
|
late AnimationController _slideController;
|
|
late AnimationController _scaleController;
|
|
|
|
late Animation<double> _fadeAnimation;
|
|
|
|
// Date range variables for each report type
|
|
DateTime? _transactionStartDate;
|
|
DateTime? _transactionEndDate;
|
|
DateTime? _inventoryStartDate;
|
|
DateTime? _inventoryEndDate;
|
|
DateTime? _salesStartDate;
|
|
DateTime? _salesEndDate;
|
|
DateTime? _customerStartDate;
|
|
DateTime? _customerEndDate;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
|
|
// Initialize animation controllers
|
|
_fadeController = AnimationController(
|
|
duration: const Duration(milliseconds: 800),
|
|
vsync: this,
|
|
);
|
|
|
|
_slideController = AnimationController(
|
|
duration: const Duration(milliseconds: 1000),
|
|
vsync: this,
|
|
);
|
|
|
|
_scaleController = AnimationController(
|
|
duration: const Duration(milliseconds: 600),
|
|
vsync: this,
|
|
);
|
|
|
|
// Initialize animations
|
|
_fadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
|
|
CurvedAnimation(parent: _fadeController, curve: Curves.easeInOut),
|
|
);
|
|
|
|
// Start animations
|
|
_fadeController.forward();
|
|
_slideController.forward();
|
|
_scaleController.forward();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_fadeController.dispose();
|
|
_slideController.dispose();
|
|
_scaleController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
void _downloadReport(
|
|
String reportType,
|
|
DateTime? startDate,
|
|
DateTime? endDate,
|
|
) {
|
|
if (startDate == null || endDate == null) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
const SnackBar(
|
|
content: Text('Please select both start and end dates'),
|
|
backgroundColor: AppColor.error,
|
|
),
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Implement download logic here
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text(
|
|
'Downloading $reportType from ${_formatDate(startDate)} to ${_formatDate(endDate)}',
|
|
),
|
|
backgroundColor: AppColor.success,
|
|
),
|
|
);
|
|
}
|
|
|
|
String _formatDate(DateTime date) {
|
|
return '${date.day}/${date.month}/${date.year}';
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
backgroundColor: AppColor.background,
|
|
body: CustomScrollView(
|
|
slivers: [
|
|
// SliverAppBar with gradient
|
|
SliverAppBar(
|
|
expandedHeight: 120,
|
|
floating: false,
|
|
pinned: true,
|
|
elevation: 0,
|
|
backgroundColor: AppColor.primary,
|
|
flexibleSpace: CustomAppBar(title: 'Download Report'),
|
|
),
|
|
|
|
// Content
|
|
SliverToBoxAdapter(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(20),
|
|
child: Column(
|
|
children: [
|
|
// Report Options
|
|
FadeTransition(
|
|
opacity: _fadeAnimation,
|
|
child: Column(
|
|
children: [
|
|
// Transaction Report Card
|
|
_ReportOptionCard(
|
|
title: 'Transaction Report',
|
|
subtitle:
|
|
'Export all transaction data with detailed analytics',
|
|
icon: Icons.receipt_long_outlined,
|
|
gradient: const [
|
|
AppColor.primary,
|
|
AppColor.primaryLight,
|
|
],
|
|
startDate: _transactionStartDate,
|
|
endDate: _transactionEndDate,
|
|
onDateRangeChanged: (start, end) {
|
|
setState(() {
|
|
_transactionStartDate = start;
|
|
_transactionEndDate = end;
|
|
});
|
|
},
|
|
onDownload: () => _downloadReport(
|
|
'Transaction Report',
|
|
_transactionStartDate,
|
|
_transactionEndDate,
|
|
),
|
|
delay: 200,
|
|
),
|
|
|
|
const SizedBox(height: 20),
|
|
|
|
// Inventory Report Card
|
|
_ReportOptionCard(
|
|
title: 'Inventory Report',
|
|
subtitle:
|
|
'Export inventory and stock data with trends',
|
|
icon: Icons.inventory_2_outlined,
|
|
gradient: const [
|
|
AppColor.secondary,
|
|
AppColor.secondaryLight,
|
|
],
|
|
startDate: _inventoryStartDate,
|
|
endDate: _inventoryEndDate,
|
|
onDateRangeChanged: (start, end) {
|
|
setState(() {
|
|
_inventoryStartDate = start;
|
|
_inventoryEndDate = end;
|
|
});
|
|
},
|
|
onDownload: () => _downloadReport(
|
|
'Inventory Report',
|
|
_inventoryStartDate,
|
|
_inventoryEndDate,
|
|
),
|
|
delay: 400,
|
|
),
|
|
|
|
const SizedBox(height: 20),
|
|
|
|
// Sales Report Card
|
|
_ReportOptionCard(
|
|
title: 'Sales Report',
|
|
subtitle: 'Export sales performance and revenue data',
|
|
icon: Icons.trending_up_outlined,
|
|
gradient: const [AppColor.info, Color(0xFF64B5F6)],
|
|
startDate: _salesStartDate,
|
|
endDate: _salesEndDate,
|
|
onDateRangeChanged: (start, end) {
|
|
setState(() {
|
|
_salesStartDate = start;
|
|
_salesEndDate = end;
|
|
});
|
|
},
|
|
onDownload: () => _downloadReport(
|
|
'Sales Report',
|
|
_salesStartDate,
|
|
_salesEndDate,
|
|
),
|
|
delay: 600,
|
|
),
|
|
|
|
const SizedBox(height: 20),
|
|
|
|
// Customer Report Card
|
|
_ReportOptionCard(
|
|
title: 'Customer Report',
|
|
subtitle:
|
|
'Export customer data and behavior analytics',
|
|
icon: Icons.people_outline,
|
|
gradient: const [AppColor.warning, Color(0xFFFFB74D)],
|
|
startDate: _customerStartDate,
|
|
endDate: _customerEndDate,
|
|
onDateRangeChanged: (start, end) {
|
|
setState(() {
|
|
_customerStartDate = start;
|
|
_customerEndDate = end;
|
|
});
|
|
},
|
|
onDownload: () => _downloadReport(
|
|
'Customer Report',
|
|
_customerStartDate,
|
|
_customerEndDate,
|
|
),
|
|
delay: 800,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
const SizedBox(height: 40),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _ReportOptionCard extends StatefulWidget {
|
|
final String title;
|
|
final String subtitle;
|
|
final IconData icon;
|
|
final List<Color> gradient;
|
|
final DateTime? startDate;
|
|
final DateTime? endDate;
|
|
final Function(DateTime? startDate, DateTime? endDate) onDateRangeChanged;
|
|
final VoidCallback onDownload;
|
|
final int delay;
|
|
|
|
const _ReportOptionCard({
|
|
required this.title,
|
|
required this.subtitle,
|
|
required this.icon,
|
|
required this.gradient,
|
|
required this.startDate,
|
|
required this.endDate,
|
|
required this.onDateRangeChanged,
|
|
required this.onDownload,
|
|
required this.delay,
|
|
});
|
|
|
|
@override
|
|
State<_ReportOptionCard> createState() => _ReportOptionCardState();
|
|
}
|
|
|
|
class _ReportOptionCardState extends State<_ReportOptionCard>
|
|
with SingleTickerProviderStateMixin {
|
|
late AnimationController _animationController;
|
|
late Animation<double> _slideAnimation;
|
|
bool _isExpanded = false;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_animationController = AnimationController(
|
|
duration: const Duration(milliseconds: 300),
|
|
vsync: this,
|
|
);
|
|
_slideAnimation = CurvedAnimation(
|
|
parent: _animationController,
|
|
curve: Curves.easeInOutCubic,
|
|
);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_animationController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
void _toggleExpanded() {
|
|
setState(() {
|
|
_isExpanded = !_isExpanded;
|
|
if (_isExpanded) {
|
|
_animationController.forward();
|
|
} else {
|
|
_animationController.reverse();
|
|
}
|
|
});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
decoration: BoxDecoration(
|
|
gradient: LinearGradient(
|
|
begin: Alignment.topLeft,
|
|
end: Alignment.bottomRight,
|
|
colors: widget.gradient,
|
|
),
|
|
borderRadius: BorderRadius.circular(20),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: widget.gradient.first.withOpacity(0.3),
|
|
blurRadius: 15,
|
|
offset: const Offset(0, 8),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
children: [
|
|
// Header Section
|
|
GestureDetector(
|
|
onTap: _toggleExpanded,
|
|
child: Container(
|
|
padding: const EdgeInsets.all(20),
|
|
child: Row(
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(16),
|
|
decoration: BoxDecoration(
|
|
color: AppColor.white.withOpacity(0.2),
|
|
borderRadius: BorderRadius.circular(16),
|
|
),
|
|
child: Icon(widget.icon, color: AppColor.white, size: 32),
|
|
),
|
|
const SizedBox(width: 20),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
widget.title,
|
|
style: AppStyle.lg.copyWith(
|
|
color: AppColor.white,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
widget.subtitle,
|
|
style: AppStyle.sm.copyWith(
|
|
color: AppColor.white.withOpacity(0.8),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
AnimatedRotation(
|
|
turns: _isExpanded ? 0.25 : 0,
|
|
duration: const Duration(milliseconds: 300),
|
|
child: Icon(
|
|
Icons.arrow_forward_ios,
|
|
color: AppColor.white.withOpacity(0.8),
|
|
size: 20,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
|
|
// Expandable Content
|
|
SizeTransition(
|
|
sizeFactor: _slideAnimation,
|
|
child: Container(
|
|
padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),
|
|
child: Column(
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(20),
|
|
decoration: BoxDecoration(
|
|
color: AppColor.white.withOpacity(0.1),
|
|
borderRadius: BorderRadius.circular(16),
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
'Select Date Range',
|
|
style: AppStyle.md.copyWith(
|
|
color: AppColor.white,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
|
|
// Date Range Picker Field Style
|
|
DateRangePickerField(
|
|
placeholder: 'Select date range',
|
|
startDate: widget.startDate,
|
|
endDate: widget.endDate,
|
|
onChanged: widget.onDateRangeChanged,
|
|
),
|
|
|
|
const SizedBox(height: 20),
|
|
|
|
// Download Button
|
|
SizedBox(
|
|
width: double.infinity,
|
|
child: ElevatedButton(
|
|
onPressed:
|
|
widget.startDate != null &&
|
|
widget.endDate != null
|
|
? widget.onDownload
|
|
: null,
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: AppColor.white,
|
|
foregroundColor: widget.gradient.first,
|
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
elevation: 0,
|
|
),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Icon(
|
|
Icons.download_rounded,
|
|
color: widget.gradient.first,
|
|
),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
'Download Report',
|
|
style: AppStyle.md.copyWith(
|
|
color: widget.gradient.first,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|