From ec461003226021ec72939ac4a78d6a98dabf0a09 Mon Sep 17 00:00:00 2001 From: wuyize Date: Mon, 3 Jul 2023 17:13:47 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=8C=E6=88=90=E4=BC=A0?= =?UTF-8?q?=E8=BE=93=E5=88=97=E8=A1=A8=E7=9A=84UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AicsKnowledgeBase/qml/MainWindow.qml | 21 +---- .../qml/component/CustomAppBar.qml | 16 +++- .../qml/component/TransferListPopup.qml | 63 +++++-------- AicsKnowledgeBase/qml/page/ContentPage.qml | 6 +- .../src/FileTransferListModel.cpp | 85 ++++++++++++++++++ AicsKnowledgeBase/src/FileTransferListModel.h | 47 ++++++++++ AicsKnowledgeBase/src/FileTransferManager.cpp | 90 ++++++++++++++++++- AicsKnowledgeBase/src/FileTransferManager.h | 10 ++- AicsKnowledgeBase/src/main.cpp | 14 ++- 9 files changed, 279 insertions(+), 73 deletions(-) create mode 100644 AicsKnowledgeBase/src/FileTransferListModel.cpp create mode 100644 AicsKnowledgeBase/src/FileTransferListModel.h diff --git a/AicsKnowledgeBase/qml/MainWindow.qml b/AicsKnowledgeBase/qml/MainWindow.qml index ff9d053..0e18052 100644 --- a/AicsKnowledgeBase/qml/MainWindow.qml +++ b/AicsKnowledgeBase/qml/MainWindow.qml @@ -26,22 +26,6 @@ FluWindow { } } - RowLayout { - id: tool_bar - anchors.top: parent.top - anchors.right: parent.right - anchors.rightMargin: 140 - - height: 44 - - layoutDirection: Qt.RightToLeft - - // Rectangle{ - // anchors.fill: parent - // color: "red" - // } - } - RowLayout { anchors.fill: parent @@ -101,10 +85,7 @@ FluWindow { onReady: { setTitleBarItem(title_bar) moveWindowToDesktopCenter() - setHitTestVisible(title_bar.minimizeButton()) - setHitTestVisible(title_bar.maximizeButton()) - setHitTestVisible(title_bar.closeButton()) - setHitTestVisible(title_bar.transferButton()) + title_bar.setHitTestVisibleItems(framless_helper) title_bar.maximizeButton.visible = true // window.backgroundVisible = false window.show() diff --git a/AicsKnowledgeBase/qml/component/CustomAppBar.qml b/AicsKnowledgeBase/qml/component/CustomAppBar.qml index 8e9c4c3..56ead21 100644 --- a/AicsKnowledgeBase/qml/component/CustomAppBar.qml +++ b/AicsKnowledgeBase/qml/component/CustomAppBar.qml @@ -110,6 +110,15 @@ Rectangle { } } + FluIconButton { + id: btn_note + height: 32 + width: 32 + Layout.rightMargin: 10 + iconSource: FluentIcons.PenPalette + iconSize: 14 + } + Text { Layout.margins: { right: 10 @@ -204,7 +213,10 @@ Rectangle { return btn_close } - function transferButton() { - return btn_transfer + function setHitTestVisibleItems(frameless_helper) { + frameless_helper.setHitTestVisible(btn_minimize) + frameless_helper.setHitTestVisible(btn_maximize) + frameless_helper.setHitTestVisible(btn_close) + frameless_helper.setHitTestVisible(btn_transfer) } } diff --git a/AicsKnowledgeBase/qml/component/TransferListPopup.qml b/AicsKnowledgeBase/qml/component/TransferListPopup.qml index 371103f..dece83f 100644 --- a/AicsKnowledgeBase/qml/component/TransferListPopup.qml +++ b/AicsKnowledgeBase/qml/component/TransferListPopup.qml @@ -16,52 +16,29 @@ Popup { FluShadow {} } - contentItem: Item { - anchors.top: parent.top + contentItem: FluScrollablePage { + anchors.fill: parent + anchors.topMargin: 10 + ColumnLayout { + Layout.fillWidth: true + Layout.bottomMargin: -10 + Repeater { + model: FileTransferListModel + delegate: ColumnLayout { + Layout.bottomMargin: 10 + spacing: 10 + width: parent.width + Text { + text: name + } - ListModel //模型-提供数据 - { - id: itemModel - ListElement { - - name: "Apple" - progressValue: 0.1 - } - ListElement { - name: "Orange" - progressValue: 1 - } - ListElement { - name: "Banana" - progressValue: 0.6 - } - } - - Component //委托-提供一个展示数据的示例(如何展示一个模型中的数据) - { - id: itemDelegate - - ColumnLayout { - spacing: 10 - width: parent.width - Text { - Layout.topMargin: 10 - text: name - } - - FluProgressBar { - Layout.fillWidth: true - progress: progressValue - indeterminate: false + FluProgressBar { + Layout.fillWidth: true + progress: completedSize / totalSize + indeterminate: false + } } } } - - ListView //视图-设置委托和模型,根据委托提供的展示方式展示模型提供的数据 - { - anchors.fill: parent - model: itemModel - delegate: itemDelegate - } } } diff --git a/AicsKnowledgeBase/qml/page/ContentPage.qml b/AicsKnowledgeBase/qml/page/ContentPage.qml index 3b081f1..626fdfb 100644 --- a/AicsKnowledgeBase/qml/page/ContentPage.qml +++ b/AicsKnowledgeBase/qml/page/ContentPage.qml @@ -5,13 +5,14 @@ import QtQuick.Controls import QtQuick.Controls.Basic import QtWebEngine 1.2 import FluentUI +import AicsKB.FileTransferManager FluArea { id: content_area paddings: 0 backgroundColor: "#f9f9f9" property string type: "" - property int knowledgeFileId + property string knowledgeFileId signal download(string knowledgeFileId) signal clickTags(string tagName) @@ -134,6 +135,7 @@ FluArea { } onClicked: { emit: content_area.download(content_area.knowledgeFileId) + FileTransferManager.download(content_area.knowledgeFileId) } } } @@ -148,7 +150,7 @@ FluArea { id: video_view FluMediaPlayer { Layout.fillWidth: true - implicitHeight: 270 + implicitHeight: width * 9 / 16. } } Component { diff --git a/AicsKnowledgeBase/src/FileTransferListModel.cpp b/AicsKnowledgeBase/src/FileTransferListModel.cpp new file mode 100644 index 0000000..b079988 --- /dev/null +++ b/AicsKnowledgeBase/src/FileTransferListModel.cpp @@ -0,0 +1,85 @@ +#include "FileTransferListModel.h" + +FileTransferListModel::FileTransferListModel(QObject *parent) + : QAbstractListModel(parent) +{ + m_roleName.insert(kIdRole, "fileId"); + m_roleName.insert(kNameRole, "name"); + m_roleName.insert(kCompletedSizeRole, "completedSize"); + m_roleName.insert(kTotalSizeRole, "totalSize"); + + m_data = { + {"v", "vivo", 1200, 2000}, + {"m", "meizu", 1300, 1500}, + {"a", "apple", 1400, 1400}, + }; + + +} + + +int FileTransferListModel::rowCount(const QModelIndex &parent) const +{ + // For list models only the root node (an invalid parent) should return the list's size. For all + // other (valid) parents, rowCount() should return 0 so that it does not become a tree model. + if (parent.isValid()) + return 0; + + return m_data.size(); +} + +QVariant FileTransferListModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + switch (role) { + case kIdRole: + return m_data.value(index.row()).id; + case kNameRole: + return m_data.value(index.row()).name; + case kCompletedSizeRole: + return m_data.value(index.row()).completedSize; + case kTotalSizeRole: + return m_data.value(index.row()).totalSize; + default: + break; + } + + return QVariant(); + +} + +QHash FileTransferListModel::roleNames() const +{ + return m_roleName; +} + +QAbstractItemModel *FileTransferListModel::model() +{ + return this; +} + + + +void FileTransferListModel::insertItem(const FileItem &item) +{ + beginInsertRows(QModelIndex(), 0, 0); + m_data.push_front(item); + endInsertRows(); +} + +void FileTransferListModel::setItem(const FileItem &item) +{ + auto iter = std::find_if(m_data.begin(), m_data.end(), [&item](FileItem &i) { + return i.id == item.id; + }); + + if (iter != m_data.end()) { + int row = iter - m_data.begin(); + *iter = item; + emit dataChanged(createIndex(row, 0), createIndex(row, 0)); + } +} + + diff --git a/AicsKnowledgeBase/src/FileTransferListModel.h b/AicsKnowledgeBase/src/FileTransferListModel.h new file mode 100644 index 0000000..092e357 --- /dev/null +++ b/AicsKnowledgeBase/src/FileTransferListModel.h @@ -0,0 +1,47 @@ +#ifndef AICSKNOWLEDGEBASE_FILETRANSFERLISTMODEL_H +#define AICSKNOWLEDGEBASE_FILETRANSFERLISTMODEL_H + +#include + +struct FileItem +{ + QString id; + QString name; + int completedSize; + int totalSize; +}; + + +class FileTransferListModel : public QAbstractListModel +{ +Q_OBJECT + +public: + explicit FileTransferListModel(QObject *parent = nullptr); + + // Basic functionality: + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + + QHash roleNames() const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + void insertItem(const FileItem &item); + + void setItem(const FileItem &item); + + Q_INVOKABLE QAbstractItemModel *model(); + + enum FileItemRole + { + kIdRole = Qt::UserRole + 1, + kNameRole, + kCompletedSizeRole, + kTotalSizeRole + }; +private: + QList m_data; + QHash m_roleName; +}; + +#endif // AICSKNOWLEDGEBASE_FILETRANSFERLISTMODEL_H diff --git a/AicsKnowledgeBase/src/FileTransferManager.cpp b/AicsKnowledgeBase/src/FileTransferManager.cpp index 9184507..ff98641 100644 --- a/AicsKnowledgeBase/src/FileTransferManager.cpp +++ b/AicsKnowledgeBase/src/FileTransferManager.cpp @@ -5,12 +5,59 @@ #include "FileTransferManager.h" #include #include +#include +#include -FileTransferManager::FileTransferManager(QObject *parent) : QObject(parent) +static const std::string baseUrl = "http://127.0.0.1:4523/m1/2914957-0-default/"; + +static size_t writeDataCallback(void *contents, size_t size, size_t nmemb, void *userp) +{ + try { + size_t realSize = size * nmemb; + static int current_index = 0; + int content_size = nmemb * size; + std::string result = std::string((char *) contents, content_size); + auto *pStr = (std::string *) userp; + if (pStr) { + (*pStr).append(result); + } + return realSize; + } + catch (...) {} + return 0; +} + +CURLcode httpGet(const std::string &url, std::string &response, int timeout = 3000) +{ + CURLcode res; + + // 获取easy handle + CURL *easy_handle = curl_easy_init(); + if (nullptr == easy_handle) { + curl_global_cleanup(); + return CURLE_FAILED_INIT; + } + // 设置easy handle属性 + //curl_easy_setopt(easy_handle, CURLOPT_HTTP_VERSION, (long) CURL_HTTP_VERSION_3ONLY); + curl_easy_setopt(easy_handle, CURLOPT_URL, (baseUrl + url).c_str()); + curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, writeDataCallback); + curl_easy_setopt(easy_handle, CURLOPT_TIMEOUT, timeout); + curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, (void *) &response); + curl_easy_setopt(easy_handle, CURLOPT_FOLLOWLOCATION, 1L); + //curl_easy_setopt(easy_handle, CURLOPT_DEFAULT_PROTOCOL, "https"); + // 执行数据请求 + res = curl_easy_perform(easy_handle); + curl_easy_cleanup(easy_handle); + return res; +} + +FileTransferManager::FileTransferManager(FileTransferListModel &model, QObject *parent) + : model(model), QObject(parent) { } + void FileTransferManager::upload(QUrl fileUrl) { qDebug() << fileUrl.fileName(); @@ -19,7 +66,7 @@ void FileTransferManager::upload(QUrl fileUrl) CURL *curl; CURLcode res; curl = curl_easy_init(); - if(curl) { + if (curl) { curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:4523/m1/2914957-0-default/"); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); @@ -49,3 +96,42 @@ void FileTransferManager::upload(QUrl fileUrl) curl_easy_cleanup(curl); } +void FileTransferManager::download(QString fileId) +{ + static int _fileId = 0; + fileId = QString::number(_fileId++); + + QtConcurrent::run([fileId, this] { + qDebug() << "Start Get"; + std::string resData; + if (CURLE_OK != httpGet(fileId.toStdString() + "/status", resData)) + return; + + qDebug() << resData.c_str(); + auto resJson = QJsonDocument::fromJson(resData.c_str()); + //if(!resJson["isCompleted"].toBool()) + // return; + + int size = resJson["size"].toInt(); + FileItem item{fileId, resJson["md5"].toString(), 0, size}; + QTimer::singleShot(0, qApp, [this, item]() { + model.insertItem(item); + }); + + while (item.completedSize < item.totalSize) { + item.completedSize += 1; + QTimer::singleShot(0, qApp, [this, item]() { + model.setItem(item); + }); + + using namespace std::chrono_literals; + std::this_thread::sleep_for(100ms); + } + + + qDebug() << "End Get"; + }); + + +} + diff --git a/AicsKnowledgeBase/src/FileTransferManager.h b/AicsKnowledgeBase/src/FileTransferManager.h index 21bb2c5..8c438c2 100644 --- a/AicsKnowledgeBase/src/FileTransferManager.h +++ b/AicsKnowledgeBase/src/FileTransferManager.h @@ -8,14 +8,20 @@ #include #include +#include "FileTransferListModel.h" -class FileTransferManager: public QObject +class FileTransferManager : public QObject { Q_OBJECT public: - explicit FileTransferManager(QObject *parent = nullptr); + explicit FileTransferManager(FileTransferListModel &model, QObject *parent = nullptr); + Q_INVOKABLE void upload(QUrl fileUrl); + Q_INVOKABLE void download(QString fileId); + +private: + FileTransferListModel &model; }; diff --git a/AicsKnowledgeBase/src/main.cpp b/AicsKnowledgeBase/src/main.cpp index c7f388e..731c748 100644 --- a/AicsKnowledgeBase/src/main.cpp +++ b/AicsKnowledgeBase/src/main.cpp @@ -7,13 +7,19 @@ #include #include #include +#include #include "HttpClient.h" #include "FileTransferManager.h" +#include "FileTransferListModel.h" FRAMELESSHELPER_USE_NAMESPACE int main(int argc, char *argv[]) { + if (CURLE_OK != curl_global_init(CURL_GLOBAL_DEFAULT)) + return CURLE_FAILED_INIT; + + //将样式设置为Basic,不然会导致组件显示异常 qputenv("QT_QUICK_CONTROLS_STYLE", "Basic"); @@ -38,8 +44,12 @@ int main(int argc, char *argv[]) QQmlApplicationEngine engine; FramelessHelper::Quick::registerTypes(&engine); + + FileTransferListModel fileTransferListModel; + engine.rootContext()->setContextProperty("FileTransferListModel", &fileTransferListModel); + auto httpClient = new HttpClient(engine); - auto fileTransferManager = new FileTransferManager(); + auto fileTransferManager = new FileTransferManager(fileTransferListModel); qmlRegisterSingletonInstance("AicsKB.HttpClient", 1, 0, "HttpClient", httpClient); qmlRegisterSingletonInstance("AicsKB.FileTransferManager", 1, 0, "FileTransferManager", @@ -56,6 +66,6 @@ int main(int argc, char *argv[]) auto result = QGuiApplication::exec(); httpClient->deleteLater(); fileTransferManager->deleteLater(); - + curl_global_cleanup(); return result; }