diff --git a/tools/chatgui/src/messagedelegate.cpp b/tools/chatgui/src/messagedelegate.cpp index e116b6ab..cc7d8307 100644 --- a/tools/chatgui/src/messagedelegate.cpp +++ b/tools/chatgui/src/messagedelegate.cpp @@ -23,11 +23,13 @@ #include #include #include +#include MessageDelegate::MessageDelegate(QObject *parent) : QStyledItemDelegate(parent) {} struct VoicePlayState { + bool loading = false; bool playing = false; bool paused = false; qint64 startMs = 0; @@ -48,6 +50,7 @@ static void ensureVoiceTimer() { bool anyActive = false; SoundManager* sm = SoundManager::instance(); for (auto it = s_voiceStates.begin(); it != s_voiceStates.end(); ++it) { + if (it->loading) { anyActive = true; continue; } if (!it->playing && !it->paused) { if (it->displayFrac > 0.001f || it->displayElapsed > 0.001f) anyActive = true; continue; @@ -161,6 +164,7 @@ bool MessageDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, ensureVoiceTimer(); VoicePlayState& st = s_voiceStates[filePath]; + if (st.loading) return true; QString durStr = index.data(MsgVoiceDurationRole).toString(); durStr.remove('s'); @@ -175,21 +179,21 @@ bool MessageDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, if (!st.playing && !st.paused) { /* Start playback then seek */ - float actualDur = VoicePlayer::playOpusFile(filePath); - if (actualDur <= 0.0f) return false; - targetSec = clickFrac * actualDur; - st.playing = true; - st.paused = false; - st.durationSec = actualDur; - st.startMs = now - (qint64)(targetSec * 1000.0); - st.pausedPosSec = targetSec; - st.displayFrac = (targetSec > 0 && actualDur > 0) ? (targetSec / actualDur) : 0; - st.displayElapsed = targetSec; - int sr = SoundManager::instance()->currentPcmSampleRate(); - if (sr > 0) - SoundManager::instance()->seekCurrentPcm((unsigned long long)(targetSec * sr)); + st.loading = true; + QPersistentModelIndex persistent(index); + VoicePlayer::playOpusFile(filePath, this, [filePath, clickFrac, persistent](float actualDur) { + s_voiceStates[filePath].loading = false; + if (actualDur <= 0) return; + MessageDelegate::startAutoPlay(filePath, actualDur); + float position = clickFrac * actualDur; + auto& state = s_voiceStates[filePath]; + state.startMs -= (qint64)(position * 1000); state.pausedPosSec = position; + state.displayFrac = clickFrac; state.displayElapsed = position; + int rate = SoundManager::instance()->currentPcmSampleRate(); + if (rate > 0) SoundManager::instance()->seekCurrentPcm((unsigned long long)(position * rate)); + if (persistent.isValid()) const_cast(persistent.model())->setData(persistent, 1, MsgVoicePlayStateRole); + }); s_voiceTimer->start(); - model->setData(index, 1, MsgVoicePlayStateRole); } else { /* Currently playing or paused — seek */ st.startMs = now - (qint64)(targetSec * 1000.0); @@ -246,18 +250,15 @@ bool MessageDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, SoundManager::instance()->stopCurrentPcm(); } - float actualDur = VoicePlayer::playOpusFile(filePath); - if (actualDur <= 0.0f) return false; - st.playing = true; - st.paused = false; - st.pausedPosSec = 0; - st.startMs = QDateTime::currentMSecsSinceEpoch(); - st.durationSec = actualDur; - st.displayFrac = 0; - st.displayElapsed = 0; - + st.loading = true; + QPersistentModelIndex persistent(index); + VoicePlayer::playOpusFile(filePath, this, [filePath, persistent](float actualDur) { + s_voiceStates[filePath].loading = false; + if (actualDur <= 0) return; + MessageDelegate::startAutoPlay(filePath, actualDur); + if (persistent.isValid()) const_cast(persistent.model())->setData(persistent, 1, MsgVoicePlayStateRole); + }); s_voiceTimer->start(); - model->setData(index, 1, MsgVoicePlayStateRole); return true; } @@ -1492,6 +1493,7 @@ void MessageDelegate::drawAvatar(QPainter *p, const Layout &L, } void MessageDelegate::startAutoPlay(const QString& filePath, float actualDurationSec) { + if (actualDurationSec <= 0) return; ensureVoiceTimer(); VoicePlayState& st = s_voiceStates[filePath]; st.playing = true; @@ -1506,6 +1508,8 @@ void MessageDelegate::startAutoPlay(const QString& filePath, float actualDuratio } void MessageDelegate::stopAllAutoPlay() { - for (auto it = s_voiceStates.begin(); it != s_voiceStates.end(); ++it) - it->playing = false; + VoicePlayer::cancelPending(); + for (auto it = s_voiceStates.begin(); it != s_voiceStates.end(); ++it) { + it->playing = false; it->paused = false; it->loading = false; + } } diff --git a/tools/chatgui/src/messagelist.cpp b/tools/chatgui/src/messagelist.cpp index bd8cc11e..d746ab0a 100644 --- a/tools/chatgui/src/messagelist.cpp +++ b/tools/chatgui/src/messagelist.cpp @@ -960,8 +960,7 @@ void MessageList::onAttachmentDownloaded(const QString& chId, int64_t msgId) { if (!fp.isEmpty() && QFile::exists(fp)) { QTimer::singleShot(500, this, [this, fp]() { MessageDelegate::stopAllAutoPlay(); - float actualDur = VoicePlayer::playOpusFile(fp); - MessageDelegate::startAutoPlay(fp, actualDur); + VoicePlayer::playOpusFile(fp, this, [fp](float actualDur) { MessageDelegate::startAutoPlay(fp, actualDur); }); }); } }