add data collect.
This commit is contained in:
parent
5adb0d783d
commit
6289b66ac5
@ -9,7 +9,8 @@
|
|||||||
|
|
||||||
Application::Application(int &argc, char **argv)
|
Application::Application(int &argc, char **argv)
|
||||||
: m_app(std::make_shared<QGuiApplication>(argc, argv)), m_videoFrameProvider(new VideoFrameProvider()),
|
: m_app(std::make_shared<QGuiApplication>(argc, argv)), m_videoFrameProvider(new VideoFrameProvider()),
|
||||||
m_player(std::make_shared<H264Palyer>()), m_devices(new DeviceListModel(this)) {
|
m_player(std::make_shared<H264Palyer>()), m_devices(new DeviceListModel(this)),
|
||||||
|
m_collector(new DataCollection(this)) {
|
||||||
QFont font;
|
QFont font;
|
||||||
font.setPointSize(16);
|
font.setPointSize(16);
|
||||||
m_app->setFont(font);
|
m_app->setFont(font);
|
||||||
@ -149,25 +150,27 @@ void Application::updateNetworkInfomation(bool dhcp, const QString &ip, const QS
|
|||||||
void Application::connectToDevice(int index) {
|
void Application::connectToDevice(int index) {
|
||||||
if (!m_device.expired()) {
|
if (!m_device.expired()) {
|
||||||
auto device = m_device.lock();
|
auto device = m_device.lock();
|
||||||
disconnect(device.get(), &DeviceConnection::currentOpenDoorAreaChanged, this,
|
disconnect(device.get(), &DeviceConnection::openDoorAreaChanged, this, &Application::onDeviceOpenDoorArea);
|
||||||
&Application::onDeviceOpenDoorArea);
|
disconnect(device.get(), &DeviceConnection::shieldedAreaChanged, this, &Application::onDeviceShieldedArea);
|
||||||
disconnect(device.get(), &DeviceConnection::currentShieldedAreaChanged, this,
|
disconnect(device.get(), &DeviceConnection::antiClipAreaChanged, this, &Application::onDeviceAntiClipArea);
|
||||||
&Application::onDeviceShieldedArea);
|
disconnect(device.get(), &DeviceConnection::networkInfomationChanged, this,
|
||||||
disconnect(device.get(), &DeviceConnection::currentAntiClipAreaChanged, this,
|
|
||||||
&Application::onDeviceAntiClipArea);
|
|
||||||
disconnect(device.get(), &DeviceConnection::currentNetworkInfomationChanged, this,
|
|
||||||
&Application::onDeviceNetworkInfomation);
|
&Application::onDeviceNetworkInfomation);
|
||||||
|
disconnect(device.get(), &DeviceConnection::otaProgressChanged, this,
|
||||||
|
&Application::currentDeviceOtaProgressChanged);
|
||||||
device->setH264FrameCallback(DeviceConnection::H264FrameCallback());
|
device->setH264FrameCallback(DeviceConnection::H264FrameCallback());
|
||||||
device->setLiveStreamEnabled(false);
|
device->setLiveStreamEnabled(false);
|
||||||
}
|
}
|
||||||
|
if (index >= 0) {
|
||||||
auto device = m_devices->device(index);
|
auto device = m_devices->device(index);
|
||||||
m_device = device;
|
m_device = device;
|
||||||
|
|
||||||
connect(device.get(), &DeviceConnection::currentOpenDoorAreaChanged, this, &Application::onDeviceOpenDoorArea);
|
connect(device.get(), &DeviceConnection::openDoorAreaChanged, this, &Application::onDeviceOpenDoorArea);
|
||||||
connect(device.get(), &DeviceConnection::currentShieldedAreaChanged, this, &Application::onDeviceShieldedArea);
|
connect(device.get(), &DeviceConnection::shieldedAreaChanged, this, &Application::onDeviceShieldedArea);
|
||||||
connect(device.get(), &DeviceConnection::currentAntiClipAreaChanged, this, &Application::onDeviceAntiClipArea);
|
connect(device.get(), &DeviceConnection::antiClipAreaChanged, this, &Application::onDeviceAntiClipArea);
|
||||||
connect(device.get(), &DeviceConnection::currentNetworkInfomationChanged, this,
|
connect(device.get(), &DeviceConnection::networkInfomationChanged, this,
|
||||||
&Application::onDeviceNetworkInfomation);
|
&Application::onDeviceNetworkInfomation);
|
||||||
|
connect(device.get(), &DeviceConnection::otaProgressChanged, this,
|
||||||
|
&Application::currentDeviceOtaProgressChanged);
|
||||||
device->setH264FrameCallback([this](const char *data, uint32_t size) {
|
device->setH264FrameCallback([this](const char *data, uint32_t size) {
|
||||||
auto image = m_player->decode((const uint8_t *)data, size);
|
auto image = m_player->decode((const uint8_t *)data, size);
|
||||||
if (image) {
|
if (image) {
|
||||||
@ -192,6 +195,12 @@ void Application::connectToDevice(int index) {
|
|||||||
emit currentShieldedAreaEnabledChanged();
|
emit currentShieldedAreaEnabledChanged();
|
||||||
emit currentAntiClipAreaEnabledChanged();
|
emit currentAntiClipAreaEnabledChanged();
|
||||||
emit currentNetworkInfomationChanged();
|
emit currentNetworkInfomationChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::startSearchDevice() {
|
||||||
|
connectToDevice(-1);
|
||||||
|
m_devices->startSearchDevice();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::upgradeDevice(const QString &file) {
|
void Application::upgradeDevice(const QString &file) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#ifndef APPLICATION_H
|
#ifndef APPLICATION_H
|
||||||
#define APPLICATION_H
|
#define APPLICATION_H
|
||||||
|
|
||||||
|
#include "DataCollection.h"
|
||||||
#include "DataStructure.h"
|
#include "DataStructure.h"
|
||||||
#include "DeviceConnection.h"
|
#include "DeviceConnection.h"
|
||||||
#include "DeviceListModel.h"
|
#include "DeviceListModel.h"
|
||||||
@ -20,6 +21,8 @@ class Application : public QObject {
|
|||||||
Q_PROPERTY(int DeviceWidth MEMBER DeviceWidth CONSTANT FINAL)
|
Q_PROPERTY(int DeviceWidth MEMBER DeviceWidth CONSTANT FINAL)
|
||||||
Q_PROPERTY(int DeviceHeight MEMBER DeviceHeight CONSTANT FINAL)
|
Q_PROPERTY(int DeviceHeight MEMBER DeviceHeight CONSTANT FINAL)
|
||||||
Q_PROPERTY(DeviceListModel *devices MEMBER m_devices CONSTANT FINAL);
|
Q_PROPERTY(DeviceListModel *devices MEMBER m_devices CONSTANT FINAL);
|
||||||
|
Q_PROPERTY(DataCollection *collector MEMBER m_collector CONSTANT FINAL);
|
||||||
|
|
||||||
Q_PROPERTY(DeviceConnection::AreaWay currentOpenDoorAreaWay READ currentOpenDoorAreaWay WRITE
|
Q_PROPERTY(DeviceConnection::AreaWay currentOpenDoorAreaWay READ currentOpenDoorAreaWay WRITE
|
||||||
setCurrentOpenDoorAreaWay NOTIFY currentOpenDoorAreaWayChanged)
|
setCurrentOpenDoorAreaWay NOTIFY currentOpenDoorAreaWayChanged)
|
||||||
Q_PROPERTY(QList<QPointF> currentOpenDoorAreaPoints READ currentOpenDoorAreaPoints WRITE
|
Q_PROPERTY(QList<QPointF> currentOpenDoorAreaPoints READ currentOpenDoorAreaPoints WRITE
|
||||||
@ -65,6 +68,7 @@ public:
|
|||||||
const QString &gateway);
|
const QString &gateway);
|
||||||
Q_INVOKABLE void connectToDevice(int index);
|
Q_INVOKABLE void connectToDevice(int index);
|
||||||
Q_INVOKABLE void upgradeDevice(const QString &file);
|
Q_INVOKABLE void upgradeDevice(const QString &file);
|
||||||
|
Q_INVOKABLE void startSearchDevice();
|
||||||
|
|
||||||
int exec();
|
int exec();
|
||||||
static Application *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine);
|
static Application *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine);
|
||||||
@ -78,6 +82,7 @@ signals:
|
|||||||
void currentShieldedAreaEnabledChanged();
|
void currentShieldedAreaEnabledChanged();
|
||||||
void currentAntiClipAreaEnabledChanged();
|
void currentAntiClipAreaEnabledChanged();
|
||||||
void currentNetworkInfomationChanged();
|
void currentNetworkInfomationChanged();
|
||||||
|
void currentDeviceOtaProgressChanged(bool status, int progress, const QString &message);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Application(int &argc, char **argv);
|
Application(int &argc, char **argv);
|
||||||
@ -92,6 +97,7 @@ private:
|
|||||||
std::shared_ptr<H264Palyer> m_player;
|
std::shared_ptr<H264Palyer> m_player;
|
||||||
std::weak_ptr<DeviceConnection> m_device;
|
std::weak_ptr<DeviceConnection> m_device;
|
||||||
DeviceListModel *m_devices = nullptr;
|
DeviceListModel *m_devices = nullptr;
|
||||||
|
DataCollection *m_collector = nullptr;
|
||||||
|
|
||||||
DeviceConnection::AreaWay m_currentOpenDoorAreaWay = DeviceConnection::Diabled;
|
DeviceConnection::AreaWay m_currentOpenDoorAreaWay = DeviceConnection::Diabled;
|
||||||
QList<QPointF> m_currentOpenDoorAreaPoints;
|
QList<QPointF> m_currentOpenDoorAreaPoints;
|
||||||
|
@ -21,7 +21,7 @@ set(FFmpeg_INCLUDE_DIR ${FFmpeg_ROOT}/include)
|
|||||||
set(FFmpeg_LIB_DIR ${FFmpeg_ROOT}/lib)
|
set(FFmpeg_LIB_DIR ${FFmpeg_ROOT}/lib)
|
||||||
|
|
||||||
find_package(Boost REQUIRED COMPONENTS json)
|
find_package(Boost REQUIRED COMPONENTS json)
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Qml Quick Network)
|
find_package(Qt6 REQUIRED COMPONENTS Qml Quick Network QuickControls2)
|
||||||
|
|
||||||
qt_standard_project_setup(REQUIRES 6.5)
|
qt_standard_project_setup(REQUIRES 6.5)
|
||||||
|
|
||||||
@ -37,6 +37,7 @@ qt_add_executable(AntiClipSettings
|
|||||||
main.cpp
|
main.cpp
|
||||||
Application.h Application.cpp
|
Application.h Application.cpp
|
||||||
DataStructure.h
|
DataStructure.h
|
||||||
|
DataCollection.h DataCollection.cpp
|
||||||
DeviceConnection.h DeviceConnection.cpp
|
DeviceConnection.h DeviceConnection.cpp
|
||||||
DeviceListModel.h DeviceListModel.cpp
|
DeviceListModel.h DeviceListModel.cpp
|
||||||
H264Palyer.h H264Palyer.cpp
|
H264Palyer.h H264Palyer.cpp
|
||||||
@ -46,10 +47,19 @@ qt_add_executable(AntiClipSettings
|
|||||||
qt_add_qml_module(AntiClipSettings
|
qt_add_qml_module(AntiClipSettings
|
||||||
URI AntiClipSettings
|
URI AntiClipSettings
|
||||||
QML_FILES
|
QML_FILES
|
||||||
Main.qml
|
qml/Main.qml
|
||||||
DeviceView.qml
|
qml/DeviceView.qml
|
||||||
NetworkSettingPopup.qml
|
qml/IconButton.qml
|
||||||
OtaPopup.qml
|
qml/MessageDialog.qml
|
||||||
|
qml/NetworkSettingPopup.qml
|
||||||
|
qml/OtaPopup.qml
|
||||||
|
qml/StatusTip.qml
|
||||||
|
qml/DataCollectionPopup.qml
|
||||||
|
RESOURCES
|
||||||
|
resources/popup_close.svg
|
||||||
|
resources/prompt_delete.svg
|
||||||
|
resources/successfull.svg
|
||||||
|
resources/warning.svg
|
||||||
)
|
)
|
||||||
|
|
||||||
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
|
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
|
||||||
@ -78,6 +88,7 @@ target_link_directories(AntiClipSettings
|
|||||||
target_link_libraries(AntiClipSettings
|
target_link_libraries(AntiClipSettings
|
||||||
PRIVATE Qt6::Qml
|
PRIVATE Qt6::Qml
|
||||||
PRIVATE Qt6::Quick
|
PRIVATE Qt6::Quick
|
||||||
|
PRIVATE Qt6::QuickControls2
|
||||||
PRIVATE Qt6::Network
|
PRIVATE Qt6::Network
|
||||||
PRIVATE Boost::json
|
PRIVATE Boost::json
|
||||||
PRIVATE avcodec
|
PRIVATE avcodec
|
||||||
|
90
DataCollection.cpp
Normal file
90
DataCollection.cpp
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#include "DataCollection.h"
|
||||||
|
#include "BoostLog.h"
|
||||||
|
#include <QFile>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <boost/json/object.hpp>
|
||||||
|
#include <boost/json/parse.hpp>
|
||||||
|
#include <boost/json/serialize.hpp>
|
||||||
|
|
||||||
|
DataCollection::DataCollection(QObject *parent) : QObject{parent} {
|
||||||
|
m_manager = new QNetworkAccessManager(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCollection::start(const QString &address) {
|
||||||
|
m_address = address;
|
||||||
|
m_enabled = true;
|
||||||
|
emit enabledChanged();
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCollection::stop() {
|
||||||
|
m_enabled = false;
|
||||||
|
emit enabledChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DataCollection::path() const {
|
||||||
|
return m_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCollection::setPath(const QString &path) {
|
||||||
|
// file:///E:/Downloads/logs
|
||||||
|
auto p = path;
|
||||||
|
if (p.startsWith("file:///")) {
|
||||||
|
p.remove(0, 8);
|
||||||
|
}
|
||||||
|
if (m_path != p) {
|
||||||
|
m_path = p;
|
||||||
|
emit pathChanged();
|
||||||
|
LOG(info) << "set data path: " << m_path.toStdWString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DataCollection::enabled() const {
|
||||||
|
return m_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCollection::start() {
|
||||||
|
auto url = QString("http://%1:8080/capture.do").arg(m_address);
|
||||||
|
QNetworkRequest request;
|
||||||
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
request.setUrl(url);
|
||||||
|
|
||||||
|
boost::json::object data;
|
||||||
|
data["devid"] = 1;
|
||||||
|
auto content = boost::json::serialize(data);
|
||||||
|
QNetworkReply *reply = m_manager->post(request, QString::fromStdString(content).toLocal8Bit());
|
||||||
|
connect(reply, &QNetworkReply::finished, this, &DataCollection::onCaptureFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCollection::onCaptureFinished() {
|
||||||
|
auto reply = dynamic_cast<QNetworkReply *>(sender());
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
auto text = reply->readAll().toStdString();
|
||||||
|
|
||||||
|
auto replyVale = boost::json::parse(text);
|
||||||
|
auto root = replyVale.as_object();
|
||||||
|
|
||||||
|
m_filename = QString::fromStdString(std::string(root.at("path").as_string()));
|
||||||
|
auto url = QString("http://%1:8080/%2").arg(m_address, m_filename);
|
||||||
|
QNetworkRequest request;
|
||||||
|
request.setUrl(url);
|
||||||
|
QNetworkReply *dataReply = m_manager->get(request);
|
||||||
|
connect(dataReply, &QNetworkReply::finished, this, &DataCollection::onDataGetFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCollection::onDataGetFinished() {
|
||||||
|
auto reply = dynamic_cast<QNetworkReply *>(sender());
|
||||||
|
auto data = reply->readAll();
|
||||||
|
LOG(info) << "error: " << reply->error() << ", capture data size: " << data.size();
|
||||||
|
|
||||||
|
QFile file(m_path + "/" + m_filename);
|
||||||
|
file.open(QIODevice::WriteOnly);
|
||||||
|
file.write(data);
|
||||||
|
file.close();
|
||||||
|
if (m_enabled) {
|
||||||
|
QTimer::singleShot(0, this, [this]() { start(); });
|
||||||
|
}
|
||||||
|
}
|
43
DataCollection.h
Normal file
43
DataCollection.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#ifndef DATACOLLECTION_H
|
||||||
|
#define DATACOLLECTION_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QQmlEngine>
|
||||||
|
|
||||||
|
class QNetworkAccessManager;
|
||||||
|
|
||||||
|
class DataCollection : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
QML_UNCREATABLE("Only created in C++...")
|
||||||
|
|
||||||
|
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
|
||||||
|
Q_PROPERTY(bool enabled READ enabled NOTIFY enabledChanged)
|
||||||
|
public:
|
||||||
|
explicit DataCollection(QObject *parent = nullptr);
|
||||||
|
Q_INVOKABLE void start(const QString &address);
|
||||||
|
Q_INVOKABLE void stop();
|
||||||
|
|
||||||
|
QString path() const;
|
||||||
|
void setPath(const QString &path);
|
||||||
|
|
||||||
|
bool enabled() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void pathChanged();
|
||||||
|
void enabledChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void start();
|
||||||
|
void onCaptureFinished();
|
||||||
|
void onDataGetFinished();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QNetworkAccessManager *m_manager = nullptr;
|
||||||
|
bool m_enabled = false;
|
||||||
|
QString m_address;
|
||||||
|
QString m_path;
|
||||||
|
QString m_filename;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DATACOLLECTION_H
|
@ -2,6 +2,7 @@
|
|||||||
#include "BoostLog.h"
|
#include "BoostLog.h"
|
||||||
#include "StringUtility.h"
|
#include "StringUtility.h"
|
||||||
#include <QPointF>
|
#include <QPointF>
|
||||||
|
#include <QTimer>
|
||||||
#include <WinSock2.h>
|
#include <WinSock2.h>
|
||||||
#include <boost/json/object.hpp>
|
#include <boost/json/object.hpp>
|
||||||
#include <boost/json/parse.hpp>
|
#include <boost/json/parse.hpp>
|
||||||
@ -13,8 +14,25 @@
|
|||||||
DeviceConnection::DeviceConnection(QObject *parent) : QObject{parent} {
|
DeviceConnection::DeviceConnection(QObject *parent) : QObject{parent} {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceConnection::connect(const QString &address) {
|
DeviceConnection::Infomation DeviceConnection::infomation() const {
|
||||||
|
return m_infomation;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceConnection::isConnected() const {
|
||||||
|
bool ret = false;
|
||||||
|
if (m_commandSocket != nullptr) {
|
||||||
|
// LOG(info) << "DeviceConnection::isConnected " << m_commandSocket->isValid();
|
||||||
|
ret = m_commandSocket->isValid() && (m_commandSocket->state() == QTcpSocket::ConnectedState);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceConnection::connect(const Infomation &infomation) {
|
||||||
|
m_infomation = infomation;
|
||||||
m_commandSocket = new QTcpSocket(this);
|
m_commandSocket = new QTcpSocket(this);
|
||||||
|
QObject::connect(m_commandSocket, &QTcpSocket::disconnected, this, &DeviceConnection::disconnected);
|
||||||
|
QObject::connect(m_commandSocket, &QTcpSocket::errorOccurred, this, &DeviceConnection::onErrorOccurred);
|
||||||
|
|
||||||
m_h264Socket = new QTcpSocket(this);
|
m_h264Socket = new QTcpSocket(this);
|
||||||
|
|
||||||
QObject::connect(m_commandSocket, &QTcpSocket::connected, this, &DeviceConnection::onConnected);
|
QObject::connect(m_commandSocket, &QTcpSocket::connected, this, &DeviceConnection::onConnected);
|
||||||
@ -22,14 +40,22 @@ void DeviceConnection::connect(const QString &address) {
|
|||||||
|
|
||||||
QObject::connect(m_h264Socket, &QTcpSocket::readyRead, this, &DeviceConnection::onH264ReadyRead);
|
QObject::connect(m_h264Socket, &QTcpSocket::readyRead, this, &DeviceConnection::onH264ReadyRead);
|
||||||
QObject::connect(m_commandSocket, &QTcpSocket::readyRead, this, &DeviceConnection::onCommandReadyRead);
|
QObject::connect(m_commandSocket, &QTcpSocket::readyRead, this, &DeviceConnection::onCommandReadyRead);
|
||||||
|
LOG(info) << "connect to " << infomation.ip.toStdString();
|
||||||
m_commandSocket->connectToHost(address, 8000);
|
m_commandSocket->connectToHost(infomation.ip, 8000);
|
||||||
m_h264Socket->connectToHost(address, 8000);
|
m_h264Socket->connectToHost(infomation.ip, 8000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceConnection::start() {
|
DeviceConnection::Area DeviceConnection::area() const {
|
||||||
|
return m_area;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkInfomation DeviceConnection::networkInfomation() const {
|
||||||
|
return m_networkInfomation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceConnection::setLiveStreamEnabled(bool enabled) {
|
||||||
boost::json::object request;
|
boost::json::object request;
|
||||||
request["func"] = "openlivestream_setdata";
|
request["func"] = enabled ? "openlivestream_setdata" : "closelivestream_setdata";
|
||||||
request["deviceid"] = "0";
|
request["deviceid"] = "0";
|
||||||
|
|
||||||
boost::json::object data;
|
boost::json::object data;
|
||||||
@ -236,11 +262,13 @@ void DeviceConnection::updateNetworkInfomation(bool dhcp, const QString &ip, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DeviceConnection::requestOta(const QString &file) {
|
void DeviceConnection::requestOta(const QString &file) {
|
||||||
LOG(info) << file.toStdString();
|
m_otaProgress = 0;
|
||||||
|
emit otaProgressChanged(true, m_otaProgress, "正在向设备发起OTA请求......");
|
||||||
|
|
||||||
auto task = [this, file]() {
|
auto task = [this, file]() {
|
||||||
std::ifstream ifs(Amass::StringUtility::UTF8ToGBK(file.toStdString()), std::ifstream::binary);
|
std::ifstream ifs(Amass::StringUtility::UTF8ToGBK(file.toStdString()), std::ifstream::binary);
|
||||||
m_uploadBuffer = std::vector<uint8_t>((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
m_uploadBuffer = std::vector<uint8_t>((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
||||||
|
m_sendedSize = 0;
|
||||||
|
|
||||||
unsigned char md5[16];
|
unsigned char md5[16];
|
||||||
mbedtls_md5_context context;
|
mbedtls_md5_context context;
|
||||||
@ -259,13 +287,13 @@ void DeviceConnection::requestOta(const QString &file) {
|
|||||||
request["func"] = "a22devicefirmware_setdata";
|
request["func"] = "a22devicefirmware_setdata";
|
||||||
request["deviceid"] = "0";
|
request["deviceid"] = "0";
|
||||||
boost::json::object data;
|
boost::json::object data;
|
||||||
data["target_linux04_firmware"] = "RD_T009_V21R003B001";
|
data["target_linux04_firmware"] = "RD_T009_V21R003B002";
|
||||||
data["datasize"] = std::filesystem::file_size(file.toStdString());
|
data["datasize"] = std::filesystem::file_size(file.toStdString());
|
||||||
data["md5"] = oss.str();
|
data["md5"] = oss.str();
|
||||||
request["data"] = std::move(data);
|
request["data"] = std::move(data);
|
||||||
auto text = boost::json::serialize(request);
|
auto text = boost::json::serialize(request);
|
||||||
m_commandSocket->write(text.data(), text.size());
|
m_commandSocket->write(text.data(), text.size());
|
||||||
LOG(info) << "requestOta: " << text;
|
LOG(info) << "requestOta: " << text << ": " << text.size();
|
||||||
};
|
};
|
||||||
if (m_requests.empty()) {
|
if (m_requests.empty()) {
|
||||||
task();
|
task();
|
||||||
@ -273,6 +301,48 @@ void DeviceConnection::requestOta(const QString &file) {
|
|||||||
m_requests.push(task);
|
m_requests.push(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeviceConnection::transferBinContent() {
|
||||||
|
constexpr int SliceSize = 1024;
|
||||||
|
constexpr int WaitMd5CheckTime = 3000; // ms
|
||||||
|
if (m_sendedSize >= m_uploadBuffer.size()) return;
|
||||||
|
|
||||||
|
char buffer[1 + sizeof(int32_t) + 1024];
|
||||||
|
int sendSize = SliceSize;
|
||||||
|
if ((m_sendedSize + SliceSize) > m_uploadBuffer.size()) {
|
||||||
|
sendSize = m_uploadBuffer.size() - m_sendedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buffer + 1 + sizeof(int32_t), m_uploadBuffer.data() + m_sendedSize, sendSize);
|
||||||
|
buffer[0] = ':';
|
||||||
|
auto contentSize = reinterpret_cast<int32_t *>(&buffer[1]);
|
||||||
|
*contentSize = htonl(sendSize);
|
||||||
|
|
||||||
|
m_commandSocket->write(buffer, sendSize + 1 + sizeof(uint32_t));
|
||||||
|
m_sendedSize += sendSize;
|
||||||
|
|
||||||
|
auto fileProgress = static_cast<float>(m_sendedSize) / m_uploadBuffer.size();
|
||||||
|
m_otaProgress = 2 + 95 * fileProgress;
|
||||||
|
emit otaProgressChanged(true, m_otaProgress, "向设备发送OTA升级文件......");
|
||||||
|
|
||||||
|
if (m_sendedSize < m_uploadBuffer.size()) {
|
||||||
|
QTimer::singleShot(0, this, &DeviceConnection::transferBinContent);
|
||||||
|
} else if (m_sendedSize >= m_uploadBuffer.size()) {
|
||||||
|
LOG(info) << "transfer ota file finished, wait " << WaitMd5CheckTime
|
||||||
|
<< " ms for send check, total sended size: " << m_sendedSize;
|
||||||
|
QTimer::singleShot(WaitMd5CheckTime, this, [this]() {
|
||||||
|
boost::json::object request;
|
||||||
|
request["func"] = "a22devicefirmware_setdata";
|
||||||
|
request["deviceid"] = "0";
|
||||||
|
boost::json::object data;
|
||||||
|
data["target_linux04_firmware"] = "RD_T009_V21R003B001";
|
||||||
|
request["data"] = std::move(data);
|
||||||
|
auto text = boost::json::serialize(request);
|
||||||
|
m_commandSocket->write(text.data(), text.size());
|
||||||
|
LOG(info) << "request md5 check result: " << text;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DeviceConnection::handleCommand(const std::string_view &replyText) {
|
void DeviceConnection::handleCommand(const std::string_view &replyText) {
|
||||||
boost::system::error_code error;
|
boost::system::error_code error;
|
||||||
auto replyValue = boost::json::parse(replyText, error);
|
auto replyValue = boost::json::parse(replyText, error);
|
||||||
@ -300,7 +370,9 @@ void DeviceConnection::handleCommand(const std::string_view &replyText) {
|
|||||||
} else if (value == "2") {
|
} else if (value == "2") {
|
||||||
way = Quadrangle;
|
way = Quadrangle;
|
||||||
}
|
}
|
||||||
emit currentOpenDoorAreaChanged(way, points);
|
m_area.openDoorAreaWay = way;
|
||||||
|
m_area.openDoorArea = points;
|
||||||
|
emit openDoorAreaChanged(way, points);
|
||||||
} else if (function == "a03opendoor4_getdata") {
|
} else if (function == "a03opendoor4_getdata") {
|
||||||
auto &data = reply.at("data").as_object();
|
auto &data = reply.at("data").as_object();
|
||||||
auto &value = data.at("value").as_string();
|
auto &value = data.at("value").as_string();
|
||||||
@ -313,7 +385,9 @@ void DeviceConnection::handleCommand(const std::string_view &replyText) {
|
|||||||
point.setY(obj.at("y").as_double());
|
point.setY(obj.at("y").as_double());
|
||||||
points.push_back(point);
|
points.push_back(point);
|
||||||
}
|
}
|
||||||
emit currentShieldedAreaChanged(value == "1", points);
|
m_area.shieldedAreaEnabled = value == "1";
|
||||||
|
m_area.shieldedArea = points;
|
||||||
|
emit shieldedAreaChanged(value == "1", points);
|
||||||
} else if (function == "a03opendoor5_getdata") {
|
} else if (function == "a03opendoor5_getdata") {
|
||||||
auto &data = reply.at("data").as_object();
|
auto &data = reply.at("data").as_object();
|
||||||
auto &value = data.at("value").as_string();
|
auto &value = data.at("value").as_string();
|
||||||
@ -326,15 +400,47 @@ void DeviceConnection::handleCommand(const std::string_view &replyText) {
|
|||||||
point.setY(obj.at("y").as_double());
|
point.setY(obj.at("y").as_double());
|
||||||
points.push_back(point);
|
points.push_back(point);
|
||||||
}
|
}
|
||||||
emit currentAntiClipAreaChanged(value == "1", points);
|
m_area.antiClipAreaEnabled = value == "1";
|
||||||
|
m_area.antiClipArea = points;
|
||||||
|
emit antiClipAreaChanged(value == "1", points);
|
||||||
} else if (function == "netconfig_getdata") {
|
} else if (function == "netconfig_getdata") {
|
||||||
auto &data = reply.at("data").as_object();
|
auto &data = reply.at("data").as_object();
|
||||||
NetworkInfomation info;
|
m_networkInfomation.dhcp = data.at("type").as_string() == "dhcp";
|
||||||
info.dhcp = data.at("type").as_string() == "dhcp";
|
m_networkInfomation.ip = data.at("ip").as_string().c_str();
|
||||||
info.ip = data.at("ip").as_string().c_str();
|
m_networkInfomation.gateway = data.at("gateway").as_string().c_str();
|
||||||
info.gateway = data.at("gateway").as_string().c_str();
|
m_networkInfomation.netmask = data.at("netmask").as_string().c_str();
|
||||||
info.netmask = data.at("netmask").as_string().c_str();
|
emit networkInfomationChanged(m_networkInfomation);
|
||||||
emit currentNetworkInfomationChanged(info);
|
} else if (function == "a03opendoor5_setdata") {
|
||||||
|
requestAntiClipArea();
|
||||||
|
} else if (function == "a03opendoor4_setdata") {
|
||||||
|
requestShieldedArea();
|
||||||
|
} else if (function == "a03opendoor1_setdata") {
|
||||||
|
requestOpenDoorArea();
|
||||||
|
} else if (function == "a22devicefirmware_setdata") {
|
||||||
|
LOG(warning) << "ota reply: " << replyText;
|
||||||
|
auto &data = reply.at("data").as_object();
|
||||||
|
auto &value = data.at("value").as_string();
|
||||||
|
if (value == "1") {
|
||||||
|
m_otaProgress = 1;
|
||||||
|
emit otaProgressChanged(true, m_otaProgress, "设备已进入OTA升级状态......");
|
||||||
|
QTimer::singleShot(0, this, [this]() { transferBinContent(); });
|
||||||
|
} else if (value == "2") {
|
||||||
|
LOG(info) << "md5 check finished";
|
||||||
|
m_otaProgress = 98;
|
||||||
|
emit otaProgressChanged(true, m_otaProgress, "设备正在升级中,请稍后......");
|
||||||
|
QTimer::singleShot(0, this, [this]() {
|
||||||
|
m_commandSocket->close();
|
||||||
|
m_h264Socket->close();
|
||||||
|
});
|
||||||
|
QTimer::singleShot(25000, this, [this]() {
|
||||||
|
LOG(info) << "try connect after ota.";
|
||||||
|
m_commandSocket->connectToHost(m_infomation.ip, 8000);
|
||||||
|
m_h264Socket->connectToHost(m_infomation.ip, 8000);
|
||||||
|
m_needReconnect = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(warning) << "unknown reply: " << replyText;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,8 +452,16 @@ void DeviceConnection::onConnected() {
|
|||||||
requestShieldedArea();
|
requestShieldedArea();
|
||||||
requestAntiClipArea();
|
requestAntiClipArea();
|
||||||
requestNetworkInfomation();
|
requestNetworkInfomation();
|
||||||
|
emit connected();
|
||||||
|
// m_timerId = startTimer(2500);
|
||||||
|
if (m_otaProgress > 0) {
|
||||||
|
m_otaProgress = 100;
|
||||||
|
emit otaProgressChanged(true, m_otaProgress, "设备升级成功!");
|
||||||
|
}
|
||||||
} else if (socket == m_h264Socket) {
|
} else if (socket == m_h264Socket) {
|
||||||
start();
|
if (m_needReconnect) {
|
||||||
|
setLiveStreamEnabled(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,12 +497,31 @@ void DeviceConnection::onCommandReadyRead() {
|
|||||||
while (!m_commandBuffer.isEmpty()) {
|
while (!m_commandBuffer.isEmpty()) {
|
||||||
auto packageSize = ntohl(*reinterpret_cast<uint32_t *>(m_commandBuffer.data()));
|
auto packageSize = ntohl(*reinterpret_cast<uint32_t *>(m_commandBuffer.data()));
|
||||||
if (m_commandBuffer.size() < (packageSize + sizeof(uint32_t))) break;
|
if (m_commandBuffer.size() < (packageSize + sizeof(uint32_t))) break;
|
||||||
LOG(info) << "h264 reply: " << m_commandBuffer.data() + sizeof(uint32_t);
|
|
||||||
handleCommand(std::string_view(m_commandBuffer.data() + sizeof(uint32_t), packageSize));
|
handleCommand(std::string_view(m_commandBuffer.data() + sizeof(uint32_t), packageSize));
|
||||||
m_commandBuffer.remove(0, packageSize + sizeof(uint32_t));
|
m_commandBuffer.remove(0, packageSize + sizeof(uint32_t));
|
||||||
|
|
||||||
|
if (!m_requests.empty()) {
|
||||||
m_requests.pop();
|
m_requests.pop();
|
||||||
if (!m_requests.empty()) {
|
if (!m_requests.empty()) {
|
||||||
m_requests.front()();
|
m_requests.front()();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceConnection::onErrorOccurred(QAbstractSocket::SocketError socketError) {
|
||||||
|
auto socket = dynamic_cast<QTcpSocket *>(sender());
|
||||||
|
qDebug() << "DeviceConnection::onErrorOccurred" << socketError;
|
||||||
|
if (m_needReconnect) {
|
||||||
|
if (socket->state() == QTcpSocket::UnconnectedState) {
|
||||||
|
LOG(info) << "try reconnect after ota.";
|
||||||
|
socket->connectToHost(m_infomation.ip, 8000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceConnection::timerEvent(QTimerEvent *event) {
|
||||||
|
if (isConnected()) {
|
||||||
|
requestOpenDoorArea();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,39 @@ public:
|
|||||||
FullArea,
|
FullArea,
|
||||||
Quadrangle, // 四边形
|
Quadrangle, // 四边形
|
||||||
};
|
};
|
||||||
|
class Infomation {
|
||||||
|
public:
|
||||||
|
QString deviceId;
|
||||||
|
QString softwareVersion;
|
||||||
|
QString firmwareVersion;
|
||||||
|
QString ip;
|
||||||
|
};
|
||||||
Q_ENUM(AreaWay)
|
Q_ENUM(AreaWay)
|
||||||
|
|
||||||
|
class Area {
|
||||||
|
public:
|
||||||
|
QList<QPointF> openDoorArea;
|
||||||
|
AreaWay openDoorAreaWay;
|
||||||
|
|
||||||
|
QList<QPointF> shieldedArea;
|
||||||
|
bool shieldedAreaEnabled;
|
||||||
|
|
||||||
|
QList<QPointF> antiClipArea;
|
||||||
|
bool antiClipAreaEnabled;
|
||||||
|
};
|
||||||
|
|
||||||
using H264FrameCallback = std::function<void(const char *data, uint32_t size)>;
|
using H264FrameCallback = std::function<void(const char *data, uint32_t size)>;
|
||||||
explicit DeviceConnection(QObject *parent = nullptr);
|
explicit DeviceConnection(QObject *parent = nullptr);
|
||||||
|
Infomation infomation() const;
|
||||||
|
bool isConnected() const;
|
||||||
void setH264FrameCallback(H264FrameCallback &&callback);
|
void setH264FrameCallback(H264FrameCallback &&callback);
|
||||||
void connect(const QString &address);
|
void connect(const Infomation &infomation);
|
||||||
void start();
|
|
||||||
|
void setLiveStreamEnabled(bool enabled);
|
||||||
|
|
||||||
|
NetworkInfomation networkInfomation() const;
|
||||||
|
Area area() const;
|
||||||
|
|
||||||
void requestOpenDoorArea();
|
void requestOpenDoorArea();
|
||||||
void updateOpenDoorAreaPoints(AreaWay way, const QList<QPointF> &points);
|
void updateOpenDoorAreaPoints(AreaWay way, const QList<QPointF> &points);
|
||||||
void requestShieldedArea();
|
void requestShieldedArea();
|
||||||
@ -41,13 +68,25 @@ public:
|
|||||||
void requestNetworkInfomation();
|
void requestNetworkInfomation();
|
||||||
void updateNetworkInfomation(bool dhcp, const QString &ip, const QString &netmask, const QString &gateway);
|
void updateNetworkInfomation(bool dhcp, const QString &ip, const QString &netmask, const QString &gateway);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 对设备升级OTA,主要有几个步骤
|
||||||
|
* 1. 对设备发起OTA请求,等待设备回复 1
|
||||||
|
* 2. 发送二进制文件至设备 2-97
|
||||||
|
* 3. 对设备发起包检查结果,等待设备回复 98
|
||||||
|
* 4. 设备会重启,一直尝试连接设置,直至连接成功 99
|
||||||
|
*
|
||||||
|
* @param file
|
||||||
|
*/
|
||||||
void requestOta(const QString &file);
|
void requestOta(const QString &file);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void currentOpenDoorAreaChanged(AreaWay way, const QList<QPointF> &points);
|
void connected();
|
||||||
void currentShieldedAreaChanged(bool enabled, const QList<QPointF> &points);
|
void disconnected();
|
||||||
void currentAntiClipAreaChanged(bool enabled, const QList<QPointF> &points);
|
void openDoorAreaChanged(AreaWay way, const QList<QPointF> &points);
|
||||||
void currentNetworkInfomationChanged(const NetworkInfomation &info);
|
void shieldedAreaChanged(bool enabled, const QList<QPointF> &points);
|
||||||
|
void antiClipAreaChanged(bool enabled, const QList<QPointF> &points);
|
||||||
|
void networkInfomationChanged(const NetworkInfomation &info);
|
||||||
|
void otaProgressChanged(bool status, int progress, const QString &message);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void onConnected();
|
void onConnected();
|
||||||
@ -55,8 +94,11 @@ protected:
|
|||||||
void onCommandReadyRead();
|
void onCommandReadyRead();
|
||||||
void handleCommand(const std::string_view &replyText);
|
void handleCommand(const std::string_view &replyText);
|
||||||
void onErrorOccurred(QAbstractSocket::SocketError socketError);
|
void onErrorOccurred(QAbstractSocket::SocketError socketError);
|
||||||
|
void timerEvent(QTimerEvent *event) final;
|
||||||
|
void transferBinContent();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Infomation m_infomation;
|
||||||
QTcpSocket *m_commandSocket = nullptr;
|
QTcpSocket *m_commandSocket = nullptr;
|
||||||
|
|
||||||
QTcpSocket *m_h264Socket = nullptr;
|
QTcpSocket *m_h264Socket = nullptr;
|
||||||
@ -64,9 +106,17 @@ private:
|
|||||||
|
|
||||||
QByteArray m_commandBuffer;
|
QByteArray m_commandBuffer;
|
||||||
QByteArray m_h264Buffer;
|
QByteArray m_h264Buffer;
|
||||||
|
|
||||||
|
int m_otaProgress = 0;
|
||||||
|
bool m_needReconnect = false;
|
||||||
std::vector<uint8_t> m_uploadBuffer;
|
std::vector<uint8_t> m_uploadBuffer;
|
||||||
|
int m_sendedSize = 0;
|
||||||
|
|
||||||
H264FrameCallback m_frameCallback;
|
H264FrameCallback m_frameCallback;
|
||||||
std::queue<std::function<void()>> m_requests;
|
std::queue<std::function<void()>> m_requests;
|
||||||
|
int m_timerId = -1;
|
||||||
|
Area m_area;
|
||||||
|
NetworkInfomation m_networkInfomation;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DEVICECONNECTION_H
|
#endif // DEVICECONNECTION_H
|
||||||
|
@ -73,9 +73,6 @@ void DeviceListModel::startSearchDevice() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
for (auto &device : m_devices) {
|
|
||||||
device->deleteLater();
|
|
||||||
}
|
|
||||||
m_devices.clear();
|
m_devices.clear();
|
||||||
endResetModel();
|
endResetModel();
|
||||||
auto interfaces = QNetworkInterface::allInterfaces();
|
auto interfaces = QNetworkInterface::allInterfaces();
|
||||||
|
@ -31,7 +31,7 @@ public:
|
|||||||
QHash<int, QByteArray> roleNames() const final;
|
QHash<int, QByteArray> roleNames() const final;
|
||||||
Q_INVOKABLE QVariantMap get(int index) const;
|
Q_INVOKABLE QVariantMap get(int index) const;
|
||||||
std::shared_ptr<DeviceConnection> device(int index);
|
std::shared_ptr<DeviceConnection> device(int index);
|
||||||
Q_INVOKABLE void startSearchDevice();
|
void startSearchDevice();
|
||||||
bool isSearching() const;
|
bool isSearching() const;
|
||||||
float searchProgress() const;
|
float searchProgress() const;
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@ VideoFrameProvider::VideoFrameProvider()
|
|||||||
|
|
||||||
QImage VideoFrameProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize) {
|
QImage VideoFrameProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize) {
|
||||||
Q_UNUSED(id);
|
Q_UNUSED(id);
|
||||||
|
if (id == "black") {
|
||||||
|
m_image.fill(Qt::black);
|
||||||
|
}
|
||||||
|
|
||||||
if (size) *size = m_image.size();
|
if (size) *size = m_image.size();
|
||||||
|
|
||||||
|
3
main.cpp
3
main.cpp
@ -3,6 +3,7 @@
|
|||||||
#include "Configuration.h"
|
#include "Configuration.h"
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
|
#include <QQuickStyle>
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
using namespace Amass;
|
using namespace Amass;
|
||||||
@ -12,5 +13,7 @@ int main(int argc, char *argv[]) {
|
|||||||
LOG(info) << "Program version: " << APP_VERSION << std::endl;
|
LOG(info) << "Program version: " << APP_VERSION << std::endl;
|
||||||
|
|
||||||
auto app = Singleton<Application>::instance<Construct>(argc, argv);
|
auto app = Singleton<Application>::instance<Construct>(argc, argv);
|
||||||
|
QQuickStyle::setStyle("Basic");
|
||||||
|
|
||||||
return app->exec();
|
return app->exec();
|
||||||
}
|
}
|
||||||
|
6
qml/DataCollectionPopup.qml
Normal file
6
qml/DataCollectionPopup.qml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
Popup {
|
||||||
|
|
||||||
|
}
|
@ -5,6 +5,7 @@ import AntiClipSettings
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
property alias enabled: shieldedRow.enabled
|
||||||
property int dargWidth: 12
|
property int dargWidth: 12
|
||||||
property color openDoorAreaColor: "green"
|
property color openDoorAreaColor: "green"
|
||||||
property var openDoorAreaPoints: []
|
property var openDoorAreaPoints: []
|
||||||
@ -29,13 +30,16 @@ Item {
|
|||||||
property real aspectRatio: 16 / 9
|
property real aspectRatio: 16 / 9
|
||||||
width: Math.min(parent.width, parent.height * aspectRatio)
|
width: Math.min(parent.width, parent.height * aspectRatio)
|
||||||
height: width / aspectRatio
|
height: width / aspectRatio
|
||||||
|
enabled: root.enabled
|
||||||
|
|
||||||
Canvas {
|
Canvas {
|
||||||
id: canvas
|
id: canvas
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onPaint: {
|
onPaint: {
|
||||||
|
|
||||||
var ctx = canvas.getContext("2d")
|
var ctx = canvas.getContext("2d")
|
||||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||||
|
if(!root.enabled)return
|
||||||
if(openDoorAreaWay == DeviceConnection.FullArea){
|
if(openDoorAreaWay == DeviceConnection.FullArea){
|
||||||
ctx.strokeStyle = openDoorAreaColor
|
ctx.strokeStyle = openDoorAreaColor
|
||||||
ctx.lineWidth = 8
|
ctx.lineWidth = 8
|
||||||
@ -100,7 +104,7 @@ Item {
|
|||||||
delegate: Rectangle {
|
delegate: Rectangle {
|
||||||
width: dargWidth
|
width: dargWidth
|
||||||
height: dargWidth
|
height: dargWidth
|
||||||
visible: openDoorAreaWay>=DeviceConnection.Quadrangle
|
visible: root.enabled &&(openDoorAreaWay>=DeviceConnection.Quadrangle)
|
||||||
color: openDoorAreaColor
|
color: openDoorAreaColor
|
||||||
x: scaledPoint(modelData, canvas.width,
|
x: scaledPoint(modelData, canvas.width,
|
||||||
canvas.height).x - width / 2
|
canvas.height).x - width / 2
|
||||||
@ -116,7 +120,7 @@ Item {
|
|||||||
delegate: Rectangle {
|
delegate: Rectangle {
|
||||||
width: dargWidth
|
width: dargWidth
|
||||||
height: dargWidth
|
height: dargWidth
|
||||||
visible: shieldedAreaEnabled
|
visible: root.enabled && shieldedAreaEnabled
|
||||||
color: shieldedAreaColor
|
color: shieldedAreaColor
|
||||||
x: scaledPoint(modelData, canvas.width,
|
x: scaledPoint(modelData, canvas.width,
|
||||||
canvas.height).x - width / 2
|
canvas.height).x - width / 2
|
||||||
@ -130,7 +134,7 @@ Item {
|
|||||||
visible: antiClipAreaEnabled
|
visible: antiClipAreaEnabled
|
||||||
model: antiClipAreaPoints
|
model: antiClipAreaPoints
|
||||||
delegate: Rectangle {
|
delegate: Rectangle {
|
||||||
visible: antiClipAreaEnabled
|
visible: root.enabled && antiClipAreaEnabled
|
||||||
width: dargWidth
|
width: dargWidth
|
||||||
height: dargWidth
|
height: dargWidth
|
||||||
color: antiClipAreaColor
|
color: antiClipAreaColor
|
||||||
@ -143,6 +147,7 @@ Item {
|
|||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
enabled: root.enabled
|
||||||
property int draggedOpenDoorAreaPointIndex: -1
|
property int draggedOpenDoorAreaPointIndex: -1
|
||||||
property int draggedShieldedAreaPointIndex: -1
|
property int draggedShieldedAreaPointIndex: -1
|
||||||
property int draggedAntiAreaPointIndex: -1
|
property int draggedAntiAreaPointIndex: -1
|
||||||
@ -242,6 +247,7 @@ Item {
|
|||||||
spacing: 10
|
spacing: 10
|
||||||
Text {text: qsTr("开门区域: ")}
|
Text {text: qsTr("开门区域: ")}
|
||||||
Row {
|
Row {
|
||||||
|
enabled: root.enabled
|
||||||
RadioButton {
|
RadioButton {
|
||||||
text: "关闭"
|
text: "关闭"
|
||||||
checked: App.currentOpenDoorAreaWay ==DeviceConnection.Diabled
|
checked: App.currentOpenDoorAreaWay ==DeviceConnection.Diabled
|
||||||
@ -268,6 +274,7 @@ Item {
|
|||||||
|
|
||||||
Text {text: qsTr("防夹区域: ")}
|
Text {text: qsTr("防夹区域: ")}
|
||||||
Row {
|
Row {
|
||||||
|
enabled: root.enabled
|
||||||
RadioButton {
|
RadioButton {
|
||||||
text: "关闭"
|
text: "关闭"
|
||||||
checked: !App.currentAntiClipAreaEnabled
|
checked: !App.currentAntiClipAreaEnabled
|
||||||
@ -321,6 +328,13 @@ Item {
|
|||||||
return Qt.point(x, y)
|
return Qt.point(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onEnabledChanged: {
|
||||||
|
canvas.requestPaint()
|
||||||
|
if(!enabled){
|
||||||
|
image.source = "image://videoframe/black"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: App
|
target: App
|
||||||
function onNewVideoFrame() {
|
function onNewVideoFrame() {
|
12
qml/IconButton.qml
Normal file
12
qml/IconButton.qml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import QtQuick 2.12
|
||||||
|
import QtQuick.Controls 2.12
|
||||||
|
|
||||||
|
Button {
|
||||||
|
property alias source: image.source
|
||||||
|
background: Item {
|
||||||
|
Image {
|
||||||
|
id:image
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,11 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Dialogs
|
||||||
import AntiClipSettings
|
import AntiClipSettings
|
||||||
|
|
||||||
ApplicationWindow {
|
ApplicationWindow {
|
||||||
|
id: window
|
||||||
width: 1000
|
width: 1000
|
||||||
height: 640
|
height: 640
|
||||||
visible: true
|
visible: true
|
||||||
@ -16,23 +18,19 @@ ApplicationWindow {
|
|||||||
text: "搜索设备"
|
text: "搜索设备"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
deviceList.currentIndex = -1
|
deviceList.currentIndex = -1
|
||||||
App.devices.startSearchDevice()
|
App.startSearchDevice()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
text: `设备总数: ${deviceList.count}`
|
text: `设备总数: ${deviceList.count}`
|
||||||
}
|
}
|
||||||
Row {
|
Text {
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
Text {
|
Layout.preferredWidth: 400
|
||||||
text: qsTr("当前设备版本号: ")
|
text: deviceList.currentIndex
|
||||||
|
>= 0 ? `当前设备版本号: ${App.devices.get(
|
||||||
|
deviceList.currentIndex).softwareVersion}` : ""
|
||||||
}
|
}
|
||||||
Text {
|
|
||||||
id: deviceVersion
|
|
||||||
text: qsTr("RD_T009_V02R001B001")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +60,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
color: onlineStatus ? "green":"black"
|
color: onlineStatus ? "green" : "black"
|
||||||
width: 10
|
width: 10
|
||||||
height: 10
|
height: 10
|
||||||
radius: 5
|
radius: 5
|
||||||
@ -72,7 +70,6 @@ ApplicationWindow {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
deviceList.currentIndex = index
|
deviceList.currentIndex = index
|
||||||
|
|
||||||
}
|
}
|
||||||
onDoubleClicked: {
|
onDoubleClicked: {
|
||||||
networkPopup.open()
|
networkPopup.open()
|
||||||
@ -80,7 +77,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onCurrentIndexChanged: {
|
onCurrentIndexChanged: {
|
||||||
deviceVersion.text = App.devices.get(deviceList.currentIndex).softwareVersion;
|
// deviceVersion.text = App.devices.get(deviceList.currentIndex).softwareVersion;
|
||||||
App.connectToDevice(deviceList.currentIndex)
|
App.connectToDevice(deviceList.currentIndex)
|
||||||
}
|
}
|
||||||
ProgressBar {
|
ProgressBar {
|
||||||
@ -100,6 +97,7 @@ ApplicationWindow {
|
|||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.left: deviceList.right
|
anchors.left: deviceList.right
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
enabled: deviceList.currentIndex>=0
|
||||||
openDoorAreaWay: App.currentOpenDoorAreaWay
|
openDoorAreaWay: App.currentOpenDoorAreaWay
|
||||||
openDoorAreaPoints: App.currentOpenDoorAreaPoints
|
openDoorAreaPoints: App.currentOpenDoorAreaPoints
|
||||||
shieldedAreaEnabled: App.currentShieldedAreaEnabled
|
shieldedAreaEnabled: App.currentShieldedAreaEnabled
|
||||||
@ -119,18 +117,61 @@ ApplicationWindow {
|
|||||||
id: otaPopup
|
id: otaPopup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FolderDialog {
|
||||||
|
id: folderDialog
|
||||||
|
onAccepted: {
|
||||||
|
App.collector.path = folderDialog.selectedFolder
|
||||||
|
App.collector.start(App.devices.get(deviceList.currentIndex).ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
footer: RowLayout {
|
footer: RowLayout {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
Item {}
|
Item {}
|
||||||
Button {
|
Button {
|
||||||
text: "数据采集"
|
text: App.collector.enabled ? "停止采集" : "数据采集"
|
||||||
|
onClicked: {
|
||||||
|
if (App.collector.enabled) {
|
||||||
|
App.collector.stop()
|
||||||
|
} else {
|
||||||
|
if (deviceList.currentIndex < 0) {
|
||||||
|
showMessageDialog(2, "数据采集", "请先选择设备")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (App.collector.path.length <= 0) {
|
||||||
|
folderDialog.open()
|
||||||
|
} else {
|
||||||
|
App.collector.start(App.devices.get(
|
||||||
|
deviceList.currentIndex).ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Item {}
|
Item {}
|
||||||
Button {
|
Button {
|
||||||
text: "升级"
|
text: "升级"
|
||||||
onClicked: otaPopup.open()
|
onClicked: {
|
||||||
|
if (deviceList.currentIndex < 0) {
|
||||||
|
showMessageDialog(2, "OTA升级", "请选选择设备")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
otaPopup.open()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Item {}
|
Item {}
|
||||||
spacing: (parent.width - (2 * 100)) / 3
|
spacing: (parent.width - (2 * 100)) / 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showMessageDialog(type, title, message) {
|
||||||
|
let component = Qt.createComponent("MessageDialog.qml")
|
||||||
|
if (component.status === Component.Ready) {
|
||||||
|
let dialog = component.createObject(window, {
|
||||||
|
"type": type,
|
||||||
|
"height": 200,
|
||||||
|
"titleText": title,
|
||||||
|
"text": message
|
||||||
|
})
|
||||||
|
dialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
108
qml/MessageDialog.qml
Normal file
108
qml/MessageDialog.qml
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: control
|
||||||
|
width: 320
|
||||||
|
parent: Overlay.overlay
|
||||||
|
anchors.centerIn: Overlay.overlay
|
||||||
|
modal: true
|
||||||
|
property alias titleText: titleLabel.text
|
||||||
|
property alias text: textLabel.text
|
||||||
|
property alias textFontSize: textLabel.font.pixelSize
|
||||||
|
property int type: MessageDialog.Type.Successful
|
||||||
|
closePolicy: Popup.CloseOnEscap | Popup.NoAutoClose
|
||||||
|
background: Rectangle {
|
||||||
|
radius: 8
|
||||||
|
}
|
||||||
|
enum Type {
|
||||||
|
Ok,
|
||||||
|
Successful,
|
||||||
|
Warning,
|
||||||
|
Failed
|
||||||
|
}
|
||||||
|
IconButton {
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 7
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: 10
|
||||||
|
source: "../resources/popup_close.svg"
|
||||||
|
onClicked: control.close()
|
||||||
|
}
|
||||||
|
Image {
|
||||||
|
id: image
|
||||||
|
width: 18
|
||||||
|
height: 18
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 30
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: 40
|
||||||
|
source: "qrc:/qt/qml/AntiClipSettings/resources/successfull.svg"
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: titleLabel
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 60
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: 40
|
||||||
|
font.family: control.font.family
|
||||||
|
font.pixelSize: 16
|
||||||
|
color: "#0A1F44"
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: textLabel
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 60
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 40
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: 76
|
||||||
|
font.family: control.font.family
|
||||||
|
font.pixelSize: 14
|
||||||
|
color: "#53627C"
|
||||||
|
horizontalAlignment: Text.AlignLeft
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: cancelButton
|
||||||
|
width: 72
|
||||||
|
height: 26
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 15
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: 15
|
||||||
|
font.family: control.font.family
|
||||||
|
text: "关闭"
|
||||||
|
font.pixelSize: 14
|
||||||
|
contentItem: Text {
|
||||||
|
text: parent.text
|
||||||
|
font: parent.font
|
||||||
|
color: parent.down ? "#FFFFFF" : "#53627C"
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
border.color: "#E1E4E8"
|
||||||
|
border.width: 1
|
||||||
|
color: parent.down ? "#F25959" : "#FFFFFF"
|
||||||
|
radius: 2
|
||||||
|
}
|
||||||
|
onClicked: control.reject()
|
||||||
|
}
|
||||||
|
onTypeChanged: {
|
||||||
|
if (type === MessageDialog.Type.Successful || type === MessageDialog.Type.Ok) {
|
||||||
|
image.source = "qrc:/qt/qml/AntiClipSettings/resources/successfull.svg"
|
||||||
|
} else if (type === MessageDialog.Type.Warning) {
|
||||||
|
image.source = "qrc:/qt/qml/AntiClipSettings/resources/warning.svg"
|
||||||
|
} else if(type === MessageDialog.Type.Failed){
|
||||||
|
// image.source = "qrc:/AntiClipSettings/resources/prompt_delete.svg"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,8 +9,8 @@ Popup {
|
|||||||
id: root
|
id: root
|
||||||
parent: Overlay.overlay
|
parent: Overlay.overlay
|
||||||
anchors.centerIn: Overlay.overlay
|
anchors.centerIn: Overlay.overlay
|
||||||
width: 500
|
width: 540
|
||||||
height: 200
|
height: 260
|
||||||
modal: true
|
modal: true
|
||||||
focus: true
|
focus: true
|
||||||
closePolicy: Popup.CloseOnEscape
|
closePolicy: Popup.CloseOnEscape
|
||||||
@ -96,18 +96,18 @@ Popup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connections {
|
Connections {
|
||||||
// target: App
|
target: App
|
||||||
// function onUpdateFinished() {
|
function onCurrentDeviceOtaProgressChanged (status, progress, message) {
|
||||||
// otaMessage.text = "OTA升级完成"
|
progressBar.value = progress
|
||||||
// otaMessage.color = "green"
|
progressText.text = `${progress}%`
|
||||||
// }
|
if(progress>=100){
|
||||||
// function onOtaMessage(message) {
|
otaMessage.text = "OTA升级完成"
|
||||||
// otaMessage.text = message
|
otaMessage.color = "green"
|
||||||
// }
|
}else {
|
||||||
// function onOtaProgressChanged(progress) {
|
otaMessage.text = message
|
||||||
// progressBar.value = progress
|
}
|
||||||
// progressText.text = `${progress}%`
|
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
}
|
}
|
55
qml/StatusTip.qml
Normal file
55
qml/StatusTip.qml
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
Popup{
|
||||||
|
id: control
|
||||||
|
property alias text: textItem.text
|
||||||
|
property alias icon: image.source
|
||||||
|
property alias color: back.color
|
||||||
|
property string borderColor
|
||||||
|
x: (parent.width-200)/2
|
||||||
|
y: 40
|
||||||
|
width: 200
|
||||||
|
height: 32
|
||||||
|
font.pixelSize: 16
|
||||||
|
contentItem: Row{
|
||||||
|
leftPadding: 4
|
||||||
|
spacing: 9.6
|
||||||
|
Image {
|
||||||
|
id: image
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
id: textItem
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: control.text
|
||||||
|
font: control.font
|
||||||
|
color: "#666666"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
id:back
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "#EBF8ED"
|
||||||
|
radius: 3.2
|
||||||
|
border.width: 1
|
||||||
|
border.color: control.borderColor
|
||||||
|
layer.enabled: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: timer
|
||||||
|
repeat: false
|
||||||
|
onTriggered: control.visible=false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function show(text,timeout){
|
||||||
|
control.text = text
|
||||||
|
timer.interval = timeout
|
||||||
|
timer.restart();
|
||||||
|
control.visible=true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
15
resources/popup_close.svg
Normal file
15
resources/popup_close.svg
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="10px" height="10px" viewBox="0 0 10 10" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 53.2 (72643) - https://sketchapp.com -->
|
||||||
|
<title>Mask</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs>
|
||||||
|
<path d="M6.1785113,5 L8.92258898,7.74407768 C9.24802589,8.06951459 9.24802589,8.59715207 8.92258898,8.92258898 C8.59715207,9.24802589 8.06951459,9.24802589 7.74407768,8.92258898 L5,6.1785113 L2.25592232,8.92258898 C1.93048541,9.24802589 1.40284793,9.24802589 1.07741102,8.92258898 C0.751974106,8.59715207 0.751974106,8.06951459 1.07741102,7.74407768 L3.8214887,5 L1.07741102,2.25592232 C0.751974106,1.93048541 0.751974106,1.40284793 1.07741102,1.07741102 C1.40284793,0.751974106 1.93048541,0.751974106 2.25592232,1.07741102 L5,3.8214887 L7.74407768,1.07741102 C8.06951459,0.751974106 8.59715207,0.751974106 8.92258898,1.07741102 C9.24802589,1.40284793 9.24802589,1.93048541 8.92258898,2.25592232 L6.1785113,5 Z" id="path-1"></path>
|
||||||
|
</defs>
|
||||||
|
<g id="下载页" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<mask id="mask-2" fill="white">
|
||||||
|
<use xlink:href="#path-1"></use>
|
||||||
|
</mask>
|
||||||
|
<use id="Mask" fill="#182C4F" fill-rule="nonzero" xlink:href="#path-1"></use>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
15
resources/prompt_delete.svg
Normal file
15
resources/prompt_delete.svg
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="18px" height="17px" viewBox="0 0 18 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 53.2 (72643) - https://sketchapp.com -->
|
||||||
|
<title>Mask</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs>
|
||||||
|
<path d="M10.7557911,1.21895043 L17.3867068,13.3756291 C17.9156322,14.3453257 17.5583166,15.560199 16.5886199,16.0891245 C16.2948427,16.2493666 15.9655536,16.3333333 15.6309156,16.3333333 L2.36908438,16.3333333 C1.26451488,16.3333333 0.369084379,15.4379028 0.369084379,14.3333333 C0.369084379,13.9986954 0.453051125,13.6694063 0.613293233,13.3756291 L7.24420885,1.21895043 C7.77313431,0.24925376 8.98800759,-0.108061909 9.95770426,0.42086355 C10.2948373,0.604754298 10.5719004,0.881817396 10.7557911,1.21895043 Z M9.07936508,11.75 C8.61912779,11.75 8.24603175,12.123096 8.24603175,12.5833333 C8.24603175,13.0435706 8.61912779,13.4166667 9.07936508,13.4166667 C9.53960237,13.4166667 9.91269841,13.0435706 9.91269841,12.5833333 C9.91269841,12.123096 9.53960237,11.75 9.07936508,11.75 Z M9.07936508,5.5 C8.61912779,5.5 8.24603175,5.87309604 8.24603175,6.33333333 L8.24603175,9.66666667 C8.24603175,10.126904 8.61912779,10.5 9.07936508,10.5 C9.53960237,10.5 9.91269841,10.126904 9.91269841,9.66666667 L9.91269841,6.33333333 C9.91269841,5.87309604 9.53960237,5.5 9.07936508,5.5 Z" id="path-1"></path>
|
||||||
|
</defs>
|
||||||
|
<g id="下载页" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<mask id="mask-2" fill="white">
|
||||||
|
<use xlink:href="#path-1"></use>
|
||||||
|
</mask>
|
||||||
|
<use id="Mask" fill="#F25959" xlink:href="#path-1"></use>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
9
resources/successfull.svg
Normal file
9
resources/successfull.svg
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="12px" height="12px" viewBox="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 53.2 (72643) - https://sketchapp.com -->
|
||||||
|
<title>Combined Shape</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<g id="下载页" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<path d="M6.1,11.6 C3.0072054,11.6 0.5,9.0927946 0.5,6 C0.5,2.9072054 3.0072054,0.4 6.1,0.4 C9.1927946,0.4 11.7,2.9072054 11.7,6 C11.7,9.0927946 9.1927946,11.6 6.1,11.6 Z M5.74088496,8.2481404 L9.2254819,4.76354346 C9.44990579,4.53911957 9.44990579,4.17579395 9.2254819,3.95194404 C9.00105802,3.72752015 8.63773239,3.72752015 8.41388248,3.95194404 L5.33508525,7.03074127 L4.28528656,5.98094259 C4.06143665,5.75709268 3.69811103,5.75709268 3.47368714,5.98094259 C3.24983723,6.20536647 3.24983723,6.5686921 3.47368714,6.79311598 L4.92928554,8.2481404 C5.15313545,8.47256429 5.51646107,8.47256429 5.74088496,8.2481404 Z" id="Combined-Shape" fill="#37BD4B"></path>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
17
resources/warning.svg
Normal file
17
resources/warning.svg
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="18px" height="17px" viewBox="0 0 18 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 53.2 (72643) - https://sketchapp.com -->
|
||||||
|
<title>💚 Icon</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs>
|
||||||
|
<path d="M10.7557911,2.21895043 L17.3867068,14.3756291 C17.9156322,15.3453257 17.5583166,16.560199 16.5886199,17.0891245 C16.2948427,17.2493666 15.9655536,17.3333333 15.6309156,17.3333333 L2.36908438,17.3333333 C1.26451488,17.3333333 0.369084379,16.4379028 0.369084379,15.3333333 C0.369084379,14.9986954 0.453051125,14.6694063 0.613293233,14.3756291 L7.24420885,2.21895043 C7.77313431,1.24925376 8.98800759,0.891938091 9.95770426,1.42086355 C10.2948373,1.6047543 10.5719004,1.8818174 10.7557911,2.21895043 Z M9.07936508,12.75 C8.61912779,12.75 8.24603175,13.123096 8.24603175,13.5833333 C8.24603175,14.0435706 8.61912779,14.4166667 9.07936508,14.4166667 C9.53960237,14.4166667 9.91269841,14.0435706 9.91269841,13.5833333 C9.91269841,13.123096 9.53960237,12.75 9.07936508,12.75 Z M9.07936508,6.5 C8.61912779,6.5 8.24603175,6.87309604 8.24603175,7.33333333 L8.24603175,10.6666667 C8.24603175,11.126904 8.61912779,11.5 9.07936508,11.5 C9.53960237,11.5 9.91269841,11.126904 9.91269841,10.6666667 L9.91269841,7.33333333 C9.91269841,6.87309604 9.53960237,6.5 9.07936508,6.5 Z" id="path-1"></path>
|
||||||
|
</defs>
|
||||||
|
<g id="下载页" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="💚-Icon" transform="translate(0.000000, -1.000000)">
|
||||||
|
<mask id="mask-2" fill="white">
|
||||||
|
<use xlink:href="#path-1"></use>
|
||||||
|
</mask>
|
||||||
|
<use id="Mask" fill="#F5A623" xlink:href="#path-1"></use>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
Loading…
Reference in New Issue
Block a user