完成录音功能

pull/1/head
张萌 3 years ago
parent 68b1a6c1b3
commit f623ea1f65

@ -56,4 +56,6 @@
<uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- 读取手机IMEI的设备权限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 麦克风权限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
</manifest>

@ -44,6 +44,7 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
TextEditingController _telController = TextEditingController();
String? _content;
List<File> _photos = [];
String? _voiceUri;
@override
void dispose() {
@ -818,7 +819,11 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
24.w.heightBox,
GestureDetector(
onTap: () async {
await Get.bottomSheet(BeeRecordVoiceWidget());
var re = await Get.bottomSheet(BeeRecordVoiceWidget());
if (re != null) {
_voiceUri = re;
}
setState(() {});
},
child: Material(
color: Colors.transparent,
@ -832,10 +837,14 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
.color(Colors.black.withOpacity(0.45))
.make(),
),
if (_voiceUri != null)
VoicePlayer(
url: '5d143e1b735b0.mp3',
path: _voiceUri,
showXmark: true,
onDelete: () {},
onDelete: () {
_voiceUri = null;
setState(() {});
},
),
Spacer(),
Icon(

@ -1,10 +1,12 @@
import 'dart:async';
import 'package:aku_new_community/base/base_style.dart';
import 'package:aku_new_community/extensions/num_ext.dart';
import 'package:aku_new_community/widget/bee_divider.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_sound/public/flutter_sound_recorder.dart';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:get/get.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:velocity_x/src/extensions/string_ext.dart';
@ -18,17 +20,78 @@ class BeeRecordVoiceWidget extends StatefulWidget {
class _BeeRecordVoiceWidgetState extends State<BeeRecordVoiceWidget> {
bool _inRecordVoice = false;
var myPlayer = FlutterSoundRecorder();
var myRecorder = FlutterSoundRecorder();
var myPlayer = FlutterSoundPlayer();
String? filePath;
String fileName = 'record.aac';
bool get reclaim => !_inRecordVoice && filePath != null;
bool get play => !_inRecordVoice && filePath != null;
Timer? _timer;
int _recordSeconds = 0;
int _maxSeconds = 0;
String get _recordTime {
var min = (_recordSeconds ~/ 60).toString();
if (min.length < 2) {
min = '0$min';
}
var sec = (_recordSeconds % 60).toString();
if (sec.length < 2) {
sec = '0$sec';
}
return '$min:$sec';
}
@override
void initState() {
myPlayer.openRecorder();
myRecorder.openRecorder();
myPlayer.openPlayer();
Future.delayed(Duration(seconds: 0), () async {
var permission = await Permission.microphone.isGranted;
print(permission);
if (!permission) {
await Permission.microphone.request();
}
});
super.initState();
}
void cancelTimer() {
_timer?.cancel();
_timer = null;
}
void startRecord() {
cancelTimer();
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
_recordSeconds++;
setState(() {});
});
}
void startPlay() {
cancelTimer();
_maxSeconds = _recordSeconds;
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
if (_recordSeconds == 0) {
cancelTimer();
_recordSeconds = _maxSeconds;
setState(() {});
} else {
_recordSeconds--;
setState(() {});
}
});
}
@override
void dispose() {
myPlayer.closeRecorder();
myRecorder.closeRecorder();
myPlayer.closePlayer();
cancelTimer();
super.dispose();
}
@ -50,8 +113,7 @@ class _BeeRecordVoiceWidgetState extends State<BeeRecordVoiceWidget> {
.color(Colors.black.withOpacity(0.85))
.make(),
20.hb,
'00:00'
.text
_recordTime.text
.size(24.sp)
.isIntrinsic
.bold
@ -65,27 +127,38 @@ class _BeeRecordVoiceWidgetState extends State<BeeRecordVoiceWidget> {
.text
.size(24.sp)
.isIntrinsic
.color(Colors.black.withOpacity(0.45))
.color(
reclaim ? kPrimaryColor : Colors.black.withOpacity(0.45))
.make(),
12.wb,
Icon(
GestureDetector(
onTap: reclaim
? () async {
myRecorder.deleteRecord(fileName: fileName);
filePath = null;
_recordSeconds = 0;
setState(() {});
}
: null,
child: Icon(
CupertinoIcons.mic_circle,
size: 60.w,
color: Colors.black.withOpacity(0.45),
color:
reclaim ? kPrimaryColor : Colors.black.withOpacity(0.45),
),
),
40.wb,
GestureDetector(
onTap: () async {
var permission = await Permission.microphone.isGranted;
if (!permission) {
await Permission.microphone.request();
}
if (myPlayer.isRecording) {
await myPlayer.pauseRecorder();
} else if (myPlayer.isPaused) {
await myPlayer.resumeRecorder();
if (myRecorder.isRecording) {
filePath = await myRecorder.stopRecorder();
cancelTimer();
} else {
await myPlayer.startRecorder();
if (filePath != null) {
myRecorder.deleteRecord(fileName: fileName);
}
await myRecorder.startRecorder(toFile: fileName);
startRecord();
}
_inRecordVoice = !_inRecordVoice;
setState(() {});
@ -113,16 +186,31 @@ class _BeeRecordVoiceWidgetState extends State<BeeRecordVoiceWidget> {
),
),
40.wb,
Icon(
GestureDetector(
onTap: play
? () async {
if (myPlayer.isPlaying) {
myPlayer.stopPlayer();
cancelTimer();
_recordSeconds = _maxSeconds;
setState(() {});
} else {
await myPlayer.startPlayer(fromURI: filePath);
startPlay();
}
}
: null,
child: Icon(
CupertinoIcons.play_circle,
size: 60.w,
color: Colors.black.withOpacity(0.45),
color: play ? kPrimaryColor : Colors.black.withOpacity(0.45),
),
),
12.wb,
'试听'
.text
.size(24.sp)
.color(Colors.black.withOpacity(0.45))
.color(play ? kPrimaryColor : Colors.black.withOpacity(0.45))
.isIntrinsic
.make()
],
@ -136,6 +224,8 @@ class _BeeRecordVoiceWidgetState extends State<BeeRecordVoiceWidget> {
onTap: () {
Get.back();
},
child: Material(
color: Colors.transparent,
child: Container(
height: 80.w,
alignment: Alignment.center,
@ -148,6 +238,7 @@ class _BeeRecordVoiceWidgetState extends State<BeeRecordVoiceWidget> {
),
),
),
),
Container(
height: 80.w,
width: 1.w,
@ -156,8 +247,10 @@ class _BeeRecordVoiceWidgetState extends State<BeeRecordVoiceWidget> {
Expanded(
child: GestureDetector(
onTap: () {
Get.back();
Get.back(result: filePath);
},
child: Material(
color: Colors.transparent,
child: Container(
height: 80.w,
alignment: Alignment.center,
@ -169,6 +262,7 @@ class _BeeRecordVoiceWidgetState extends State<BeeRecordVoiceWidget> {
.make(),
),
),
),
)
],
),

@ -9,13 +9,15 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:just_audio/just_audio.dart';
class VoicePlayer extends StatefulWidget {
final String url;
final String? url;
final VoidCallback? onDelete;
final bool showXmark;
final String? path;
const VoicePlayer(
{Key? key, required this.url, this.onDelete, this.showXmark = false})
: super(key: key);
{Key? key, this.url, this.onDelete, this.showXmark = false, this.path})
: assert(url != null || path != null),
super(key: key);
@override
_VoicePlayerState createState() => _VoicePlayerState();
@ -62,7 +64,11 @@ class _VoicePlayerState extends State<VoicePlayer>
}
Future initVoice() async {
if (widget.url != null) {
await player.setUrl(SARSAPI.image(widget.url));
} else {
await player.setFilePath(widget.path!);
}
_voiceLength = await player.load();
_currentLength = _voiceLength?.inSeconds ?? 0;
await player.setClip(start: Duration(seconds: 0), end: _voiceLength);

Loading…
Cancel
Save