Add Android boot startup, lazy settings, emoji and DM calls

Add battery optimization controls and configurable boot startup. Keep message sounds in the application and render general settings lazily to avoid ANRs. Add animated emoji controls and live BGP availability for direct-message calls on Android and desktop.
This commit is contained in:
evgeny committed 2026-10-02 17:18:24 +03:00
1 parent 66afcc8625
commit 23368a5bbe
40 files changed
+1165 -180

No files matched your search

+70
View File
@@ -349,6 +349,10 @@ MessageList::MessageList(DbManager* db, AudioRecorder* recorder, QWidget *parent
hl->setContentsMargins(10, 6, 10, 6);
hl->setSpacing(8);
m_peerStatus = new QLabel(header);
m_peerStatus->setFixedSize(12, 12);
m_peerStatus->hide();
hl->addWidget(m_peerStatus);
m_channelTitle = new QLabel(header);
m_channelTitle->setStyleSheet("font-weight: bold; font-size: 14px;");
m_channelTitle->setText(QStringLiteral("Канал"));
@@ -359,6 +363,18 @@ MessageList::MessageList(DbManager* db, AudioRecorder* recorder, QWidget *parent
m_talkingLabel->hide();
hl->addWidget(m_talkingLabel);
m_callBtn = new QPushButton(QStringLiteral("☎"), header);
m_callBtn->setAccessibleName(QStringLiteral("Позвонить"));
m_callBtn->setFixedSize(34, 30);
m_callBtn->setCursor(Qt::PointingHandCursor);
m_callBtn->hide();
clearDmCallRoute();
hl->addWidget(m_callBtn);
connect(m_callBtn, &QPushButton::clicked, this, [this]() {
if (m_callBtn->isEnabled() && m_callPeer && isDmChannel(m_currentChannelId))
emit callRequested(m_currentChannelId, m_callPeer, m_channelTitle->text());
});
m_radioBtn = new QPushButton(header);
m_radioBtn->setIcon(makeRadioIcon(header->palette().color(QPalette::ButtonText)));
m_radioBtn->setIconSize(QSize(24, 24));
@@ -638,6 +654,10 @@ void MessageList::loadChannel(const QString& channelId) {
m_model->clear();
m_avatarCache.clear();
m_currentChannelId = channelId;
clearDmCallRoute();
m_callBtn->setVisible(isDmChannel(channelId));
m_peerStatus->setVisible(isDmChannel(channelId));
m_radioBtn->setVisible(!isDmChannel(channelId));
m_inputBar->setRecordingContext(m_db ? m_db->dbPath() + "/media" : QString(), channelId);
m_readDebounce->stop();
@@ -654,6 +674,17 @@ void MessageList::loadChannel(const QString& channelId) {
/* История и состояния PM поступают из ядра в одном снимке. */
if (isDmChannel(channelId)) {
m_radioBtn->setEnabled(false);
if (m_db) {
for (const auto& conv : m_db->getDmConversations()) {
if (conv.convId != dmConvId(channelId)) continue;
QString name = m_db->getDisplayName(conv.peerNodeId);
if (name.isEmpty()) name = conv.peerName;
if (name.isEmpty()) name = QStringLiteral("0x%1").arg(conv.peerNodeId, 16, 16, QChar('0'));
m_channelTitle->setText(name);
break;
}
}
refreshDmCallRoute();
requestDmMessages(channelId);
if (prevFocus)
prevFocus->setFocus();
@@ -1041,6 +1072,45 @@ void MessageList::onMessageContextMenu(const QPoint& pos) {
/* ── DM (p2p чат) ── */
void MessageList::clearDmCallRoute() {
m_callPeer = 0; m_callGroup = 0;
m_callBtn->setEnabled(false);
m_callBtn->setToolTip(QStringLiteral("Собеседник недоступен"));
m_peerStatus->setStyleSheet("background: #E53935; border-radius: 6px;");
m_peerStatus->setToolTip(QStringLiteral("Не в сети"));
}
void MessageList::refreshDmCallRoute() {
if (!isDmChannel(m_currentChannelId)) return;
auto* inst = gui_bridge_get_inst();
if (!inst) { clearDmCallRoute(); return; }
auto* req = (struct dm_messages_req*)u_calloc(1, sizeof(struct dm_messages_req));
if (!req) { DEBUG_ERROR(DEBUG_CATEGORY_CALL, "PM route request: allocation failed"); clearDmCallRoute(); return; }
req->inst = inst;
QByteArray conv = dmConvId(m_currentChannelId).toUtf8();
snprintf(req->conv_id, sizeof(req->conv_id), "%s", conv.constData());
gui_bridge_post_uasync_fn(dm_call_route_trampoline, req);
}
void MessageList::onDmCallRoute(const uint8_t* data, int len) {
if (!data || len < 17 || len != 17 + data[0]) {
DEBUG_WARN(DEBUG_CATEGORY_CALL, "PM route snapshot: invalid size=%d", len); return;
}
QString conv = QString::fromUtf8((const char*)data + 1, data[0]);
if (m_currentChannelId != QStringLiteral("dm:") + conv) return;
quint64 peer = 0, group = 0;
memcpy(&peer, data + 1 + data[0], 8);
memcpy(&group, data + 9 + data[0], 8);
if (m_callPeer != peer || m_callGroup != group)
DEBUG_INFO(DEBUG_CATEGORY_CALL, "PM button: conv=%s peer=%llu group=%llu enabled=%d",
conv.toUtf8().constData(), (unsigned long long)peer, (unsigned long long)group, peer && group);
m_callPeer = peer; m_callGroup = group;
m_callBtn->setEnabled(peer && group);
m_peerStatus->setStyleSheet(group ? "background: #4CAF50; border-radius: 6px;" : "background: #E53935; border-radius: 6px;");
m_peerStatus->setToolTip(group ? QStringLiteral("В сети") : QStringLiteral("Не в сети"));
m_callBtn->setToolTip(group ? QStringLiteral("Позвонить") : QStringLiteral("Собеседник недоступен"));
}
bool MessageList::isDmChannel(const QString& channelId) {
return channelId.startsWith(QStringLiteral("dm:"));
}