Browse Source

Notify about live incoming channel and direct messages

master
evgeny 5 days ago
parent
commit
33c98a014f
  1. 47
      tools/chatgui/src/mainwindow.cpp
  2. 5
      tools/chatgui/src/mainwindow.h
  3. 9
      tools/chatgui/transport/gui_bridge_impl.cpp

47
tools/chatgui/src/mainwindow.cpp

@ -30,6 +30,7 @@ extern "C" {
#include "call_audio_engine.h"
#include "radio_audio_engine.h"
#include "ptt_hotkey_manager.h"
#include "message_notification.h"
extern "C" {
#include "../../lib/audio_compressor.h"
@ -92,9 +93,9 @@ static void saveLastChannelId(const QString& channelId) {
postUiStateKv("last_channel_id", channelId);
}
static void onMsgReceivedCallback(const char* ch_id, int ch_id_len, uint64_t author) {
static void onMsgReceivedCallback(const char* ch_id, int ch_id_len, uint64_t author, int initial_sync) {
if (s_mainWindow)
s_mainWindow->onMessageReceived(ch_id, ch_id_len, author);
s_mainWindow->onMessageReceived(ch_id, ch_id_len, author, initial_sync != 0);
}
static void onChannelUpdatedCallback(const char* ch_id, int ch_id_len) {
@ -181,6 +182,7 @@ MainWindow::MainWindow(QWidget *parent, DbManager* db, const QString& cfgPath,
MainWindow::~MainWindow() {
s_mainWindow = nullptr;
if (m_messageNotification) m_messageNotification->dismiss("shutdown");
delete AvatarManager::instance();
delete GroupAvatarManager::instance();
gui_bridge_set_group_avatar_result_cb(nullptr);
@ -799,6 +801,7 @@ void MainWindow::onMessageLinkActivated(const QString& link) {
void MainWindow::onDmMsgReceived(const QString& convId, quint64 author) {
QString key = QStringLiteral("dm:") + convId;
showIncomingMessageNotification(key, author);
if (m_currentChannelId == key) {
m_messageList->refresh();
return;
@ -813,6 +816,18 @@ void MainWindow::setupTray() {
m_trayIcon->setIcon(QIcon(":/icons/app_icon.png"));
m_trayIcon->setToolTip("vibechat");
m_messageNotification = new MessageNotification(this);
connect(m_messageNotification, &MessageNotification::activated, this, [this](const QString& target) {
if (isMinimized()) setWindowState(windowState() & ~Qt::WindowMinimized);
show();
raise();
activateWindow();
reloadChannels();
m_channelList->selectChannel(target);
if (m_currentChannelId != target) GUI_WARN("notification: target no longer available target=%s", qPrintable(target));
else GUI_INFO("notification: opened chat target=%s", qPrintable(target));
});
m_trayMenu = new QMenu(this);
QAction *settingsAction = m_trayMenu->addAction(QCoreApplication::translate("ChatGui", "Settings"));
connect(settingsAction, &QAction::triggered, this, &MainWindow::showSettings);
@ -837,6 +852,30 @@ void MainWindow::setupTray() {
m_trayIcon->show();
}
void MainWindow::showIncomingMessageNotification(const QString& target, quint64 author) {
if (!m_db || !m_db->isOpen() || !m_messageNotification) {
GUI_WARN("notification: GUI not ready target=%s author=%llu", qPrintable(target), (unsigned long long)author);
return;
}
if (author == m_db->myNodeId() || isActiveWindow()) {
GUI_DEBUG("notification: skipped target=%s own=%d window_active=%d",
qPrintable(target), int(author == m_db->myNodeId()), int(isActiveWindow()));
return;
}
QString channel;
if (target.startsWith(QStringLiteral("dm:"))) channel = QCoreApplication::translate("ChatGui", "Direct messages");
else {
for (const auto& row : m_db->getChannels()) {
if (row.channelId == target) { channel = row.name.isEmpty() ? target : row.name; break; }
}
if (channel.isEmpty()) {
GUI_WARN("notification: channel no longer available target=%s", qPrintable(target));
return;
}
}
m_messageNotification->showMessage(target, m_db->getDisplayName(author), channel, m_trayIcon->geometry());
}
void MainWindow::closeEvent(QCloseEvent *event) {
DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "MainWindow: closeEvent — hiding to tray");
saveWindowGeometry();
@ -848,6 +887,7 @@ void MainWindow::closeEvent(QCloseEvent *event) {
void MainWindow::requestShutdown() {
DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "MainWindow: requestShutdown — saving geometry and stopping node");
if (m_messageNotification) m_messageNotification->dismiss("shutdown");
saveWindowGeometry();
if (m_node) m_node->requestStop();
}
@ -951,8 +991,9 @@ void MainWindow::openImage(const QString& filePath) {
m_imageViewer->showFullScreen();
}
void MainWindow::onMessageReceived(const char* ch_id, int ch_id_len, uint64_t author) {
void MainWindow::onMessageReceived(const char* ch_id, int ch_id_len, uint64_t author, bool initialSync) {
QString cid = QString::fromUtf8(ch_id, ch_id_len);
if (!initialSync) showIncomingMessageNotification(cid, author);
if (m_db && author != m_db->myNodeId()
&& m_db->getUiStateInt(QStringLiteral("ch_%1_sound_on_message").arg(cid), 1))
SoundManager::instance()->play("msg_incoming");

5
tools/chatgui/src/mainwindow.h

@ -24,6 +24,7 @@ class ImageViewerWindow;
class CallWindow;
class CallAudioEngine;
class MemberFileBrowser;
class MessageNotification;
struct AutoPlayItem {
QString channelId;
@ -59,7 +60,7 @@ private slots:
void autoPlayTimerTick();
public:
void onMessageReceived(const char* ch_id, int ch_id_len, uint64_t author);
void onMessageReceived(const char* ch_id, int ch_id_len, uint64_t author, bool initialSync);
void onMemberList(const QString& chId, int count, const uint8_t* data, int dataLen);
void onMemberUpdated(const QString& chId, const uint8_t* data);
void onMemberRemoved(const QString& chId, uint64_t nodeId);
@ -92,6 +93,7 @@ private:
void saveWindowGeometry();
void restoreWindowGeometry();
void setupTray();
void showIncomingMessageNotification(const QString& target, quint64 author);
void setupNode();
void setupMessaging();
void setupSoundFromConfig();
@ -108,6 +110,7 @@ private:
QSplitter *m_splitter = nullptr;
QSystemTrayIcon *m_trayIcon;
QMenu *m_trayMenu;
MessageNotification* m_messageNotification = nullptr;
DbManager *m_db;
UtunNode *m_node = nullptr;
QString m_cfgPath;

9
tools/chatgui/transport/gui_bridge_impl.cpp

@ -123,13 +123,14 @@ void GuiBridgeReceiver::processPost(int eventType, QByteArray data) {
case GUI_EVT_MSG_RECEIVED:
if (dlen >= 2) {
uint8_t chLen = d[0];
if (dlen >= 1 + chLen + 8) {
if (chLen && dlen == 1 + chLen + 9 && d[1 + chLen + 8] <= 1) {
uint64_t author = 0;
memcpy(&author, d + 1 + chLen, 8);
const int initialSync = d[1 + chLen + 8];
QString chId = QString::fromUtf8((const char*)d + 1, chLen);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "gui_bridge: MSG_RECEIVED ch=%s author=%llu",
qPrintable(chId), (unsigned long long)author);
if (g_msg_received_cb) g_msg_received_cb((const char*)d + 1, chLen, author);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "gui_bridge: MSG_RECEIVED ch=%s author=%llu initial_sync=%d",
qPrintable(chId), (unsigned long long)author, initialSync);
if (g_msg_received_cb) g_msg_received_cb((const char*)d + 1, chLen, author, initialSync);
} else {
DEBUG_WARN(DEBUG_CATEGORY_CHAT, "gui_bridge: MSG_RECEIVED invalid data length %d", dlen);
}

Loading…
Cancel
Save