multiples mejoras añadidas, se retiró la categoría

This commit is contained in:
Abraham
2026-01-13 14:11:03 -08:00
parent cd23fdc071
commit 8612688aa3
8 changed files with 358 additions and 776 deletions

View File

@@ -79,31 +79,22 @@ class _PremiumDashboardPageState extends State<PremiumDashboardPage>
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildWelcomeHeader(),
const Gap(32),
/* _buildWelcomeHeader(),
const Gap(32), */
_buildStatsCards(isMobile),
const Gap(32),
if (!isMobile) ...[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(flex: 3, child: _buildCategoryChart()),
Expanded(flex: 2, child: _buildViewsChart()),
const Gap(24),
Expanded(flex: 2, child: _buildTopVideos()),
],
),
const Gap(24),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(flex: 2, child: _buildViewsChart()),
const Gap(24),
Expanded(flex: 3, child: _buildRecentActivity()),
],
),
_buildRecentActivity(),
] else ...[
_buildCategoryChart(),
const Gap(24),
_buildTopVideos(),
const Gap(24),
_buildViewsChart(),
@@ -189,9 +180,8 @@ class _PremiumDashboardPageState extends State<PremiumDashboardPage>
return _buildLoadingSkeleton(isMobile);
}
final totalVideos = stats['totalVideos'] ?? 0;
final totalViews = stats['totalReproducciones'] ?? 0;
final categories = stats['totalCategories'] ?? 0;
final totalVideos = stats['total_videos'] ?? 0;
final totalViews = stats['total_reproducciones'] ?? 0;
final avgViews = totalVideos > 0 ? (totalViews / totalVideos).round() : 0;
final cards = [
@@ -215,16 +205,6 @@ class _PremiumDashboardPageState extends State<PremiumDashboardPage>
trend: '+23%',
trendUp: true,
),
_StatCard(
title: 'Categorías',
value: categories.toString(),
icon: Icons.category,
gradient: const LinearGradient(
colors: [Color(0xFF6B2F8A), Color(0xFF9B4FC9)],
),
trend: '+5%',
trendUp: true,
),
_StatCard(
title: 'Promedio Vistas',
value: _formatNumber(avgViews),
@@ -249,12 +229,12 @@ class _PremiumDashboardPageState extends State<PremiumDashboardPage>
}
return GridView.count(
crossAxisCount: 4,
crossAxisCount: 3,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisSpacing: 20,
mainAxisSpacing: 20,
childAspectRatio: 1.5,
childAspectRatio: 2.2,
children: cards,
);
}
@@ -264,14 +244,14 @@ class _PremiumDashboardPageState extends State<PremiumDashboardPage>
baseColor: AppTheme.of(context).tertiaryBackground,
highlightColor: AppTheme.of(context).secondaryBackground,
child: GridView.count(
crossAxisCount: isMobile ? 1 : 4,
crossAxisCount: isMobile ? 1 : 3,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisSpacing: 20,
mainAxisSpacing: 20,
childAspectRatio: isMobile ? 3 : 1.5,
children: List.generate(
4,
3,
(index) => Container(
decoration: BoxDecoration(
color: Colors.white,
@@ -283,154 +263,6 @@ class _PremiumDashboardPageState extends State<PremiumDashboardPage>
);
}
Widget _buildCategoryChart() {
if (isLoading) {
return _buildChartSkeleton('Distribución por Categoría');
}
final videosByCategory =
stats['videosByCategory'] as Map<String, int>? ?? {};
return Container(
padding: const EdgeInsets.all(28),
decoration: BoxDecoration(
color: AppTheme.of(context).secondaryBackground,
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: AppTheme.of(context).primaryColor.withOpacity(0.1),
width: 1,
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 20,
offset: const Offset(0, 4),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: AppTheme.of(context).primaryColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
),
child: Icon(
Icons.pie_chart,
color: AppTheme.of(context).primaryColor,
size: 24,
),
),
const Gap(12),
Text(
'Distribución por Categoría',
style: AppTheme.of(context).title3.override(
fontFamily: 'Poppins',
color: AppTheme.of(context).primaryText,
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
],
),
const Gap(32),
SizedBox(
height: 280,
child: videosByCategory.isEmpty
? _buildEmptyChart('No hay datos de categorías')
: PieChart(
PieChartData(
sectionsSpace: 3,
centerSpaceRadius: 60,
sections: _buildPieChartSections(videosByCategory),
borderData: FlBorderData(show: false),
),
),
),
const Gap(24),
_buildLegend(videosByCategory),
],
),
);
}
List<PieChartSectionData> _buildPieChartSections(
Map<String, int> videosByCategory) {
final colors = [
const Color(0xFF4EC9F5),
const Color(0xFFFFB733),
const Color(0xFF6B2F8A),
const Color(0xFFFF2D2D),
const Color(0xFF00C9A7),
];
int index = 0;
return videosByCategory.entries.map((entry) {
final color = colors[index % colors.length];
index++;
return PieChartSectionData(
value: entry.value.toDouble(),
title: '${entry.value}',
color: color,
radius: 50,
titleStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Color(0xFF0B0B0D),
fontFamily: 'Poppins',
),
);
}).toList();
}
Widget _buildLegend(Map<String, int> videosByCategory) {
final colors = [
const Color(0xFF4EC9F5),
const Color(0xFFFFB733),
const Color(0xFF6B2F8A),
const Color(0xFFFF2D2D),
const Color(0xFF00C9A7),
];
int index = 0;
return Wrap(
spacing: 16,
runSpacing: 12,
children: videosByCategory.entries.map((entry) {
final color = colors[index % colors.length];
index++;
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 16,
height: 16,
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(4),
),
),
const Gap(8),
Text(
entry.key,
style: AppTheme.of(context).bodyText2.override(
fontFamily: 'Poppins',
color: AppTheme.of(context).secondaryText,
fontSize: 13,
),
),
],
);
}).toList(),
);
}
Widget _buildViewsChart() {
return Container(
padding: const EdgeInsets.all(28),
@@ -1008,98 +840,103 @@ class _StatCardState extends State<_StatCard>
onExit: (_) => setState(() => _isHovered = false),
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
transform: Matrix4.identity()..scale(_isHovered ? 1.03 : 1.0),
transform: Matrix4.identity()..scale(_isHovered ? 1.02 : 1.0),
child: Container(
padding: const EdgeInsets.all(24),
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
gradient: widget.gradient,
borderRadius: BorderRadius.circular(20),
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: widget.gradient.colors.first.withOpacity(0.3),
blurRadius: _isHovered ? 20 : 12,
offset: Offset(0, _isHovered ? 8 : 4),
color: widget.gradient.colors.first.withOpacity(0.25),
blurRadius: _isHovered ? 16 : 10,
offset: Offset(0, _isHovered ? 6 : 3),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
child: Row(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(10),
),
child: Icon(
widget.icon,
color: const Color(0xFF0B0B0D),
size: 24,
),
),
if (widget.trend != null)
// Icono y valor en la izquierda
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Icono
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 4),
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: widget.trendUp
? Colors.green.withOpacity(0.2)
: Colors.red.withOpacity(0.2),
borderRadius: BorderRadius.circular(12),
color: Colors.white.withOpacity(0.25),
borderRadius: BorderRadius.circular(10),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
widget.trendUp
? Icons.trending_up
: Icons.trending_down,
size: 14,
color: const Color(0xFF0B0B0D),
),
const Gap(4),
Text(
widget.trend!,
style: const TextStyle(
color: Color(0xFF0B0B0D),
fontSize: 11,
fontWeight: FontWeight.bold,
fontFamily: 'Poppins',
),
),
],
child: Icon(
widget.icon,
color: const Color(0xFF0B0B0D),
size: 22,
),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.value,
style: const TextStyle(
color: Color(0xFF0B0B0D),
fontSize: 32,
fontWeight: FontWeight.bold,
fontFamily: 'Poppins',
const Gap(12),
// Valor
Text(
widget.value,
style: const TextStyle(
color: Color(0xFF0B0B0D),
fontSize: 28,
fontWeight: FontWeight.bold,
fontFamily: 'Poppins',
height: 1.0,
),
),
),
const Gap(4),
Text(
widget.title,
style: TextStyle(
color: const Color(0xFF0B0B0D).withOpacity(0.8),
fontSize: 14,
fontFamily: 'Poppins',
fontWeight: FontWeight.w500,
const Gap(4),
// Título
Text(
widget.title,
style: TextStyle(
color: const Color(0xFF0B0B0D).withOpacity(0.75),
fontSize: 12,
fontFamily: 'Poppins',
fontWeight: FontWeight.w500,
),
),
),
],
],
),
),
// Trend badge a la derecha
if (widget.trend != null)
Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
decoration: BoxDecoration(
color: widget.trendUp
? Colors.white.withOpacity(0.3)
: Colors.black.withOpacity(0.2),
borderRadius: BorderRadius.circular(10),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
widget.trendUp
? Icons.trending_up
: Icons.trending_down,
size: 18,
color: const Color(0xFF0B0B0D),
),
const Gap(2),
Text(
widget.trend!,
style: const TextStyle(
color: Color(0xFF0B0B0D),
fontSize: 11,
fontWeight: FontWeight.bold,
fontFamily: 'Poppins',
),
),
],
),
),
],
),
),