feature: media auto-download + manual download + UI download state indication (Android + desktop)
C-layer: - chat_event.h: CHAT_EVT_ATTACHMENT_DOWNLOADED (14) - chat_msg.c: fixed md_auto_download (non-NULL done_cb, correct media_base from db_path, use chat_setting for autoload checks) - chat_msg.c: added chat_core_attachment_download + trampoline for manual download - chat_core.h: exported attachment_dl_req + trampoline Android (Kotlin + JNI): - Message: downloadState field (parse from localAttrs) - ChatRepository: parse localAttrs for download state - NativeLib: attachmentDownload() JNI - MessageBubble: FileBubble with download status icon + tap-to-download - ChatViewModel: downloadAttachment() + CHAT_EVT_ATTACHMENT_DOWNLOADED handler - ChatScreen: wire onDownloadFile handler - android_jni_bridge: utun_bridge_attachment_download + JNI + localAttrs in JSON Desktop (Qt/C++): - messagedelegate.h: MsgFileDownloadStateRole, MsgChannelIdRole - messagelist.cpp: parse localAttrs for file download state - messagedelegate.cpp: FileBubble with download icon/text + click handler via chat_core_attachment_download_trampoline - gui_bridge.h: GUI_EVT_ATTACHMENT_DOWNLOADED (14) + callback typedef - gui_bridge_impl.cpp: event dispatch + setter - mainwindow.cpp: callback registration -> refresh message list
This commit is contained in:
1 parent
b8920cf483
commit
70797f921e
23 files changed
+558
-174
No files matched your search
@@ -20,6 +20,14 @@
|
||||
#include <QFile>
|
||||
#include <QDebug>
|
||||
|
||||
extern "C" {
|
||||
#include "../transport/gui_bridge.h"
|
||||
#include "chat/chat_core.h"
|
||||
#include "../../lib/u_async.h"
|
||||
#include "../../lib/mem.h"
|
||||
void chat_core_attachment_download_trampoline(void* arg);
|
||||
}
|
||||
|
||||
MessageDelegate::MessageDelegate(QObject *parent)
|
||||
: QStyledItemDelegate(parent) {}
|
||||
|
||||
@@ -67,6 +75,24 @@ bool MessageDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
|
||||
const QModelIndex &index) {
|
||||
if (event->type() != QEvent::MouseButtonRelease) return false;
|
||||
Layout L = calcLayout(option, index);
|
||||
|
||||
if (L.isFile) {
|
||||
int dlState = index.data(MsgFileDownloadStateRole).toInt();
|
||||
if (dlState != 0) return false; /* already downloaded or in progress */
|
||||
qint64 msgId = index.data(MsgIdRole).toLongLong();
|
||||
QString chId = index.data(MsgChannelIdRole).toString();
|
||||
if (chId.isEmpty() || msgId <= 0) return false;
|
||||
|
||||
struct attachment_dl_req* req = (struct attachment_dl_req*)
|
||||
u_malloc(sizeof(struct attachment_dl_req));
|
||||
if (!req) return false;
|
||||
memset(req, 0, sizeof(*req));
|
||||
strncpy(req->channel_id, chId.toUtf8().constData(), sizeof(req->channel_id) - 1);
|
||||
req->msg_id = msgId;
|
||||
gui_bridge_post_uasync_fn(chat_core_attachment_download_trampoline, req);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!L.isVoice) return false;
|
||||
|
||||
QMouseEvent* me = static_cast<QMouseEvent*>(event);
|
||||
@@ -797,17 +823,22 @@ void MessageDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio
|
||||
return;
|
||||
}
|
||||
|
||||
if (L.isFile) {
|
||||
if (L.isFile) {
|
||||
drawBubble(painter, L, option);
|
||||
if (!L.narrow) drawAvatar(painter, L, index);
|
||||
|
||||
/* File icon */
|
||||
int dlState = index.data(MsgFileDownloadStateRole).toInt();
|
||||
|
||||
/* File icon based on download state: 0=not_started, 1=downloading, 2=downloaded */
|
||||
QFont iconFont = option.font;
|
||||
iconFont.setPointSize(iconFont.pointSize() + 6);
|
||||
painter->setFont(iconFont);
|
||||
painter->setPen(option.palette.text().color());
|
||||
QRect iconRect(L.bubbleRect.left() + kPadH, kPadTop, 24, 24);
|
||||
painter->drawText(iconRect, Qt::AlignCenter, QString::fromUtf8("\xF0\x9F\x93\x84"));
|
||||
if (dlState == 2)
|
||||
painter->drawText(iconRect, Qt::AlignCenter, QString::fromUtf8("\xE2\x9C\x85"));
|
||||
else
|
||||
painter->drawText(iconRect, Qt::AlignCenter, QString::fromUtf8("\xE2\xAC\x87\xEF\xB8\x8F"));
|
||||
|
||||
QFont fileFont = option.font;
|
||||
fileFont.setBold(true);
|
||||
@@ -822,19 +853,16 @@ void MessageDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio
|
||||
painter->setPen(QColor(0x80, 0x80, 0x80));
|
||||
qint64 fsz = index.data(MsgFileSizeRole).toLongLong();
|
||||
QString sizeStr = formatFileSize(fsz);
|
||||
QString stateStr = (dlState == 2) ? "Downloaded" : "Tap to download";
|
||||
QString info = sizeStr + " \xC2\xB7 " + stateStr;
|
||||
int nameH = QFontMetrics(fileFont).height();
|
||||
QRect sizeRect(L.textRect.left(), L.textRect.top() + nameH, L.textRect.width(), QFontMetrics(sizeFont).height());
|
||||
painter->drawText(sizeRect, Qt::AlignLeft | Qt::AlignVCenter, sizeStr);
|
||||
|
||||
/* Timestamp */
|
||||
QFont tsFont = option.font;
|
||||
tsFont.setPointSize(tsFont.pointSize() - 1);
|
||||
painter->setFont(tsFont);
|
||||
painter->drawText(QRect(L.textRect.right() - 40, L.textRect.top() + nameH, 40, QFontMetrics(sizeFont).height()),
|
||||
Qt::AlignRight | Qt::AlignVCenter, index.data(MsgTimeRole).toString());
|
||||
painter->drawText(sizeRect, Qt::AlignLeft | Qt::AlignVCenter, info);
|
||||
|
||||
painter->restore();
|
||||
return;
|
||||
|
||||
|
||||
}
|
||||
|
||||
auto *cv = qobject_cast<const ChatView *>(option.widget);
|
||||
|
||||
Reference in new issue
Block a user