diff --git a/tools/chatgui/src/member_files/batch.cpp b/tools/chatgui/src/member_files/batch.cpp index a8d67369..eba3b045 100644 --- a/tools/chatgui/src/member_files/batch.cpp +++ b/tools/chatgui/src/member_files/batch.cpp @@ -133,7 +133,8 @@ void MemberFileBatch::next() { if (m_queue.isEmpty() && !m_verify.isEmpty()) { m_queue = m_verify; m_verify.clear(); } if (m_queue.isEmpty()) { finish(); return; } const auto entry = m_queue.first(); - if (!pathBytes(entry.remote, true) || (m_mode != Remove && !pathBytes(entry.local, false))) { + if (!pathBytes(entry.remote, true) || (m_mode != Remove && !pathBytes(entry.local, false)) || + (m_mode == Download && (entry.version.size() != 16 || mf_zero((const uint8_t*)entry.version.constData(), 16)))) { finish(text("Cannot copy this path: %1").arg(entry.remote)); return; } progress(text("Processed %1, skipped %2, remaining %3: %4").arg(m_done).arg(m_skipped).arg(m_queue.size()).arg(entry.remote), -1); @@ -267,7 +268,7 @@ void MemberFileBatch::finish(const QString& error) { if (m_finished) return; m_finished = true; bool ok = error.isEmpty() && !m_cancelled; - QString summary = text("Completed: %1, skipped: %2").arg(m_done).arg(m_skipped); + QString summary = text("Completed: %1, skipped: %2, remaining: %3").arg(m_done).arg(m_skipped).arg(m_queue.size()); if (!ok) summary = (m_cancelled ? text("Copy cancelled") : error) + " — " + summary; if (ok) DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "file batch: %s", qPrintable(summary)); else DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "file batch: %s", qPrintable(summary)); diff --git a/tools/chatgui/src/member_files/batch.h b/tools/chatgui/src/member_files/batch.h index 1d649724..fecb7bdd 100644 --- a/tools/chatgui/src/member_files/batch.h +++ b/tools/chatgui/src/member_files/batch.h @@ -47,7 +47,7 @@ private: QList m_queue, m_verify; QSet m_seen; QStringList m_roots; - QString m_temporary, m_error; + QString m_temporary; QThreadPool m_pool; std::atomic_bool m_cancelled{false}; bool m_work = false, m_finished = false; diff --git a/tools/chatgui/src/member_files/browser.cpp b/tools/chatgui/src/member_files/browser.cpp index 43d35bf9..6a969654 100644 --- a/tools/chatgui/src/member_files/browser.cpp +++ b/tools/chatgui/src/member_files/browser.cpp @@ -547,7 +547,7 @@ void MemberFileBrowser::publishExport(const QStringList& paths, bool clipboard) DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "file browser: exporting entries=%d clipboard=%d", int(paths.size()), clipboard); if (clipboard) { QGuiApplication::clipboard()->setMimeData(mime); - m_status->setText(text("File copied. Paste it in your file manager.")); + m_status->setText(text("Selection copied. Paste it in your file manager.")); } else { auto* drag = new QDrag(m_entries); drag->setMimeData(mime); drag->exec(Qt::CopyAction, Qt::CopyAction); } @@ -556,14 +556,19 @@ void MemberFileBrowser::publishExport(const QStringList& paths, bool clipboard) void MemberFileBrowser::exportFile(bool clipboard, const QString& destination) { if (!m_copyAction->isEnabled()) { DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "file browser: export unavailable"); - m_status->setText(text("Select a file and finish the current transfer first")); return; + m_status->setText(text("Select entries and finish the current transfer first")); return; } auto entries = selectedEntries(); if (entries.isEmpty()) return; - QString base = destination.isEmpty() ? QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/file-exports" : destination; + QString base = destination.isEmpty() ? QStandardPaths::writableLocation(QStandardPaths::CacheLocation) : destination; + if (base.isEmpty()) { + DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "file browser: export has no cache location"); + m_status->setText(text("Cannot prepare a local copy")); return; + } + if (destination.isEmpty()) base += "/file-exports"; m_exportId = requestId(); m_exportResult.clear(); m_openAfter = false; quint64 id = m_exportId; auto* batch = createBatch(MemberFileBatch::Download); - batch->finished = [this, batch, clipboard, destination](bool ok, const QString& summary, const QStringList& roots) { + batch->finished = [this, batch, clipboard](bool ok, const QString& summary, const QStringList& roots) { m_batch = nullptr; m_exportId = 0; m_progress->hide(); m_uploadStatus->setText(summary); m_exportResult = ok ? roots : QStringList(); batch->deleteLater(); updateActions(); if (ok && clipboard) publishExport(roots, true); @@ -637,10 +642,13 @@ void MemberFileBrowser::mutate(uint8_t command) { if (command == MF_REMOVE_PATH) { auto entries = selectedEntries(); if (entries.isEmpty()) return; QPointer guard(this); + m_dropId = requestId(); updateActions(); QString prompt = entries.size() == 1 ? text("Delete %1?").arg(entries.first().remote) : text("Delete %1 selected entries? Non-empty folders will not be removed.").arg(entries.size()); auto answer = QMessageBox::question(this, text("Delete"), prompt, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - if (!guard || answer != QMessageBox::Yes) return; + if (!guard) return; + bool cancelled = !m_dropId; m_dropId = 0; updateActions(); + if (cancelled || answer != QMessageBox::Yes) return; auto* batch = createBatch(MemberFileBatch::Remove); batch->finished = [this, batch](bool, const QString& summary, const QStringList&) { m_batch = nullptr; m_progress->hide(); m_uploadStatus->setText(summary); batch->deleteLater(); updateActions(); refresh();