multiples mejoras añadidas, se retiró la categoría
This commit is contained in:
@@ -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',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user