import 'dart:async'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:lucide_icons/lucide_icons.dart'; import 'package:fl_chart/fl_chart.dart'; class PatternControlScreen extends StatefulWidget { const PatternControlScreen({super.key}); @override State createState() => _PatternControlScreenState(); } class _PatternControlScreenState extends State { String? _activePattern; double _globalIntensity = 50; List _waveData = List.generate(20, (i) => FlSpot(i.toDouble(), 10)); Timer? _waveTimer; static const List> _patterns = [ {'id': 'pulse', 'name': '脉冲跳动', 'icon': LucideIcons.activity, 'color': Color(0xFFC084FC)}, {'id': 'wave', 'name': '深海潮汐', 'icon': LucideIcons.waves, 'color': Color(0xFF60A5FA)}, {'id': 'climb', 'name': '登峰造极', 'icon': LucideIcons.rotateCw, 'color': Color(0xFF34D399)}, {'id': 'storm', 'name': '雷雨风暴', 'icon': LucideIcons.zap, 'color': Color(0xFFFBBF24)}, {'id': 'chaos', 'name': '随机漫步', 'icon': LucideIcons.sliders, 'color': Color(0xFFF472B6)}, {'id': 'sos', 'name': 'SOS', 'icon': LucideIcons.power, 'color': Color(0xFFF87171)}, ]; @override void initState() { super.initState(); _startWaveAnimation(); } void _startWaveAnimation() { _waveTimer?.cancel(); _waveTimer = Timer.periodic(const Duration(milliseconds: 100), (_) { if (!mounted) return; setState(() { final random = Random(); _waveData = [ ..._waveData.sublist(1), FlSpot( 19, _activePattern != null ? random.nextDouble() * _globalIntensity + 20 : 10, ), ]; // Update x coordinates for (int i = 0; i < _waveData.length; i++) { _waveData[i] = FlSpot(i.toDouble(), _waveData[i].y); } }); }); } @override void dispose() { _waveTimer?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFF2E1065), body: SafeArea( child: Column( children: [ // Header Padding( padding: const EdgeInsets.fromLTRB(8, 8, 16, 16), child: Row( children: [ IconButton( onPressed: () => Navigator.of(context).pop(), icon: Icon(LucideIcons.chevronLeft, color: Colors.white.withOpacity(0.7)), ), const Text( '波形控制', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.white, ), ), ], ), ), // Wave Chart Container( height: 140, margin: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white.withOpacity(0.05), borderRadius: BorderRadius.circular(24), border: Border.all(color: Colors.white.withOpacity(0.1)), ), child: LineChart( LineChartData( gridData: const FlGridData(show: false), titlesData: const FlTitlesData(show: false), borderData: FlBorderData(show: false), minX: 0, maxX: 19, minY: 0, maxY: 100, lineBarsData: [ LineChartBarData( spots: _waveData, isCurved: true, curveSmoothness: 0.3, color: const Color(0xFFE9D5FF), barWidth: 3, isStrokeCapRound: true, dotData: const FlDotData(show: false), belowBarData: BarAreaData( show: true, gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ const Color(0xFFC084FC).withOpacity(0.6), const Color(0xFFC084FC).withOpacity(0), ], ), ), ), ], lineTouchData: const LineTouchData(enabled: false), ), ), ), const SizedBox(height: 24), // Intensity Slider Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '强度', style: TextStyle( fontSize: 12, letterSpacing: 2, color: Colors.white.withOpacity(0.6), ), ), Text( '${_globalIntensity.toInt()}%', style: TextStyle( fontSize: 12, letterSpacing: 2, color: Colors.white.withOpacity(0.6), ), ), ], ), const SizedBox(height: 8), SliderTheme( data: SliderThemeData( trackHeight: 8, thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 10), overlayShape: const RoundSliderOverlayShape(overlayRadius: 20), activeTrackColor: const Color(0xFFC084FC), inactiveTrackColor: Colors.white.withOpacity(0.2), thumbColor: Colors.white, ), child: Slider( value: _globalIntensity, min: 0, max: 100, onChanged: (value) => setState(() => _globalIntensity = value), ), ), ], ), ), const SizedBox(height: 24), // Pattern Grid Expanded( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: GridView.builder( padding: const EdgeInsets.only(bottom: 24), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 12, mainAxisSpacing: 12, childAspectRatio: 1.5, ), itemCount: _patterns.length, itemBuilder: (context, index) { final pattern = _patterns[index]; final isActive = _activePattern == pattern['id']; return GestureDetector( onTap: () { setState(() { _activePattern = isActive ? null : pattern['id'] as String; }); HapticFeedback.selectionClick(); }, child: AnimatedContainer( duration: const Duration(milliseconds: 300), decoration: BoxDecoration( color: isActive ? Colors.white : Colors.white.withOpacity(0.05), borderRadius: BorderRadius.circular(16), border: Border.all( color: isActive ? Colors.white : Colors.white.withOpacity(0.1), ), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: isActive ? const Color(0xFF2E1065).withOpacity(0.1) : Colors.white.withOpacity(0.05), shape: BoxShape.circle, ), child: Icon( pattern['icon'] as IconData, size: 18, color: isActive ? const Color(0xFF2E1065) : pattern['color'] as Color, ), ), const SizedBox(height: 8), Text( pattern['name'] as String, style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: isActive ? const Color(0xFF2E1065) : Colors.white.withOpacity(0.6), ), ), ], ), ), ); }, ), ), ), ], ), ), ); } }