Compare commits

...

2 Commits

Author SHA1 Message Date
wuyize 3f30e4ed4d Merge remote-tracking branch 'origin/main' into main 2023-07-03 17:13:58 +08:00
wuyize ec46100322 初步完成传输列表的UI 2023-07-03 17:13:47 +08:00
9 changed files with 279 additions and 73 deletions

View File

@ -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 { RowLayout {
anchors.fill: parent anchors.fill: parent
@ -101,10 +85,7 @@ FluWindow {
onReady: { onReady: {
setTitleBarItem(title_bar) setTitleBarItem(title_bar)
moveWindowToDesktopCenter() moveWindowToDesktopCenter()
setHitTestVisible(title_bar.minimizeButton()) title_bar.setHitTestVisibleItems(framless_helper)
setHitTestVisible(title_bar.maximizeButton())
setHitTestVisible(title_bar.closeButton())
setHitTestVisible(title_bar.transferButton())
title_bar.maximizeButton.visible = true title_bar.maximizeButton.visible = true
// window.backgroundVisible = false // window.backgroundVisible = false
window.show() window.show()

View File

@ -110,6 +110,15 @@ Rectangle {
} }
} }
FluIconButton {
id: btn_note
height: 32
width: 32
Layout.rightMargin: 10
iconSource: FluentIcons.PenPalette
iconSize: 14
}
Text { Text {
Layout.margins: { Layout.margins: {
right: 10 right: 10
@ -204,7 +213,10 @@ Rectangle {
return btn_close return btn_close
} }
function transferButton() { function setHitTestVisibleItems(frameless_helper) {
return btn_transfer frameless_helper.setHitTestVisible(btn_minimize)
frameless_helper.setHitTestVisible(btn_maximize)
frameless_helper.setHitTestVisible(btn_close)
frameless_helper.setHitTestVisible(btn_transfer)
} }
} }

View File

@ -16,52 +16,29 @@ Popup {
FluShadow {} FluShadow {}
} }
contentItem: Item { contentItem: FluScrollablePage {
anchors.top: parent.top anchors.fill: parent
anchors.topMargin: 10
ListModel //-
{
id: itemModel
ListElement {
name: "Apple"
progressValue: 0.1
}
ListElement {
name: "Orange"
progressValue: 1
}
ListElement {
name: "Banana"
progressValue: 0.6
}
}
Component //-
{
id: itemDelegate
ColumnLayout { ColumnLayout {
Layout.fillWidth: true
Layout.bottomMargin: -10
Repeater {
model: FileTransferListModel
delegate: ColumnLayout {
Layout.bottomMargin: 10
spacing: 10 spacing: 10
width: parent.width width: parent.width
Text { Text {
Layout.topMargin: 10
text: name text: name
} }
FluProgressBar { FluProgressBar {
Layout.fillWidth: true Layout.fillWidth: true
progress: progressValue progress: completedSize / totalSize
indeterminate: false indeterminate: false
} }
} }
} }
ListView //-
{
anchors.fill: parent
model: itemModel
delegate: itemDelegate
} }
} }
} }

View File

@ -5,13 +5,14 @@ import QtQuick.Controls
import QtQuick.Controls.Basic import QtQuick.Controls.Basic
import QtWebEngine 1.2 import QtWebEngine 1.2
import FluentUI import FluentUI
import AicsKB.FileTransferManager
FluArea { FluArea {
id: content_area id: content_area
paddings: 0 paddings: 0
backgroundColor: "#f9f9f9" backgroundColor: "#f9f9f9"
property string type: "" property string type: ""
property int knowledgeFileId property string knowledgeFileId
signal download(string knowledgeFileId) signal download(string knowledgeFileId)
signal clickTags(string tagName) signal clickTags(string tagName)
@ -134,6 +135,7 @@ FluArea {
} }
onClicked: { onClicked: {
emit: content_area.download(content_area.knowledgeFileId) emit: content_area.download(content_area.knowledgeFileId)
FileTransferManager.download(content_area.knowledgeFileId)
} }
} }
} }
@ -148,7 +150,7 @@ FluArea {
id: video_view id: video_view
FluMediaPlayer { FluMediaPlayer {
Layout.fillWidth: true Layout.fillWidth: true
implicitHeight: 270 implicitHeight: width * 9 / 16.
} }
} }
Component { Component {

View File

@ -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<int, QByteArray> 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));
}
}

