You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I am developing a chat app using flutter's getx framework. I found that when I receive a voice message and play the audio, the ripple shows that it has been played, but the voice is still playing. When I do not limit the width of the ripple, it can be displayed normally and ends synchronously. Within the fixed width of the conversation bubble, my ripple does not seem to have a way to compress its width to ensure that it can be fully displayed within the conversation bubble.
这是我语音logic中的代码
`
class DmAudioMessageLogic extends GetxController {
String tag = 'DMAudioMessageLogic';
ROLog log;
double maxWidth;
String uid;
final DmAudioMessageState state = DmAudioMessageState();
final PlayerController playerController = PlayerController();
late StreamSubscription playerStateSubscription;
List waveformData = [];
late PlayerWaveStyle playerWaveStyle;
I am developing a chat app using flutter's getx framework. I found that when I receive a voice message and play the audio, the ripple shows that it has been played, but the voice is still playing. When I do not limit the width of the ripple, it can be displayed normally and ends synchronously. Within the fixed width of the conversation bubble, my ripple does not seem to have a way to compress its width to ensure that it can be fully displayed within the conversation bubble.
这是我语音logic中的代码
`
class DmAudioMessageLogic extends GetxController {
String tag = 'DMAudioMessageLogic';
ROLog log;
double maxWidth;
String uid;
DmAudioMessageLogic(
{required this.log, required this.maxWidth, required this.uid});
final DmAudioMessageState state = DmAudioMessageState();
final PlayerController playerController = PlayerController();
late StreamSubscription playerStateSubscription;
List waveformData = [];
late PlayerWaveStyle playerWaveStyle;
@OverRide
void onInit() {
super.onInit();
playerWaveStyle = PlayerWaveStyle(
fixedWaveColor: const Color(0xFFD8D8D8),
liveWaveColor: log.incoming
? DMColor.textColorPrimary
: DMColor.btnColorPrimary,
spacing: 3,
waveThickness: 2);
initDate(); // 初始化数据
autoDownLoad();
playerStateSubscription =
playerController.onPlayerStateChanged.listen((onData) {
DMLogHelper.logInfo(tag, "${playerController.playerKey}--状态更新--$onData");
if (onData == PlayerState.paused) {
state.isPlaying.value = false;
}
});
}
/// 下载语音
Future autoDownLoad() async {
File file = File(log.fileUrl!.absoluteFilePath!);
if (!await file.exists()) {
DMLogHelper.logInfo(tag, "文件不存在");
String signedUrl = log.fileUrl!.url!.signedUrl;
String savePath = log.fileUrl!.absoluteFilePath!;
await DMHttpHelper().dio.download(signedUrl, savePath,
onReceiveProgress: (count, total) {
if (total == count) {
state.isDownLoaded.value = true;
} else {
state.downLoadProgress.value = count / total;
}
});
}
if (await file.exists()) {
state.isDownLoaded.value = true;
await preparePlayer(file);
}
}
/// 准备播放器
Future preparePlayer(File file) async {
DMLogHelper.logInfo(tag, "准备播放器");
}
/// 从 .dat 文件中提取波纹
initDate() {
try {
File file = File(log.fileUrl!.absolutePreviewFilePath!);
String jsonString = file.readAsStringSync();
DMLogHelper.logInfo(tag, 'json string $jsonString');
List decodedList = json.decode(jsonString);
waveformData =
decodedList.map((dynamic item) => (item as double) / 10.0).toList();
} catch (error) {
DMLogHelper.logError(tag, "读取波形数据失败: $error");
}
final duration = Duration(seconds: log.fileUrl!.duration!.round());
final minutes = duration.inMinutes.remainder(60).toString().padLeft(2, '0');
final remainingSeconds =
duration.inSeconds.remainder(60).toString().padLeft(2, '0');
state.audioTime.value = '${minutes}:${remainingSeconds}';
}
/// 播放语音
playAudio() async {
DMLogHelper.logInfo(tag, "处理语音--${(playerController.playerState)}");
}
/// 音频波形的实际宽度
/// 0-29s 宽度自适应 minWidth = 62,音频波形宽度 = 62+(录制时长-1)*4
/// 30-59s 178
/// >60 气泡最大宽度-74
double getWidth() {
final duration = log.fileUrl?.duration ?? 0;
if (duration < 30) {
return math.max(62, 62 + (duration * 4));
} else if (duration < 60) {
return 178;
} else {
return maxWidth - 74;
}
}
/// 处理发送按钮
void dealSendIcon() {
if (log.state == DMConstants.messageStateSendOk) {
state.isSendOver.value = true;
} else if (log.state == DMConstants.messageStateSendFail) {
state.isSendOver.value = true;
}
}
}
这是我语音气泡的widget view
class DMAudioMessagePage extends StatelessWidget {double maxWidth = 0.0;
ROLog log;
BorderRadius borderRadius;
DMAudioMessagePage(
{super.key,
required this.maxWidth,
required this.borderRadius,
required this.log});
@OverRide
Widget build(BuildContext context) {
double minWidth = 136;
double minHeight = 68;
return GetBuilder(
tag: log.imdnId,
builder: (logic) {
return GestureDetector(
onTap: () => logic.playAudio(),
child: Padding(
padding: EdgeInsets.only(left: log.incoming ? 16 : 0),
child: IntrinsicWidth(
child: ConstrainedBox(
constraints:
BoxConstraints(maxWidth: maxWidth, minHeight: minHeight),
child: Container(
constraints: BoxConstraints(minWidth: minWidth),
decoration: BoxDecoration(
color: log.incoming
? messageBubbleBackground(context)
: Theme.of(context).primaryColor,
borderRadius: borderRadius,
),
padding: const EdgeInsets.symmetric(
vertical: 11, horizontal: 12),
child: IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Obx(() {
return buildIcon(logic);
}),
const SizedBox(width: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 音频条
AudioFileWaveforms(
size: Size(logic.getWidth(), 24.0),
// 提取数据后立即显示波形
waveformData: logic.waveformData,
playerController: logic.playerController,
// 波形类型
waveformType: WaveformType.fitWidth,
playerWaveStyle: logic.playerWaveStyle,
),
// 时长条
const SizedBox(height: 4),
audioTime(logic),
],
)
],
),
),
),
),
),
),
);
});
}
这是在聊天界面中使用它的部分
/// 语音消息Widget buildAudioMessage(
ROLog log, DmImLogic logic, BorderRadius borderRadius) {
double maxWidth = sDeviceInfo.idiom != 'pad'
? logic.state.currentViewWidth * 0.725
: logic.state.currentViewWidth * 0.5625;
Get.put(DmAudioMessageLogic(log: log, maxWidth: maxWidth, uid: uid),
tag: log.imdnId);
return GetBuilder(
tag: log.imdnId,
builder: (logic) {
return DMAudioMessagePage(
key: ValueKey(log.imdnId),
borderRadius: borderRadius,
log: log,
maxWidth: maxWidth,
);
});
}`
我的波纹数据是从预览文件中提取出来的
The text was updated successfully, but these errors were encountered: