fix: true pause/resume with position preservation

- SoundManager: pauseCurrentPcm()/resumeCurrentPcm() — stop/start without destroy
- VoicePlayState: added paused/pausedPosSec fields
- editorEvent: 3-state logic — playing→pause, paused→resume, stopped→new
- Different file click: stops old with full cleanup, plays new from start
- Timer: skips paused items, full cleanup on auto-complete
This commit is contained in:
Evgeny committed 2026-07-27 08:07:19 +03:00
1 parent 830f729f52
commit 8bd4a7218c
3 files changed
+69 -21

No files matched your search

+59 -21
View File
@@ -25,8 +25,10 @@ MessageDelegate::MessageDelegate(QObject *parent)
struct VoicePlayState {
bool playing = false;
bool paused = false;
qint64 startMs = 0;
float durationSec = 0.0f;
float pausedPosSec = 0.0f;
};
static QMap<QString, VoicePlayState> s_voiceStates;
static QTimer* s_voiceTimer = nullptr;
@@ -39,10 +41,13 @@ static void ensureVoiceTimer() {
bool anyPlaying = false;
qint64 now = QDateTime::currentMSecsSinceEpoch();
for (auto it = s_voiceStates.begin(); it != s_voiceStates.end(); ) {
if (!it->playing && !it->paused) { ++it; continue; }
if (it->paused) { ++it; continue; }
if (!it->playing) { ++it; continue; }
float elapsed = (now - it->startMs) / 1000.0f;
if (elapsed >= it->durationSec && it->durationSec > 0) {
it->playing = false;
it->paused = false;
SoundManager::instance()->stopCurrentPcm();
++it;
} else {
@@ -51,7 +56,6 @@ static void ensureVoiceTimer() {
}
}
if (!anyPlaying) s_voiceTimer->stop();
// Trigger repaint through any visible view
if (auto* w = QApplication::activeWindow()) w->update();
});
}
@@ -75,29 +79,57 @@ bool MessageDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
ensureVoiceTimer();
VoicePlayState& st = s_voiceStates[filePath];
bool isOtherPlaying = false;
for (auto it = s_voiceStates.begin(); it != s_voiceStates.end(); ++it) {
if (it.key() != filePath && (it->playing || it->paused))
isOtherPlaying = true;
}
if (st.playing) {
/* Playing → Pause */
qint64 now = QDateTime::currentMSecsSinceEpoch();
st.pausedPosSec = (now - st.startMs) / 1000.0f;
st.playing = false;
SoundManager::instance()->stopCurrentPcm();
model->setData(index, 0, MsgVoicePlayStateRole);
} else {
for (auto it = s_voiceStates.begin(); it != s_voiceStates.end(); ++it)
it->playing = false;
SoundManager::instance()->stopCurrentPcm();
QString durStr = index.data(MsgVoiceDurationRole).toString();
durStr.remove('s');
float dur = durStr.toFloat();
if (dur <= 0) dur = 1.0f;
st.paused = true;
SoundManager::instance()->pauseCurrentPcm();
model->setData(index, 2, MsgVoicePlayStateRole);
return true;
}
if (st.paused) {
/* Paused → Resume */
st.paused = false;
st.playing = true;
st.startMs = QDateTime::currentMSecsSinceEpoch();
st.durationSec = dur;
VoicePlayer::playOpusFile(filePath);
qint64 now = QDateTime::currentMSecsSinceEpoch();
st.startMs = now - (qint64)(st.pausedPosSec * 1000.0);
SoundManager::instance()->resumeCurrentPcm();
s_voiceTimer->start();
model->setData(index, 1, MsgVoicePlayStateRole);
return true;
}
/* Stopped or different file → stop old, play new */
if (isOtherPlaying) {
for (auto it = s_voiceStates.begin(); it != s_voiceStates.end(); ++it) {
it->playing = false; it->paused = false;
}
SoundManager::instance()->stopCurrentPcm();
}
QString durStr = index.data(MsgVoiceDurationRole).toString();
durStr.remove('s');
float dur = durStr.toFloat();
if (dur <= 0) dur = 1.0f;
st.playing = true;
st.paused = false;
st.pausedPosSec = 0;
st.startMs = QDateTime::currentMSecsSinceEpoch();
st.durationSec = dur;
VoicePlayer::playOpusFile(filePath);
s_voiceTimer->start();
model->setData(index, 1, MsgVoicePlayStateRole);
return true;
}
@@ -578,13 +610,14 @@ void MessageDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio
}
bool isPlaying = st.playing;
bool isPaused = st.paused;
QRectF playR = L.voicePlayBtnRect;
/* Play/Pause button */
painter->setPen(Qt::NoPen);
painter->setBrush(QColor(0x33, 0x90, 0xEC));
if (isPlaying) {
if (isPlaying || isPaused) {
/* Pause icon (two vertical bars) */
qreal bw = playR.width() / 5.0;
qreal gap = playR.width() / 8.0;
@@ -617,10 +650,15 @@ void MessageDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio
int pbTop = L.voicePlayBtnRect.bottom() + 6;
int pbHeight = 3;
if (isPlaying && st.durationSec > 0) {
qint64 now = QDateTime::currentMSecsSinceEpoch();
float elapsed = (now - st.startMs) / 1000.0f;
if (elapsed > st.durationSec) elapsed = st.durationSec;
if ((isPlaying || isPaused) && st.durationSec > 0) {
float elapsed;
if (isPaused) {
elapsed = st.pausedPosSec;
} else {
qint64 now = QDateTime::currentMSecsSinceEpoch();
elapsed = (now - st.startMs) / 1000.0f;
if (elapsed > st.durationSec) elapsed = st.durationSec;
}
float frac = elapsed / st.durationSec;
painter->setPen(Qt::NoPen);