134 lines
4.0 KiB
Dart
134 lines
4.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'dart:math' as math;
|
|
|
|
class AudioWaveformProgress extends StatelessWidget {
|
|
final double progress;
|
|
final bool isActive;
|
|
final ValueChanged<double>? onChanged;
|
|
|
|
const AudioWaveformProgress({
|
|
super.key,
|
|
required this.progress,
|
|
this.isActive = true,
|
|
this.onChanged,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return GestureDetector(
|
|
onTapDown: onChanged != null
|
|
? (details) {
|
|
final box = context.findRenderObject() as RenderBox;
|
|
final localPosition = details.localPosition;
|
|
final value = localPosition.dx / box.size.width;
|
|
onChanged?.call(value.clamp(0.0, 1.0));
|
|
}
|
|
: null,
|
|
onHorizontalDragUpdate: onChanged != null
|
|
? (details) {
|
|
final box = context.findRenderObject() as RenderBox;
|
|
final localPosition = details.localPosition;
|
|
final value = localPosition.dx / box.size.width;
|
|
onChanged?.call(value.clamp(0.0, 1.0));
|
|
}
|
|
: null,
|
|
child: Container(
|
|
height: 40,
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: CustomPaint(
|
|
painter: WaveformPainter(
|
|
progress: progress.clamp(0.0, 1.0),
|
|
isActive: isActive,
|
|
),
|
|
size: Size.infinite,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class WaveformPainter extends CustomPainter {
|
|
final double progress;
|
|
final bool isActive;
|
|
|
|
WaveformPainter({
|
|
required this.progress,
|
|
required this.isActive,
|
|
});
|
|
|
|
@override
|
|
void paint(Canvas canvas, Size size) {
|
|
final random = math.Random(42); // استفاده از seed ثابت برای consistency
|
|
const barCount = 60; // تعداد میلهها
|
|
final barWidth = (size.width / barCount) * 0.45; // عرض هر میله
|
|
final spacing = size.width / barCount;
|
|
|
|
final inactivePaint = Paint()
|
|
..color = const Color.fromARGB(255, 102, 102, 102)
|
|
..strokeWidth = barWidth
|
|
..strokeCap = StrokeCap.round;
|
|
|
|
final activePaint = Paint()
|
|
..color = const Color.fromARGB(255, 0, 126, 167)
|
|
..strokeWidth = barWidth
|
|
..strokeCap = StrokeCap.round;
|
|
|
|
// رسم میلههای موج صدا
|
|
for (int i = 0; i < barCount; i++) {
|
|
final x = i * spacing + spacing / 2;
|
|
|
|
// ارتفاع تصادفی برای هر میله (شبیهسازی موج صدا)
|
|
final randomHeight = random.nextDouble();
|
|
final minHeight = size.height * 0.2;
|
|
final maxHeight = size.height * 0.9;
|
|
final barHeight = minHeight + (randomHeight * (maxHeight - minHeight));
|
|
|
|
final y1 = (size.height - barHeight) / 2;
|
|
final y2 = y1 + barHeight;
|
|
|
|
// تعیین رنگ بر اساس progress
|
|
// استفاده از (i + 1) تا میله اول از 1/60 شروع بشه نه 0/60
|
|
final barProgress = (i + 1) / barCount;
|
|
final paint = barProgress <= progress && isActive ? activePaint : inactivePaint;
|
|
|
|
canvas.drawLine(
|
|
Offset(x, y1),
|
|
Offset(x, y2),
|
|
paint,
|
|
);
|
|
}
|
|
|
|
// // رسم thumb (دایره کوچک) در محل progress
|
|
// if (isActive && progress > 0) {
|
|
// final thumbX = progress * size.width;
|
|
// final thumbPaint = Paint()
|
|
// ..color = const Color(0xFF3B82F6)
|
|
// ..style = PaintingStyle.fill;
|
|
|
|
// canvas.drawCircle(
|
|
// Offset(thumbX, size.height / 2),
|
|
// 6,
|
|
// thumbPaint,
|
|
// );
|
|
|
|
// // سایه برای thumb
|
|
// final shadowPaint = Paint()
|
|
// ..color = const Color(0xFF3B82F6).withOpacity(0.3)
|
|
// ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 4);
|
|
|
|
// canvas.drawCircle(
|
|
// Offset(thumbX, size.height / 2),
|
|
// 8,
|
|
// shadowPaint,
|
|
// );
|
|
// }
|
|
}
|
|
|
|
@override
|
|
bool shouldRepaint(WaveformPainter oldDelegate) {
|
|
return oldDelegate.progress != progress || oldDelegate.isActive != isActive;
|
|
}
|
|
}
|