attachments: preview bar + combined send (Android + desktop)
Android: file picker → pending preview bar (name+size+X) →
combined send with text; cache copy, save dialog for downloads
Desktop: attach stores pending, preview bar before send,
combined with text in onSendClicked
C: attachment_sender.c — include filename in msg data for display
This commit is contained in:
1 parent
e3df5008da
commit
6a02a16543
7 files changed
+374
-131
No files matched your search
@@ -45,6 +45,16 @@ static QWidget *wrapBottomBtn(QPushButton *btn, int pad) {
|
||||
return w;
|
||||
}
|
||||
|
||||
QString InputBar::formatFileSize(qint64 bytes) {
|
||||
if (bytes < 1024) return QString("%1B").arg(bytes);
|
||||
double kb = bytes / 1024.0;
|
||||
if (kb < 1024.0) return QString("%1KB").arg(kb, 0, 'f', kb < 10.0 ? 1 : 0);
|
||||
double mb = kb / 1024.0;
|
||||
if (mb < 1024.0) return QString("%1MB").arg(mb, 0, 'f', mb < 10.0 ? 1 : 0);
|
||||
double gb = mb / 1024.0;
|
||||
return QString("%1GB").arg(gb, 0, 'f', 1);
|
||||
}
|
||||
|
||||
InputBar::InputBar(EmojiPanel *emojiPanel, AudioRecorder *recorder, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_input(new QTextEdit(this))
|
||||
@@ -53,8 +63,29 @@ InputBar::InputBar(EmojiPanel *emojiPanel, AudioRecorder *recorder, QWidget *par
|
||||
, m_emojiPanel(emojiPanel)
|
||||
, m_recorder(recorder)
|
||||
{
|
||||
auto *layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(8, 4, 8, 4);
|
||||
auto *mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->setContentsMargins(8, 4, 8, 0);
|
||||
mainLayout->setSpacing(2);
|
||||
|
||||
/* Attachment preview bar (hidden until file selected) */
|
||||
m_attachPreview = new QWidget(this);
|
||||
auto *prevLay = new QHBoxLayout(m_attachPreview);
|
||||
prevLay->setContentsMargins(0, 2, 0, 2);
|
||||
prevLay->setSpacing(4);
|
||||
m_attachPreviewLabel = new QLabel(m_attachPreview);
|
||||
m_attachPreviewLabel->setStyleSheet("background: palette(light); border-radius: 6px; padding: 2px 8px;");
|
||||
prevLay->addWidget(m_attachPreviewLabel, 1);
|
||||
m_attachClearBtn = new QPushButton(QString::fromUtf8("\xE2\x9C\x95"), m_attachPreview);
|
||||
m_attachClearBtn->setFixedSize(20, 20);
|
||||
m_attachClearBtn->setCursor(Qt::PointingHandCursor);
|
||||
m_attachClearBtn->setStyleSheet("QPushButton { border: none; background: transparent; color: palette(text); }"
|
||||
"QPushButton:hover { color: #e74c3c; }");
|
||||
connect(m_attachClearBtn, &QPushButton::clicked, this, &InputBar::clearPendingAttachment);
|
||||
prevLay->addWidget(m_attachClearBtn);
|
||||
m_attachPreview->hide();
|
||||
mainLayout->addWidget(m_attachPreview);
|
||||
|
||||
auto *layout = new QHBoxLayout();
|
||||
layout->setSpacing(4);
|
||||
|
||||
m_attachBtn = makeIconBtn(QIcon(":/icons/attach.png"),
|
||||
@@ -144,6 +175,8 @@ InputBar::InputBar(EmojiPanel *emojiPanel, AudioRecorder *recorder, QWidget *par
|
||||
connect(recorder, &AudioRecorder::recordingStopped, this, [this](int) { hideRecordOverlay(); });
|
||||
connect(recorder, &AudioRecorder::durationChanged, this, &InputBar::updateRecordingUI);
|
||||
}
|
||||
|
||||
mainLayout->addLayout(layout);
|
||||
}
|
||||
|
||||
bool InputBar::eventFilter(QObject *obj, QEvent *event) {
|
||||
@@ -185,15 +218,29 @@ void InputBar::adjustInputHeight() {
|
||||
|
||||
void InputBar::onSendClicked() {
|
||||
QString text = m_input->toPlainText();
|
||||
GUI_INFO("send: len=%d hasLF=%d text='%s'",
|
||||
text.length(), text.contains('\n'), qPrintable(text));
|
||||
while (!text.isEmpty() && (text.back() == ' ' || text.back() == '\t'))
|
||||
text.chop(1);
|
||||
if (text.isEmpty()) return;
|
||||
emit sendMessage(text);
|
||||
m_input->clear();
|
||||
if (m_emojiPanel) m_emojiPanel->hide();
|
||||
m_input->setFocus();
|
||||
|
||||
bool hasAttach = !m_pendingAttachSrc.isEmpty();
|
||||
if (!hasAttach && text.isEmpty()) return;
|
||||
|
||||
if (hasAttach) {
|
||||
GUI_INFO("send: file=%s name=%s", qPrintable(m_pendingAttachSrc), qPrintable(m_pendingAttachName));
|
||||
emit sendFileAttachment(m_pendingAttachSrc, m_pendingAttachDest, m_pendingAttachName);
|
||||
m_pendingAttachSrc.clear();
|
||||
m_pendingAttachDest.clear();
|
||||
m_pendingAttachName.clear();
|
||||
m_pendingAttachSize = 0;
|
||||
m_attachPreview->hide();
|
||||
}
|
||||
if (!text.isEmpty()) {
|
||||
GUI_INFO("send: len=%d hasLF=%d text='%s'",
|
||||
text.length(), text.contains('\n'), qPrintable(text));
|
||||
emit sendMessage(text);
|
||||
m_input->clear();
|
||||
if (m_emojiPanel) m_emojiPanel->hide();
|
||||
m_input->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void InputBar::setRecordingContext(const QString& mediaDirBase, const QString& channelId) {
|
||||
@@ -284,9 +331,26 @@ void InputBar::onAttachClicked() {
|
||||
QString destPath = QString("%1/%2_%3_%4.%5")
|
||||
.arg(mediaPath, ts).arg(fi.completeBaseName()).arg(rnd, 4, 16, QChar('0')).arg(fi.suffix().isEmpty() ? "bin" : fi.suffix());
|
||||
|
||||
GUI_INFO("InputBar::onAttachClicked: src=%s dest=%s",
|
||||
qPrintable(srcPath), qPrintable(destPath));
|
||||
emit sendFileAttachment(srcPath, destPath, fi.fileName());
|
||||
m_pendingAttachSrc = srcPath;
|
||||
m_pendingAttachDest = destPath;
|
||||
m_pendingAttachName = fi.fileName();
|
||||
m_pendingAttachSize = fi.size();
|
||||
|
||||
QString labelText = QString::fromUtf8("\xF0\x9F\x93\x8E %1 (%2)")
|
||||
.arg(fi.fileName(), formatFileSize(fi.size()));
|
||||
m_attachPreviewLabel->setText(labelText);
|
||||
m_attachPreview->show();
|
||||
|
||||
GUI_INFO("InputBar::onAttachClicked: pending %s size=%lld",
|
||||
qPrintable(srcPath), (long long)fi.size());
|
||||
}
|
||||
|
||||
void InputBar::clearPendingAttachment() {
|
||||
m_pendingAttachSrc.clear();
|
||||
m_pendingAttachDest.clear();
|
||||
m_pendingAttachName.clear();
|
||||
m_pendingAttachSize = 0;
|
||||
m_attachPreview->hide();
|
||||
}
|
||||
|
||||
void InputBar::resizeEvent(QResizeEvent* event) {
|
||||
|
||||
Reference in new issue
Block a user