Files
packet/lib/presentation/widgets/audio_recorder.dart

107 lines
2.7 KiB
Dart
Raw Permalink Normal View History

import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:record/record.dart';
import 'package:path_provider/path_provider.dart';
class AudioRecorderButton extends StatefulWidget {
final void Function(Uint8List bytes, String nombre) onRecorded;
const AudioRecorderButton({super.key, required this.onRecorded});
@override
State<AudioRecorderButton> createState() => _AudioRecorderButtonState();
}
class _AudioRecorderButtonState extends State<AudioRecorderButton> {
final _recorder = AudioRecorder();
bool _isRecording = false;
int _seconds = 0;
Timer? _timer;
@override
void dispose() {
_timer?.cancel();
_recorder.dispose();
super.dispose();
}
Future<void> _toggleRecording() async {
if (_isRecording) {
await _stopRecording();
} else {
await _startRecording();
}
}
Future<void> _startRecording() async {
final hasPermission = await _recorder.hasPermission();
if (!hasPermission) return;
final dir = await getTemporaryDirectory();
final path = '${dir.path}/audio_${DateTime.now().millisecondsSinceEpoch}.m4a';
await _recorder.start(
const RecordConfig(encoder: AudioEncoder.aacLc),
path: path,
);
setState(() {
_isRecording = true;
_seconds = 0;
});
_timer = Timer.periodic(const Duration(seconds: 1), (t) {
setState(() => _seconds++);
});
}
Future<void> _stopRecording() async {
_timer?.cancel();
final path = await _recorder.stop();
setState(() {
_isRecording = false;
_seconds = 0;
});
if (path != null) {
final file = File(path);
final bytes = await file.readAsBytes();
final nombre = 'audio_${DateTime.now().millisecondsSinceEpoch}.m4a';
widget.onRecorded(bytes, nombre);
await file.delete();
}
}
String _formatDuration(int seconds) {
final mins = seconds ~/ 60;
final secs = seconds % 60;
return '${mins.toString().padLeft(2, '0')}:${secs.toString().padLeft(2, '0')}';
}
@override
Widget build(BuildContext context) {
return FilledButton.tonal(
onPressed: _toggleRecording,
style: FilledButton.styleFrom(
backgroundColor:
_isRecording ? Theme.of(context).colorScheme.errorContainer : null,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
_isRecording ? Icons.stop : Icons.mic,
size: 18,
color: _isRecording ? Theme.of(context).colorScheme.error : null,
),
const SizedBox(width: 4),
Text(_isRecording ? _formatDuration(_seconds) : 'Audio'),
],
),
);
}
}