2026-03-14 00:00:01 +01:00
|
|
|
// ===========================================================================
|
|
|
|
|
// FILE: lib/widgets/music_theme_widgets.dart
|
|
|
|
|
// ===========================================================================
|
|
|
|
|
|
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
import '../core/app_colors.dart';
|
|
|
|
|
import 'painters.dart';
|
|
|
|
|
|
|
|
|
|
class MusicCassetteCard extends StatelessWidget {
|
|
|
|
|
final String title;
|
|
|
|
|
final String subtitle;
|
|
|
|
|
final Color neonColor;
|
|
|
|
|
final double angle;
|
|
|
|
|
final IconData leftIcon;
|
|
|
|
|
final IconData rightIcon;
|
|
|
|
|
final VoidCallback onTap;
|
|
|
|
|
final AppThemeType themeType;
|
|
|
|
|
|
2026-03-15 16:00:01 +01:00
|
|
|
const MusicCassetteCard({
|
|
|
|
|
super.key,
|
|
|
|
|
required this.title,
|
|
|
|
|
required this.subtitle,
|
|
|
|
|
required this.neonColor,
|
|
|
|
|
required this.angle,
|
|
|
|
|
required this.leftIcon,
|
|
|
|
|
required this.rightIcon,
|
|
|
|
|
required this.onTap,
|
|
|
|
|
required this.themeType
|
|
|
|
|
});
|
2026-03-14 00:00:01 +01:00
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
2026-03-15 16:00:01 +01:00
|
|
|
// Calcoliamo la scala in base all'altezza dello schermo per strizzare la cassetta
|
|
|
|
|
final double screenHeight = MediaQuery.of(context).size.height;
|
|
|
|
|
final double vScale = (screenHeight / 850.0).clamp(0.65, 1.0);
|
|
|
|
|
|
2026-03-14 00:00:01 +01:00
|
|
|
return Transform.rotate(
|
|
|
|
|
angle: angle,
|
|
|
|
|
child: GestureDetector(
|
|
|
|
|
onTap: onTap,
|
|
|
|
|
child: Container(
|
2026-03-15 16:00:01 +01:00
|
|
|
height: 125 * vScale, // Altezza dinamica!
|
|
|
|
|
margin: EdgeInsets.symmetric(vertical: 8 * vScale, horizontal: 10),
|
|
|
|
|
padding: EdgeInsets.all(12 * vScale),
|
2026-03-14 00:00:01 +01:00
|
|
|
decoration: BoxDecoration(
|
2026-03-15 16:00:01 +01:00
|
|
|
color: const Color(0xFF22222A),
|
|
|
|
|
borderRadius: BorderRadius.circular(8),
|
|
|
|
|
border: Border.all(color: Colors.black87, width: 2),
|
|
|
|
|
boxShadow: [
|
|
|
|
|
BoxShadow(color: neonColor.withOpacity(0.5), blurRadius: 25, spreadRadius: 2),
|
|
|
|
|
const BoxShadow(color: Colors.black54, offset: Offset(5, 10), blurRadius: 15)
|
|
|
|
|
]
|
2026-03-14 00:00:01 +01:00
|
|
|
),
|
|
|
|
|
child: Column(
|
|
|
|
|
children: [
|
|
|
|
|
Expanded(
|
|
|
|
|
child: Container(
|
2026-03-15 16:00:01 +01:00
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: neonColor.withOpacity(0.15),
|
|
|
|
|
borderRadius: BorderRadius.circular(4),
|
|
|
|
|
border: Border.all(color: neonColor.withOpacity(0.5), width: 1.5)
|
|
|
|
|
),
|
2026-03-14 00:00:01 +01:00
|
|
|
child: Row(
|
|
|
|
|
children: [
|
2026-03-15 16:00:01 +01:00
|
|
|
Padding(
|
|
|
|
|
padding: EdgeInsets.symmetric(horizontal: 12 * vScale),
|
|
|
|
|
child: Icon(leftIcon, color: neonColor, size: 28 * vScale)
|
|
|
|
|
),
|
2026-03-14 00:00:01 +01:00
|
|
|
Expanded(
|
|
|
|
|
child: Column(
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
|
children: [
|
2026-03-15 16:00:01 +01:00
|
|
|
Flexible(
|
|
|
|
|
child: FittedBox(
|
|
|
|
|
fit: BoxFit.scaleDown,
|
|
|
|
|
child: Text(title, style: getSharedTextStyle(themeType, TextStyle(color: Colors.white, fontSize: 20 * vScale, fontWeight: FontWeight.w900, shadows: [Shadow(color: neonColor, blurRadius: 10)])))
|
|
|
|
|
)
|
|
|
|
|
),
|
|
|
|
|
Flexible(
|
|
|
|
|
child: FittedBox(
|
|
|
|
|
fit: BoxFit.scaleDown,
|
|
|
|
|
child: Text(subtitle, style: getSharedTextStyle(themeType, TextStyle(color: Colors.white70, fontSize: 11 * vScale, fontWeight: FontWeight.bold)))
|
|
|
|
|
)
|
|
|
|
|
),
|
2026-03-14 00:00:01 +01:00
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
2026-03-15 16:00:01 +01:00
|
|
|
Padding(
|
|
|
|
|
padding: EdgeInsets.symmetric(horizontal: 12 * vScale),
|
|
|
|
|
child: Icon(rightIcon, color: neonColor, size: 28 * vScale)
|
|
|
|
|
),
|
2026-03-14 00:00:01 +01:00
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2026-03-15 16:00:01 +01:00
|
|
|
SizedBox(height: 10 * vScale),
|
2026-03-14 00:00:01 +01:00
|
|
|
Container(
|
2026-03-15 16:00:01 +01:00
|
|
|
height: 35 * vScale,
|
|
|
|
|
width: 180 * vScale,
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: const Color(0xFF0D0D12),
|
|
|
|
|
borderRadius: BorderRadius.circular(20),
|
|
|
|
|
border: Border.all(color: Colors.white24, width: 1)
|
|
|
|
|
),
|
2026-03-14 00:00:01 +01:00
|
|
|
child: Stack(
|
|
|
|
|
alignment: Alignment.center,
|
|
|
|
|
children: [
|
2026-03-15 16:00:01 +01:00
|
|
|
Container(height: 2, width: 120 * vScale, color: const Color(0xFF333333)),
|
|
|
|
|
Row(
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
|
|
|
children: [ _buildSpool(vScale), _buildSpool(vScale) ]
|
|
|
|
|
),
|
2026-03-14 00:00:01 +01:00
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-15 16:00:01 +01:00
|
|
|
Widget _buildSpool(double vScale) {
|
2026-03-14 00:00:01 +01:00
|
|
|
return Container(
|
2026-03-15 16:00:01 +01:00
|
|
|
width: 26 * vScale,
|
|
|
|
|
height: 26 * vScale,
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
shape: BoxShape.circle,
|
|
|
|
|
color: Colors.white70,
|
|
|
|
|
border: Border.all(color: Colors.black87, width: 5 * vScale)
|
|
|
|
|
),
|
|
|
|
|
child: Center(
|
|
|
|
|
child: Container(
|
|
|
|
|
width: 6 * vScale,
|
|
|
|
|
height: 6 * vScale,
|
|
|
|
|
decoration: const BoxDecoration(shape: BoxShape.circle, color: Colors.black)
|
|
|
|
|
)
|
|
|
|
|
),
|
2026-03-14 00:00:01 +01:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class MusicKnobCard extends StatelessWidget {
|
|
|
|
|
final String title;
|
|
|
|
|
final IconData icon;
|
|
|
|
|
final VoidCallback onTap;
|
|
|
|
|
final AppThemeType themeType;
|
|
|
|
|
final Color? iconColor;
|
|
|
|
|
|
2026-03-15 16:00:01 +01:00
|
|
|
const MusicKnobCard({
|
|
|
|
|
super.key,
|
|
|
|
|
required this.title,
|
|
|
|
|
required this.icon,
|
|
|
|
|
required this.onTap,
|
|
|
|
|
required this.themeType,
|
|
|
|
|
this.iconColor
|
|
|
|
|
});
|
2026-03-14 00:00:01 +01:00
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
2026-03-15 16:00:01 +01:00
|
|
|
// Adattiamo anche le manopole in base all'altezza dello schermo
|
|
|
|
|
final double screenHeight = MediaQuery.of(context).size.height;
|
|
|
|
|
final double vScale = (screenHeight / 850.0).clamp(0.65, 1.0);
|
|
|
|
|
|
2026-03-14 00:00:01 +01:00
|
|
|
return GestureDetector(
|
|
|
|
|
onTap: onTap,
|
|
|
|
|
child: Column(
|
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
|
children: [
|
|
|
|
|
Container(
|
2026-03-15 16:00:01 +01:00
|
|
|
width: 65 * vScale,
|
|
|
|
|
height: 65 * vScale,
|
2026-03-14 00:00:01 +01:00
|
|
|
decoration: BoxDecoration(
|
2026-03-15 16:00:01 +01:00
|
|
|
shape: BoxShape.circle,
|
|
|
|
|
color: const Color(0xFF222222),
|
|
|
|
|
border: Border.all(color: const Color(0xFF111111), width: 2),
|
|
|
|
|
boxShadow: const [
|
|
|
|
|
BoxShadow(color: Colors.black87, blurRadius: 10, offset: Offset(2, 6)),
|
|
|
|
|
BoxShadow(color: Colors.white12, blurRadius: 2, offset: Offset(-1, -1))
|
|
|
|
|
],
|
2026-03-14 00:00:01 +01:00
|
|
|
),
|
|
|
|
|
child: Padding(
|
2026-03-15 16:00:01 +01:00
|
|
|
padding: EdgeInsets.all(6.0 * vScale),
|
2026-03-14 00:00:01 +01:00
|
|
|
child: Container(
|
|
|
|
|
decoration: BoxDecoration(
|
2026-03-15 16:00:01 +01:00
|
|
|
shape: BoxShape.circle,
|
|
|
|
|
border: Border.all(color: Colors.black54, width: 1),
|
2026-03-14 00:00:01 +01:00
|
|
|
gradient: const SweepGradient(colors: [Color(0xFF555555), Color(0xFFAAAAAA), Color(0xFF555555), Color(0xFF222222), Color(0xFF555555)]),
|
|
|
|
|
),
|
|
|
|
|
child: Padding(
|
2026-03-15 16:00:01 +01:00
|
|
|
padding: EdgeInsets.all(4.0 * vScale),
|
2026-03-14 00:00:01 +01:00
|
|
|
child: Container(
|
|
|
|
|
decoration: const BoxDecoration(shape: BoxShape.circle, color: Color(0xFF1A1A1A)),
|
2026-03-15 16:00:01 +01:00
|
|
|
child: Center(child: Icon(icon, color: iconColor ?? Colors.white70, size: 20 * vScale)),
|
2026-03-14 00:00:01 +01:00
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2026-03-15 16:00:01 +01:00
|
|
|
SizedBox(height: 10 * vScale),
|
|
|
|
|
FittedBox(
|
|
|
|
|
fit: BoxFit.scaleDown,
|
|
|
|
|
child: Text(title, style: getSharedTextStyle(themeType, TextStyle(color: Colors.white70, fontSize: 11 * vScale, fontWeight: FontWeight.bold, letterSpacing: 1.0)))
|
|
|
|
|
),
|
2026-03-14 00:00:01 +01:00
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|