diff --git a/tools/chatgui/src/messagelist.cpp b/tools/chatgui/src/messagelist.cpp index 6f57d993..65fa92b9 100644 --- a/tools/chatgui/src/messagelist.cpp +++ b/tools/chatgui/src/messagelist.cpp @@ -49,6 +49,7 @@ void chat_core_save_ui_state_trampoline(void* arg); } #include "radio_audio_engine.h" +#include "radiopanel.h" #include #include #include @@ -393,6 +394,10 @@ MessageList::MessageList(DbManager* db, AudioRecorder* recorder, QWidget *parent layout->addWidget(header); } + m_radioPanel = new RadioPanel(this); + m_radioPanel->hide(); + layout->addWidget(m_radioPanel); + m_view->setModel(m_model); auto* msgDelegate = new MessageDelegate(this); msgDelegate->setVideoOpenCallback([this](const QString& path) { @@ -424,24 +429,6 @@ MessageList::MessageList(DbManager* db, AudioRecorder* recorder, QWidget *parent m_view->setBackgroundImage("../resources/bg.png"); layout->addWidget(m_view, 1); - /* ── плавающая PTT-кнопка поверх чата (видна при включённой рации) ── */ - m_pttBtn = new QPushButton(QString::fromUtf8("\xF0\x9F\x8E\xA4"), this); - m_pttBtn->setFixedSize(96, 96); - m_pttBtn->setCursor(Qt::PointingHandCursor); - m_pttBtn->setToolTip(QStringLiteral("Держите и говорите")); - m_pttBtn->setStyleSheet( - "QPushButton { border: 3px solid white; border-radius: 48px; background: #e74c3c; color: white; font-size: 36px; }" - "QPushButton[transmitting=\"true\"] { background: #27ae60; }"); - m_pttBtn->setProperty("transmitting", false); - m_pttBtn->hide(); - connect(RadioAudioEngine::instance(), &RadioAudioEngine::talkingChanged, this, [this](bool) { updateRadioUi(); }); - connect(m_pttBtn, &QPushButton::pressed, this, []() { - RadioAudioEngine::instance()->talkBegin(); - }); - connect(m_pttBtn, &QPushButton::released, this, []() { - RadioAudioEngine::instance()->talkEnd(); - }); - if (s_icons.empty()) { for (const auto &cat : builtinEmojiSet()) { for (const auto &e : cat.items) { @@ -1226,49 +1213,38 @@ void MessageList::onRadioToggled(bool on) { if (groupId == 0) return; struct radio_set_active_arg* a = (struct radio_set_active_arg*)u_malloc(sizeof(*a)); - if (!a) return; + if (!a) { + DEBUG_ERROR(DEBUG_CATEGORY_RADIO, "RadioPanel: active request allocation failed group=%016llx", (unsigned long long)groupId); + QSignalBlocker blocker(m_radioBtn); + m_radioBtn->setChecked(m_radioOn); + return; + } a->inst = gui_bridge_get_inst(); a->group_id = groupId; a->on = on ? 1 : 0; gui_bridge_post_uasync_fn(radio_set_active_trampoline, a); - m_radioOn = on; if (on) { - RadioAudioEngine::instance()->start(groupId); + if (RadioAudioEngine::instance()->start(groupId) != 0) { + DEBUG_ERROR(DEBUG_CATEGORY_RADIO, "RadioPanel: radio start failed group=%016llx", (unsigned long long)groupId); + auto* undo = static_cast(u_calloc(1, sizeof(radio_set_active_arg))); + if (undo) { + undo->inst = gui_bridge_get_inst(); undo->group_id = groupId; + gui_bridge_post_uasync_fn(radio_set_active_trampoline, undo); + } else DEBUG_ERROR(DEBUG_CATEGORY_RADIO, "RadioPanel: cannot cancel failed radio subscription"); + QSignalBlocker blocker(m_radioBtn); + m_radioBtn->setChecked(false); + return; + } } else { RadioAudioEngine::instance()->stop(); m_talkingLabel->hide(); } + m_radioOn = on; updateRadioUi(); } void MessageList::updateRadioUi() { - if (!m_pttBtn) return; - auto* audio = RadioAudioEngine::instance(); - bool transmitting = audio->isTalking() && audio->groupId() == m_currentChannelId.toULongLong(); - if (m_pttBtn->property("transmitting").toBool() != transmitting) { - m_pttBtn->setProperty("transmitting", transmitting); - m_pttBtn->style()->unpolish(m_pttBtn); - m_pttBtn->style()->polish(m_pttBtn); - m_pttBtn->update(); - } bool show = m_radioOn && !isDmChannel(m_currentChannelId); - m_pttBtn->setVisible(show); - if (show) { - m_pttBtn->raise(); - layoutPttButton(); - } -} - -void MessageList::layoutPttButton() { - if (!m_pttBtn || !m_pttBtn->isVisible()) return; - int w = width(); - int x = (w - m_pttBtn->width()) / 2; - int y = 48; /* под шапкой, поверх списка сообщений */ - m_pttBtn->move(x, y); -} - -void MessageList::resizeEvent(QResizeEvent* event) { - QWidget::resizeEvent(event); - layoutPttButton(); + m_radioPanel->setVisible(show); } diff --git a/tools/chatgui/src/messagelist.h b/tools/chatgui/src/messagelist.h index 500d40a2..78b74661 100644 --- a/tools/chatgui/src/messagelist.h +++ b/tools/chatgui/src/messagelist.h @@ -15,6 +15,7 @@ class ChannelList; class AudioRecorder; class QLabel; class QPushButton; +class RadioPanel; class MessageList : public QWidget { Q_OBJECT @@ -42,9 +43,6 @@ signals: void openVideoRequested(const QString& filePath); void openImageRequested(const QString& filePath); -protected: - void resizeEvent(QResizeEvent* event) override; - private: ChatView *m_view; QStandardItemModel *m_model; @@ -66,7 +64,7 @@ private: quint64 m_callPeer = 0; quint64 m_callGroup = 0; QPushButton* m_radioBtn = nullptr; /* шапка: переключатель рации */ - QPushButton* m_pttBtn = nullptr; /* плавающая кнопка PTT поверх чата */ + RadioPanel* m_radioPanel = nullptr; /* верхняя панель устройств, VAD и PTT */ bool m_radioOn = false; QThreadPool m_thumbnailPool; QSet m_thumbnailJobs; @@ -79,7 +77,6 @@ private: void prepareVideoThumbnail(const QString& path); void onRadioToggled(bool on); void updateRadioUi(); - void layoutPttButton(); static bool isDmChannel(const QString& channelId); static QString dmConvId(const QString& channelId); };