import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:leaderboard/features/voiceComments/repostiroies/comment_data_firestore.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'dart:math' as math;
class RecordingPage extends ConsumerStatefulWidget {
final String newsId;
const RecordingPage({Key? key, required this.newsId}) : super(key: key);
@override
ConsumerState<RecordingPage> createState() => _RecordingPageState();
}
class _RecordingPageState extends ConsumerState<RecordingPage>
with SingleTickerProviderStateMixin {
FlutterSoundRecorder? _recorder;
bool _isRecording = false;
int _remainingSeconds = 30; // Changed to 30 seconds
Timer? _timer;
late AnimationController _animationController;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_initRecorder();
_animationController = AnimationController(
vsync: this,
duration: const Duration(seconds: 30), // Changed to 30 seconds
);
_animation = Tween<double>(begin: 1, end: 0).animate(_animationController);
}
Future<void> _initRecorder() async {
final status = await Permission.microphone.request();
if (status != PermissionStatus.granted) {
throw RecordingPermissionException('Microphone permission not granted');
}
_recorder = FlutterSoundRecorder();
await _recorder!.openRecorder();
}
void _startRecording() async {
if (_recorder == null) return;
await _recorder!.startRecorder(toFile: 'audio.aac');
_startTimer();
_animationController.forward();
setState(() {
_isRecording = true;
_remainingSeconds = 30; // Reset to 30 seconds
});
}
void _stopRecording() async {
if (_recorder == null) return;
final path = await _recorder!.stopRecorder();
_timer?.cancel();
_animationController.stop();
if (path != null) {
final voiceCommentProvider = ref.read(voiceCommentFirestoreProvider);
await voiceCommentProvider.addVoiceComment(
newsId: widget.newsId,
audioFilePath: path,
);
}
setState(() {
_isRecording = false;
});
Navigator.of(context).pop(); // Close the overlay
}
void _startTimer() {
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
setState(() {
if (_remainingSeconds > 0) {
_remainingSeconds--;
} else {
_stopRecording();
}
});
});
}
@override
void dispose() {
_recorder?.closeRecorder();
_timer?.cancel();
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.black.withOpacity(0.5),
child: Center(
child: Container(
width: 200,
height: 200,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
child: AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return CustomPaint(
painter: RecordingProgressPainter(
animation: _animation,
backgroundColor: Colors.grey[300]!,
valueColor: Colors.blue,
),
child: child,
);
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'${(_remainingSeconds ~/ 60).toString().padLeft(2, '0')}:${(_remainingSeconds % 60).toString().padLeft(2, '0')}',
style: const TextStyle(
fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 20),
GestureDetector(
onTap: _isRecording ? _stopRecording : _startRecording,
child: Icon(
_isRecording ? Icons.stop : Icons.mic,
size: 50,
color: _isRecording ? Colors.red : Colors.blue,
),
),
],
),
),
),
),
);
}
}
class RecordingProgressPainter extends CustomPainter {
RecordingProgressPainter({
required this.animation,
required this.backgroundColor,
required this.valueColor,
}) : super(repaint: animation);
final Animation<double> animation;
final Color backgroundColor;
final Color valueColor;
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = backgroundColor
..strokeWidth = 10.0
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke;
canvas.drawCircle(size.center(Offset.zero), size.width / 2.0, paint);
paint.color = valueColor;
double progress = (1.0 - animation.value) * 2 * math.pi;
canvas.drawArc(
Offset.zero & size,
-math.pi / 2,
progress,
false,
paint,
);
}
@override
bool shouldRepaint(RecordingProgressPainter oldDelegate) {
return animation != oldDelegate.animation ||
backgroundColor != oldDelegate.backgroundColor ||
valueColor != oldDelegate.valueColor;
}
}
RAW Paste Data
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:leaderboard/features/voiceComments/repostiroies/comment_data_firestore.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'dart:math' as math;
class RecordingPage extends ConsumerStatefulWidget {
final String newsId;
const RecordingPage({Key? key, required this.newsId}) : super(key: key);
@override
ConsumerState<RecordingPage> createState() => _RecordingPageState();
}
class _RecordingPageState extends ConsumerState<RecordingPage>
with SingleTickerProviderStateMixin {
FlutterSoundRecorder? _recorder;
bool _isRecording = false;
int _remainingSeconds = 30; // Changed to 30 seconds
Timer? _timer;
late AnimationController _animationController;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_initRecorder();
_animationController = AnimationController(
vsync: this,
duration: const Duration(seconds: 30), // Changed to 30 seconds
);
_animation = Tween<double>(begin: 1, end: 0).animate(_animationController);
}
Future<void> _initRecorder() async {
final status = await Permission.microphone.request();
if (status != PermissionStatus.granted) {
throw RecordingPermissionException('Microphone permission not granted');
}
_recorder = FlutterSoundRecorder();
await _recorder!.openRecorder();
}
void _startRecording() async {
if (_recorder == null) return;
await _recorder!.startRecorder(toFile: 'audio.aac');
_startTimer();
_animationController.forward();
setState(() {
_isRecording = true;
_remainingSeconds = 30; // Reset to 30 seconds
});
}
void _stopRecording() async {
if (_recorder == null) return;
final path = await _recorder!.stopRecorder();
_timer?.cancel();
_animationController.stop();
if (path != null) {
final voiceCommentProvider = ref.read(voiceCommentFirestoreProvider);
await voiceCommentProvider.addVoiceComment(
newsId: widget.newsId,
audioFilePath: path,
);
}
setState(() {
_isRecording = false;
});
Navigator.of(context).pop(); // Close the overlay
}
void _startTimer() {
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
setState(() {
if (_remainingSeconds > 0) {
_remainingSeconds--;
} else {
_stopRecording();
}
});
});
}
@override
void dispose() {
_recorder?.closeRecorder();
_timer?.cancel();
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.black.withOpacity(0.5),
child: Center(
child: Container(
width: 200,
height: 200,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
child: AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return CustomPaint(
painter: RecordingProgressPainter(
animation: _animation,
backgroundColor: Colors.grey[300]!,
valueColor: Colors.blue,
),
child: child,
);
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'${(_remainingSeconds ~/ 60).toString().padLeft(2, '0')}:${(_remainingSeconds % 60).toString().padLeft(2, '0')}',
style: const TextStyle(
fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 20),
GestureDetector(
onTap: _isRecording ? _stopRecording : _startRecording,
child: Icon(
_isRecording ? Icons.stop : Icons.mic,
size: 50,
color: _isRecording ? Colors.red : Colors.blue,
),
),
],
),
),
),
),
);
}
}
class RecordingProgressPainter extends CustomPainter {
RecordingProgressPainter({
required this.animation,
required this.backgroundColor,
required this.valueColor,
}) : super(repaint: animation);
final Animation<double> animation;
final Color backgroundColor;
final Color valueColor;
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = backgroundColor
..strokeWidth = 10.0
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke;
canvas.drawCircle(size.center(Offset.zero), size.width / 2.0, paint);
paint.color = valueColor;
double progress = (1.0 - animation.value) * 2 * math.pi;
canvas.drawArc(
Offset.zero & size,
-math.pi / 2,
progress,
false,
paint,
);
}
@override
bool shouldRepaint(RecordingProgressPainter oldDelegate) {
return animation != oldDelegate.animation ||
backgroundColor != oldDelegate.backgroundColor ||
valueColor != oldDelegate.valueColor;
}
}