Complete MainWindow and MessageList contracts for commands and snapshots

This commit is contained in:
evgeny committed 2026-10-28 00:59:00 +01:00
1 parent 7556695cc5
commit 17772163cd
2 files changed
+68

No files matched your search

+39
View File
@@ -41,14 +41,17 @@ struct AutoPlayItem {
class MainWindow : public QMainWindow {
Q_OBJECT
public:
// db заимствован до деструктора; nullptr создаёт UI без UtunNode. cfgPath — профиль, dbPath — override каталога.
explicit MainWindow(QWidget *parent, DbManager* db, const QString& cfgPath,
const QString& dbPath = QString(),
const QString& debugFile = QString(),
const QString& debugLevel = QString(),
const QString& debugCategories = QString());
// Снять callbacks, остановить media, stop/join node и очистить анимации.
~MainWindow() override;
protected:
// Сохранить геометрию и скрыть в tray; для выхода служит requestShutdown.
void closeEvent(QCloseEvent *event) override;
private slots:
@@ -61,56 +64,92 @@ private slots:
void openVideo(const QString& filePath);
void openImage(const QString& filePath);
void showChannelSettings(const QString& channelId);
// Дождаться конца/подготовки player, разрешить путь головы и запустить один voice.
void autoPlayTimerTick();
public:
// ch_id задан с длиной; initialSync обновляет историю без уведомления, звука и auto-play.
void onMessageReceived(const char* ch_id, int ch_id_len, uint64_t author, bool initialSync);
// Передать бинарный CHAT_MEMBER_DISPLAY снимок списку участников и кэшу аватаров.
void onMemberList(const QString& chId, int count, const uint8_t* data, int dataLen);
// Обновить участника по codec chat_member.h; байты заимствованы до возврата.
void onMemberUpdated(const QString& chId, const uint8_t* data);
// Удалить nodeId из модели/кэша выбранного chId.
void onMemberRemoved(const QString& chId, uint64_t nodeId);
// Обновить статус поиска соседей канала.
void onAutoConnectStatus(uint8_t status, uint16_t total, uint16_t totalNodes, uint16_t connected);
// Обновить online-счётчик ch_id указанной длины.
void onChannelPeersOnline(const char* ch_id, int ch_id_len, uint16_t online);
// Перечитать список, сбросить исчезнувший target и применить отложенный выбор.
void reloadChannels();
// Завершение (channel,rowid): разбудить очередь, проверить готовый encrypted voice.
void onAttachmentDownloadedForAutoPlay(const QString& chId, int64_t msgId);
// Сохранить geometry/read/scroll и поставить stop после этих команд; OOM допускает прямой stop с логом.
void requestShutdown();
// Заимствованный QObject-владелец ядра либо nullptr; управление — в GUI.
UtunNode* utunNode() const { return m_node; }
/* звонки */
// Создать исходящее окно после принятия START мостом; chId может быть dm:<conv_id>.
void onCallRequested(const QString& chId, quint64 nodeId, const QString& name);
// Показать входящий callId с именем caller из DbManager; повтор ID не создаёт окно.
void onCallIncoming(const QString& chId, quint64 caller, quint64 callId);
// Обновить состояние существующего исходящего окна и тон.
void onCallRinging(quint64 callId);
// Активировать callId/audio; при отказе capture послать hangup.
void onCallAccepted(quint64 callId);
// Завершить audio/окно, при PHONE_BUSY показать причину.
void onCallEnded(quint64 callId, uint8_t reason);
// Залогировать протокольную ошибку и закрыть окно callId.
void onCallError(quint64 callId, uint8_t err);
// Обновить диагностический BGP-путь существующего окна.
void onCallPath(quint64 callId, const QString& path);
// Снять callId из map до deleteLater; повтор безопасен.
void closeCallWindow(quint64 callId);
// Передать START для CHAT-канала и peer с новым ненулевым ID.
void onRadioCallRequested(const QString& channel, quint64 peer);
// Применить 27-байтный radio_call event, управлять диалогом/рингтоном и READY/ACCEPT.
void onRadioCallEvent(const uint8_t* data, int len);
/* DM (p2p чат) */
// Скопировать общую группу/peer/имя в команду; PM выбирается после DM_CONV_UPDATED.
void onPmRequested(const QString& chId, quint64 nodeId, const QString& name);
// Открыть отправку свежего invite фиксированному peer; source может быть пустым из PM.
void onInviteToPmRequested(const QString& source, quint64 peer, const QString& name);
// Разобрать utun/utun-msg ссылку и перейти к доступной группе/оригиналу.
void onMessageLinkActivated(const QString& link);
// Выбрать только видимое совпавшее поколение истории PM.
void onDmConvUpdated(const QString& convId, quint64 generation);
// Обновить PM/уведомление; выбранной беседе запросить снимок.
void onDmMsgReceived(const QString& convId, quint64 author);
// Подтвердить удаление конкретного generation и заблокировать его composer.
void onDmDeleteRequested(const QString& convId, quint64 generation, const QString& name);
// Применить только зарегистрированный request/conv/generation без очистки новой истории.
void onDmDeleteResult(quint64 request, const QString& convId, quint64 generation, bool success);
private:
void setupUi();
// Поставить owned geometry/maximized/splitter в ui_state.
void saveWindowGeometry();
// Восстановить размеры в пределах доступных экранов.
void restoreWindowGeometry();
void setupTray();
void showIncomingMessageNotification(const QString& target, quint64 author);
// Запустить UtunNode; stopping отсоединяет SQLite до native teardown.
void setupNode();
void setupMessaging();
void setupSoundFromConfig();
// Один MainWindow получает bridge events в GUI; деструктор снимает callbacks.
void setupBridgeCallbacks();
// Связать списки/composer/окна с командами и локальными действиями.
void setupConnects();
void onShutdownCheck();
// Проверить последнюю запись или msgId>0; повторный/свой voice не добавлять.
void autoPlayCheckNewMessage(const QString& channelId, qint64 msgId = 0);
QString autoPlayMediaDir() const;
// Путь обычного voice/проверенного plaintext VOICE; неизвестный encrypted MIME даёт пусто.
QString autoPlayFilePath(const QString& channelId, const MessageRow& message) const;
// Открыть CHAT browser с owner/общим списком; DM не поддерживается.
void showMemberFiles(const QString& channel, quint64 owner = 0);
void showStreamPublisher(quint64 group, StreamGridWindow* returnTo = nullptr); // Управление; закрытие возвращает фокус сетке.
+29
View File
@@ -29,33 +29,54 @@ struct MessageRow;
class MessageList : public QWidget {
Q_OBJECT
public:
// db/recorder заимствованы; Qt parent владеет виджетом. nullptr db допустим для пустого UI.
explicit MessageList(DbManager* db = nullptr, AudioRecorder* recorder = nullptr,
QWidget *parent = nullptr);
// Сохранить канал, сменить target; для dm:<id> зафиксировать generation и запросить снимок.
void loadChannel(const QString& channelId);
// Добавить отсутствующие сообщения (до 200); не вытеснять историческое окно цитаты.
void refresh();
// Перечитать имена, обновить авторов и превью цитат.
void reloadLocalNicks();
// Поставить read/верхнюю позицию в ui_state; окно старой цитаты сохраняет свежий watermark.
void saveChannelState();
// После остановки AnimTimer удалить общие LottieIcon; не вызывать при их отрисовке.
static void cleanupAnimations();
// Обновить только (chId,msgId) текущей модели без сетевого запроса.
void updateMessageProgress(const QString& chId, int64_t msgId, int blocksDone, int numBlocks);
// Перечитать путь/роли; отложенный пользовательский play требует прежний target.
void onAttachmentDownloaded(const QString& chId, int64_t msgId);
// [conv_len,conv,generation,JSON]: чужое/старое поколение не применяется.
void onDmMessages(const uint8_t* data, int len);
/* Блокировать отправки ожидающего удаления; forget очищает UI только для удалённого поколения и возвращает true. */
void setDmDeleting(const QString& convId, quint64 generation, bool deleting);
bool forgetDmHistory(const QString& convId, quint64 generation);
// Запросить адресата/общую группу; отказ очищает доступность кнопки.
void refreshDmCallRoute();
// [conv_len,conv,peer,group] только для выбранного PM; group=0 отключает звонок.
void onDmCallRoute(const uint8_t* data, int len);
// Сбросить peer/group и показать offline.
void clearDmCallRoute();
// Проверить codec и передать target/job/state composer.
void onAttachmentPreparation(const uint8_t* data, int len);
// Запросить свежие реакции/опрос для изменённого сообщения текущего канала.
void onFeedbackChanged(const uint8_t* data, int len);
// Проверить результат/JSON-снимок; чужой канал не меняет модель.
void onFeedbackResult(const uint8_t* data, int len);
// 9 байт (request_id LE,success) подтверждают/отклоняют зафиксированный черновик.
void onMessageSubmitted(const uint8_t* data, int len);
// Применить новую версию подписанного item с сохранением scroll и превью ответов.
void onMessageUpdated(const uint8_t* data, int len);
// Обновить encrypted-вложение и диалог выдачи ключей текущего канала.
void onAttachmentKeysChanged(const uint8_t* data, int len);
void onRadioTalk(quint64 groupId, quint64 srcNodeId, bool on); /* индикация говорящего */
bool enableRadio(); /* идемпотентное включение рации выбранного канала, false при ошибке аудио */
// Применить проверенный полный каталог выбранной CHAT-группы.
void onStreamSources(const uint8_t* data, int len);
// Очистить каталог/кнопку remote streams.
void clearStreams();
// Наблюдать CHAT-группу; пустой target/PM передаёт 0 и снимает наблюдение.
void watchStreams();
/* Показывает кнопку своей публикации во всех каналах; group=0 скрывает после завершения. GUI-поток. */
void setStreamPublisherGroup(quint64 group);
@@ -121,11 +142,14 @@ private:
QByteArray m_historyAnchor;
void updateReply(QStandardItem* item, const QByteArray& original);
void refreshReplies();
// Разрешить подписанный ID в выбранном канале, загрузить окно и подсветить оригинал.
void jumpToMessage(const QString& messageId);
bool sendFeedback(QJsonObject command, bool userAction = true); // true — запрос принят; ch фиксируется до модального UI.
void setupFeedback(QStandardItem* item, const MessageRow& message, const QString& channel);
// Проверить UTF-8 лимиты и передать опрос в исходный канал диалога.
void createPoll();
// Показать один диалог опроса или запросить недостающий снимок.
void showPoll(const QString& messageId);
void applyFeedback(const QJsonObject& state);
void requestReaction(const QModelIndex& index, int emoji);
@@ -133,10 +157,15 @@ private:
QString authorName(quint64 nodeId) const;
void restoreScrollPosition(const QString& channelId);
// Максимальный rowid полностью видимых строк; watermark меняется после принятия записи.
void updateReadPosition();
// Persistent index/QPointer защищают menu от замены модели/уничтожения UI.
void onMessageContextMenu(const QPoint& pos);
// Запросить выбранное поколение PM; ожидающее удаление блокирует запрос.
void requestDmMessages(const QString& channelId);
// Не более двух FFmpeg jobs; GUI callback защищён QPointer.
void prepareVideoThumbnail(const QString& path);
// Owned-подписка в uasync и local audio; ошибка восстанавливает кнопку.
void onRadioToggled(bool on);
void updateRadioUi();
static bool isDmChannel(const QString& channelId);