frontendPlayer/lib/presentation/pages/dashboard_page.dart
2026-04-10 09:55:19 +03:30

330 lines
14 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../core/constants/app_colors.dart';
import '../../core/constants/app_text_styles.dart';
import '../../data/services/api_service.dart';
import '../widgets/dashboard_card.dart';
import '../widgets/chart_widget.dart';
import '../widgets/teacher_panel_scaffold.dart';
import 'course_page.dart';
import 'license_page.dart';
import 'plan_renewal_page.dart';
import 'ticket_page.dart';
import 'transaction_page.dart';
class DashboardPage extends StatefulWidget {
const DashboardPage({super.key});
@override
State<DashboardPage> createState() => _DashboardPageState();
}
class _DashboardPageState extends State<DashboardPage>
with TickerProviderStateMixin {
Map<String, dynamic>? _dashboardData;
bool _isLoading = true;
late AnimationController _staggerController;
@override
void initState() {
super.initState();
_staggerController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1200),
);
_loadData();
}
Future<void> _loadData() async {
try {
final apiService = Provider.of<ApiService>(context, listen: false);
final data = await apiService.getDashboardData();
setState(() {
_dashboardData = data;
_isLoading = false;
});
_staggerController.forward();
} catch (e) {
setState(() {
_isLoading = false;
});
}
}
@override
void dispose() {
_staggerController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return TeacherPanelScaffold(
selectedMenu: PanelMenu.dashboard,
onDashboardTap: () {},
onCourseTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const CoursePage()),
);
},
onLicenseTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const PanelLicensePage()),
);
},
onTransactionTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const TransactionPage()),
);
},
onTicketTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const TicketPage()),
);
},
child: _isLoading
? const Center(child: CircularProgressIndicator())
: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LayoutBuilder(
builder: (context, constraints) {
final cardWidth = constraints.maxWidth > 800
? (constraints.maxWidth - 24) / 2
: constraints.maxWidth;
return Wrap(
spacing: 24,
runSpacing: 24,
alignment: WrapAlignment.start,
children: [
_buildAnimatedCard(
0,
cardWidth,
DashboardCard(
title: 'پلن فضا',
borderColor: AppColors.planCardBorder,
iconOrAction: Container(
padding: const EdgeInsets.all(12),
decoration: const BoxDecoration(
color: AppColors.planCardBorder,
shape: BoxShape.circle,
),
child: const Icon(
Icons.cloud,
color: Colors.white,
size: 32,
),
),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${_dashboardData!['plan']['used']} / ${_dashboardData!['plan']['total']} GB',
style: AppTextStyles.headlineMedium,
),
Text(
'${_dashboardData!['plan']['days_left']} روز',
style: AppTextStyles.bodyMedium,
),
const SizedBox(height: 8),
OutlinedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
const PlanRenewalPage(),
),
);
},
style: OutlinedButton.styleFrom(
foregroundColor: AppColors.planCardBorder,
side: const BorderSide(
color: AppColors.planCardBorder,
),
),
child: const Text('تغییر / تمدید'),
),
],
),
),
),
_buildAnimatedCard(
1,
cardWidth,
DashboardCard(
title: 'اعتبار',
borderColor: AppColors.creditCardBorder,
iconOrAction: Container(
padding: const EdgeInsets.all(12),
decoration: const BoxDecoration(
color: AppColors.creditCardBorder,
shape: BoxShape.circle,
),
child: const Icon(
Icons.attach_money,
color: Colors.white,
size: 32,
),
),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${_dashboardData!['credit']['amount']} تومان',
style: AppTextStyles.headlineMedium,
),
const SizedBox(height: 8),
OutlinedButton(
onPressed: () {},
style: OutlinedButton.styleFrom(
foregroundColor: AppColors.creditCardBorder,
side: const BorderSide(
color: AppColors.creditCardBorder,
),
),
child: const Text('افزایش اعتبار'),
),
],
),
),
),
_buildAnimatedCard(
2,
cardWidth,
DashboardCard(
title: 'کلید API',
borderColor: AppColors.apiCardBorder,
iconOrAction: Container(
padding: const EdgeInsets.all(12),
decoration: const BoxDecoration(
color: AppColors.apiCardBorder,
shape: BoxShape.circle,
),
child: const Icon(
Icons.vpn_key,
color: Colors.white,
size: 32,
),
),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_dashboardData!['api_key']['key'],
style: AppTextStyles.bodyMedium.copyWith(
fontWeight: FontWeight.bold,
),
),
Text(
_dashboardData!['api_key']['secret'],
style: AppTextStyles.bodyMedium,
),
const SizedBox(height: 8),
OutlinedButton(
onPressed: () {},
style: OutlinedButton.styleFrom(
foregroundColor: AppColors.apiCardBorder,
side: const BorderSide(
color: AppColors.apiCardBorder,
),
),
child: const Text('کپی API'),
),
],
),
),
),
_buildAnimatedCard(
3,
cardWidth,
DashboardCard(
title: 'ریبرندینگ',
borderColor: AppColors.rebrandingCardBorder,
iconOrAction: Container(
padding: const EdgeInsets.all(12),
decoration: const BoxDecoration(
color: AppColors.rebrandingCardBorder,
shape: BoxShape.circle,
),
child: const Icon(
Icons.palette,
color: Colors.white,
size: 32,
),
),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_dashboardData!['rebranding']['status'],
style: AppTextStyles.headlineMedium,
),
const SizedBox(height: 8),
OutlinedButton(
onPressed: () {},
style: OutlinedButton.styleFrom(
foregroundColor:
AppColors.rebrandingCardBorder,
side: const BorderSide(
color: AppColors.rebrandingCardBorder,
),
),
child: const Text('سفارش'),
),
],
),
),
),
],
);
},
),
const SizedBox(height: 32),
Text(
'عملکرد ۳۰ روز گذشته',
style: AppTextStyles.headlineMedium,
),
const SizedBox(height: 16),
FadeTransition(
opacity: CurvedAnimation(
parent: _staggerController,
curve: const Interval(0.6, 1.0, curve: Curves.easeOut),
),
child: ActivityChart(
data: List<Map<String, dynamic>>.from(
_dashboardData!['chart_data'],
),
),
),
],
),
),
);
}
Widget _buildAnimatedCard(int index, double width, Widget card) {
final interval = Interval(
index * 0.15,
(index * 0.15) + 0.4,
curve: Curves.easeOut,
);
return SizedBox(
width: width,
child: SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 0.3),
end: Offset.zero,
).animate(CurvedAnimation(parent: _staggerController, curve: interval)),
child: FadeTransition(
opacity: CurvedAnimation(parent: _staggerController, curve: interval),
child: card,
),
),
);
}
}