View File

@ -0,0 +1,47 @@
#ifndef AICSKNOWLEDGEBASE_FILETRANSFERLISTMODEL_H
#define AICSKNOWLEDGEBASE_FILETRANSFERLISTMODEL_H
#include <QAbstractListModel>
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<int, QByteArray> 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<FileItem> m_data;
QHash<int, QByteArray> m_roleName;
};
#endif // AICSKNOWLEDGEBASE_FILETRANSFERLISTMODEL_H

View File

@ -5,12 +5,59 @@
#include "FileTransferManager.h" #include "FileTransferManager.h"
#include <QDebug> #include <QDebug>
#include <curl/curl.h> #include <curl/curl.h>
#include <QJsonDocument>
#include <QtConcurrent/QtConcurrent>
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) void FileTransferManager::upload(QUrl fileUrl)
{ {
qDebug() << fileUrl.fileName(); qDebug() << fileUrl.fileName();
@ -49,3 +96,42 @@ void FileTransferManager::upload(QUrl fileUrl)
curl_easy_cleanup(curl); 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";
});
}

View File

@ -8,14 +8,20 @@
#include <QObject> #include <QObject>
#include <QUrl> #include <QUrl>
#include "FileTransferListModel.h"
class FileTransferManager : public QObject class FileTransferManager : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit FileTransferManager(QObject *parent = nullptr); explicit FileTransferManager(FileTransferListModel &model, QObject *parent = nullptr);
Q_INVOKABLE void upload(QUrl fileUrl); Q_INVOKABLE void upload(QUrl fileUrl);
Q_INVOKABLE void download(QString fileId);
private:
FileTransferListModel &model;
}; };

View File

@ -7,13 +7,19 @@
#include <QtWebEngineQuick/qtwebenginequickglobal.h> #include <QtWebEngineQuick/qtwebenginequickglobal.h>
#include <FramelessHelper/Quick/framelessquickmodule.h> #include <FramelessHelper/Quick/framelessquickmodule.h>
#include <FramelessHelper/Core/private/framelessconfig_p.h> #include <FramelessHelper/Core/private/framelessconfig_p.h>
#include <curl/curl.h>
#include "HttpClient.h" #include "HttpClient.h"
#include "FileTransferManager.h" #include "FileTransferManager.h"
#include "FileTransferListModel.h"
FRAMELESSHELPER_USE_NAMESPACE FRAMELESSHELPER_USE_NAMESPACE
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
if (CURLE_OK != curl_global_init(CURL_GLOBAL_DEFAULT))
return CURLE_FAILED_INIT;
//将样式设置为Basic不然会导致组件显示异常 //将样式设置为Basic不然会导致组件显示异常
qputenv("QT_QUICK_CONTROLS_STYLE", "Basic"); qputenv("QT_QUICK_CONTROLS_STYLE", "Basic");
@ -38,8 +44,12 @@ int main(int argc, char *argv[])
QQmlApplicationEngine engine; QQmlApplicationEngine engine;
FramelessHelper::Quick::registerTypes(&engine); FramelessHelper::Quick::registerTypes(&engine);
FileTransferListModel fileTransferListModel;
engine.rootContext()->setContextProperty("FileTransferListModel", &fileTransferListModel);
auto httpClient = new HttpClient(engine); auto httpClient = new HttpClient(engine);
auto fileTransferManager = new FileTransferManager(); auto fileTransferManager = new FileTransferManager(fileTransferListModel);
qmlRegisterSingletonInstance<HttpClient>("AicsKB.HttpClient", 1, 0, "HttpClient", httpClient); qmlRegisterSingletonInstance<HttpClient>("AicsKB.HttpClient", 1, 0, "HttpClient", httpClient);
qmlRegisterSingletonInstance<FileTransferManager>("AicsKB.FileTransferManager", 1, 0, "FileTransferManager", qmlRegisterSingletonInstance<FileTransferManager>("AicsKB.FileTransferManager", 1, 0, "FileTransferManager",
@ -56,6 +66,6 @@ int main(int argc, char *argv[])
auto result = QGuiApplication::exec(); auto result = QGuiApplication::exec();
httpClient->deleteLater(); httpClient->deleteLater();
fileTransferManager->deleteLater(); fileTransferManager->deleteLater();
curl_global_cleanup();
return result; return result;
} }