Keep PM composer work bound to its history generation
This commit is contained in:
1 parent
df80c43a57
commit
e10354a0ac
2 files changed
+42
-4
No files matched your search
@@ -308,7 +308,7 @@ void InputBar::installFileDropTarget(QWidget* target) {
|
||||
}
|
||||
|
||||
bool InputBar::canAttachFile() const {
|
||||
return !m_channelIdForRecord.isEmpty() && m_attachBtn->isEnabled() &&
|
||||
return isEnabled() && !m_channelIdForRecord.isEmpty() && m_attachBtn->isEnabled() &&
|
||||
!m_pttActive && (!m_recorder || !m_recorder->isRecording());
|
||||
}
|
||||
|
||||
@@ -403,6 +403,7 @@ void InputBar::adjustInputHeight() {
|
||||
}
|
||||
|
||||
void InputBar::onSendClicked() {
|
||||
if (!isEnabled()) { GUI_WARN("send: composer unavailable target=%s", qPrintable(m_channelIdForRecord)); return; }
|
||||
if (replySending()) {
|
||||
GUI_WARN("reply: submission still pending ch=%s", qPrintable(m_channelIdForRecord)); return;
|
||||
}
|
||||
@@ -450,6 +451,7 @@ void InputBar::onSendClicked() {
|
||||
u_free(request); submissionResult(requestId, false); return;
|
||||
}
|
||||
request->info.kind = ATTACHMENT_VIDEO; request->transcode = 1;
|
||||
request->dm_generation = m_dmGeneration;
|
||||
if (reply.size() == 32) memcpy(request->reply_to, reply.constData(), 32);
|
||||
request->request_id = requestId;
|
||||
snprintf(request->source, sizeof(request->source), "%s", source.constData());
|
||||
@@ -470,8 +472,10 @@ void InputBar::onSendClicked() {
|
||||
}
|
||||
}
|
||||
|
||||
void InputBar::setRecordingContext(const QString& mediaDirBase, const QString& channelId) {
|
||||
if (m_channelIdForRecord != channelId || m_mediaDirBase != mediaDirBase) {
|
||||
void InputBar::setRecordingContext(const QString& mediaDirBase, const QString& channelId, quint64 dmGeneration) {
|
||||
if (m_channelIdForRecord == channelId && m_dmGeneration && m_dmGeneration != dmGeneration)
|
||||
forgetDmHistory(channelId, m_dmGeneration);
|
||||
if (m_channelIdForRecord != channelId || m_mediaDirBase != mediaDirBase || m_dmGeneration != dmGeneration) {
|
||||
clearReply();
|
||||
++m_attachmentContext;
|
||||
clearPendingAttachment();
|
||||
@@ -479,6 +483,24 @@ void InputBar::setRecordingContext(const QString& mediaDirBase, const QString& c
|
||||
}
|
||||
m_mediaDirBase = mediaDirBase;
|
||||
m_channelIdForRecord = channelId;
|
||||
m_dmGeneration = dmGeneration;
|
||||
showPreparation();
|
||||
}
|
||||
|
||||
/* Старое завершение worker не должно вернуть ошибку/индикатор в повторно открытый PM. */
|
||||
void InputBar::forgetDmHistory(const QString& target, quint64 generation) {
|
||||
m_discardedPreparations.unite(m_preparations.take(target));
|
||||
m_preparationErrors.remove(target);
|
||||
if (m_recordTarget == target && m_recordDmGeneration == generation) {
|
||||
m_pttActive = false;
|
||||
if (m_recorder && m_recorder->isRecording()) m_recorder->stopRecording();
|
||||
m_recordTarget.clear(); m_recordReply.clear(); m_recordDmGeneration = 0;
|
||||
}
|
||||
if (m_channelIdForRecord == target && m_dmGeneration == generation) {
|
||||
++m_attachmentContext; clearPendingAttachment(); clearReply(); m_input->clear();
|
||||
if (m_dropHint) m_dropHint->hide();
|
||||
}
|
||||
GUI_INFO("PM composer cleared: target=%s generation=%llu", qPrintable(target), (unsigned long long)generation);
|
||||
showPreparation();
|
||||
}
|
||||
|
||||
@@ -498,12 +520,14 @@ void InputBar::setMediaEnabled(bool enabled) {
|
||||
}
|
||||
|
||||
void InputBar::onPttPressed() {
|
||||
if (!isEnabled() || m_channelIdForRecord.isEmpty()) { GUI_WARN("voice: composer unavailable"); return; }
|
||||
if (replySending()) { GUI_WARN("reply: recording blocked while submission pending"); return; }
|
||||
if (!m_recorder || !m_recorder->isInitialized()) return;
|
||||
m_recorder->startRecording();
|
||||
m_pttActive = m_recorder->isRecording();
|
||||
if (!m_pttActive) { DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "voice recording did not start; composer remains idle"); return; }
|
||||
m_recordTarget = m_channelIdForRecord;
|
||||
m_recordDmGeneration = m_dmGeneration;
|
||||
m_recordReply = m_replyTo; m_recordReplyGeneration = m_replyGeneration; m_replyFailed = false;
|
||||
m_pttBtn->setStyleSheet(m_pttBtn->styleSheet() +
|
||||
"QPushButton { background: #e74c3c; border-radius: 4px; }");
|
||||
@@ -517,6 +541,10 @@ void InputBar::onPttReleased() {
|
||||
"QPushButton { border: none; border-radius: 4px; background: transparent; }"
|
||||
"QPushButton:hover { background: palette(light); }");
|
||||
|
||||
if (!isEnabled()) {
|
||||
GUI_INFO("voice: discarded recording while composer unavailable target=%s", qPrintable(m_recordTarget)); return;
|
||||
}
|
||||
|
||||
int durationMs = m_recorder->durationMs();
|
||||
if (durationMs < 500) {
|
||||
GUI_INFO("InputBar: voice message too short (%dms), discarded", durationMs);
|
||||
@@ -526,6 +554,7 @@ void InputBar::onPttReleased() {
|
||||
auto* request = (struct attachment_send_req*)u_calloc(1, sizeof(struct attachment_send_req));
|
||||
if (!request) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "InputBar: voice request allocation failed"); return; }
|
||||
request->info.kind = ATTACHMENT_VOICE; request->preset = VoiceEncoder::preset();
|
||||
request->dm_generation = m_recordDmGeneration;
|
||||
if (!m_recorder->takeRecording(request)) { u_free(request); return; }
|
||||
if (m_recordReply.size() == 32) memcpy(request->reply_to, m_recordReply.constData(), 32);
|
||||
request->request_id = beginReplySend(m_recordReply, m_recordReplyGeneration, m_recordTarget);
|
||||
@@ -627,6 +656,11 @@ void InputBar::clearPendingAttachment() {
|
||||
}
|
||||
|
||||
void InputBar::updatePreparation(const QString& target, const QByteArray& job, int state) {
|
||||
if (m_discardedPreparations.contains(job)) {
|
||||
if (state) m_discardedPreparations.remove(job);
|
||||
GUI_DEBUG("PM preparation discarded after deletion: target=%s job=%s state=%d", qPrintable(target), job.toHex().constData(), state);
|
||||
return;
|
||||
}
|
||||
if (state == 0) { m_preparations[target].insert(job); m_preparationErrors.remove(target); }
|
||||
else {
|
||||
m_preparations[target].remove(job);
|
||||
|
||||
@@ -25,7 +25,9 @@ public:
|
||||
QWidget *parent = nullptr);
|
||||
~InputBar() override;
|
||||
|
||||
void setRecordingContext(const QString& mediaDirBase, const QString& channelId);
|
||||
void setRecordingContext(const QString& mediaDirBase, const QString& channelId, quint64 dmGeneration = 0);
|
||||
/* Очистить черновик/запись и задачи удалённого поколения PM; новый выбранный адресат не затрагивается. */
|
||||
void forgetDmHistory(const QString& target, quint64 generation);
|
||||
/* Один обработчик URL-drop для composer и viewport истории; отправка остаётся по кнопке/Enter. */
|
||||
void installFileDropTarget(QWidget* target);
|
||||
|
||||
@@ -96,6 +98,7 @@ private:
|
||||
QPushButton *m_attachClearBtn = nullptr;
|
||||
bool m_pttActive = false;
|
||||
bool m_dmMode = false;
|
||||
quint64 m_dmGeneration = 0, m_recordDmGeneration = 0; /* Поколения текущего composer и начатой записи PM. */
|
||||
QString m_mediaDirBase;
|
||||
QString m_channelIdForRecord;
|
||||
QString m_recordTarget;
|
||||
@@ -108,6 +111,7 @@ private:
|
||||
QLabel* m_preparationLabel = nullptr;
|
||||
QHash<QString, QSet<QByteArray>> m_preparations;
|
||||
QSet<QString> m_preparationErrors;
|
||||
QSet<QByteArray> m_discardedPreparations; /* Завершения задач удалённой истории, ещё ожидаемые из ядра. */
|
||||
void showPreparation();
|
||||
bool canAttachFile() const;
|
||||
bool prepareAttachment(const QString& source, quint64 context);
|
||||
|
||||
Reference in new issue
Block a user