mirror of
https://github.com/iDescriptor/iDescriptor.git
synced 2026-06-21 19:35:49 +08:00
add DiskUsageWidget and enhance DeviceInfoWidget layout and functionality
This commit is contained in:
+182
-55
@@ -1,36 +1,103 @@
|
||||
#include "deviceinfowidget.h"
|
||||
#include "diskusagewidget.h"
|
||||
#include "fileexplorerwidget.h"
|
||||
#include "iDescriptor.h"
|
||||
#include <QDebug>
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QGraphicsView>
|
||||
#include <QGridLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QList>
|
||||
#include <QMessageBox>
|
||||
#include <QPainter>
|
||||
#include <QPair>
|
||||
#include <QPixmap>
|
||||
#include <QPushButton>
|
||||
#include <QResizeEvent>
|
||||
#include <QTabWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
// A custom QGraphicsView that keeps the content fitted with aspect ratio on
|
||||
// resize
|
||||
class ResponsiveGraphicsView : public QGraphicsView
|
||||
{
|
||||
public:
|
||||
ResponsiveGraphicsView(QGraphicsScene *scene, QWidget *parent = nullptr)
|
||||
: QGraphicsView(scene, parent)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override
|
||||
{
|
||||
if (scene() && !scene()->items().isEmpty()) {
|
||||
fitInView(scene()->itemsBoundingRect(), Qt::KeepAspectRatio);
|
||||
}
|
||||
QGraphicsView::resizeEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent)
|
||||
: QWidget(parent), device(device)
|
||||
{
|
||||
// Create main layout for this widget
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
// Main layout with horizontal orientation
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout(this);
|
||||
mainLayout->setContentsMargins(10, 10, 10, 10);
|
||||
mainLayout->setSpacing(10);
|
||||
|
||||
// Create device info section
|
||||
QWidget *devWidget = new QWidget();
|
||||
QVBoxLayout *devLayout = new QVBoxLayout(devWidget);
|
||||
devLayout->setContentsMargins(10, 10, 10, 10);
|
||||
devLayout->setSpacing(10);
|
||||
QGraphicsScene *scene = new QGraphicsScene(this);
|
||||
QGraphicsPixmapItem *pixmapItem =
|
||||
new QGraphicsPixmapItem(QPixmap(":/resources/iphone.png"));
|
||||
scene->addItem(pixmapItem);
|
||||
|
||||
QGraphicsView *graphicsView = new ResponsiveGraphicsView(scene, this);
|
||||
graphicsView->setRenderHint(QPainter::Antialiasing);
|
||||
graphicsView->setMinimumWidth(200);
|
||||
graphicsView->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Expanding);
|
||||
graphicsView->setStyleSheet("background: transparent; border: none;");
|
||||
|
||||
mainLayout->addWidget(graphicsView, 1); // Stretch factor 1
|
||||
|
||||
// Right side: Info Table
|
||||
QWidget *infoContainer = new QWidget();
|
||||
infoContainer->setObjectName("infoContainer");
|
||||
infoContainer->setStyleSheet("QWidget#infoContainer { "
|
||||
" border: 1px solid #ccc; "
|
||||
" border-radius: 6px; "
|
||||
"}");
|
||||
infoContainer->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
|
||||
|
||||
QVBoxLayout *infoLayout = new QVBoxLayout(infoContainer);
|
||||
infoLayout->setContentsMargins(15, 15, 15, 15);
|
||||
infoLayout->setSpacing(10);
|
||||
|
||||
// Header
|
||||
QLabel *headerLabel = new QLabel(
|
||||
"Device: " + QString::fromStdString(device->deviceInfo.productType));
|
||||
headerLabel->setStyleSheet("font-size: 1rem; padding-bottom: 10px; "
|
||||
"border-bottom: 1px solid #eee; "
|
||||
"font-weight: bold;");
|
||||
infoLayout->addWidget(headerLabel);
|
||||
|
||||
// Grid for device details
|
||||
QGridLayout *gridLayout = new QGridLayout();
|
||||
gridLayout->setSpacing(8);
|
||||
gridLayout->setColumnStretch(1, 1); // Allow value column to stretch
|
||||
gridLayout->setColumnStretch(
|
||||
3, 1); // Allow value column for right side to stretch
|
||||
|
||||
QList<QPair<QString, QWidget *>> infoItems;
|
||||
|
||||
auto createValueLabel = [](const QString &text) {
|
||||
return new QLabel(text);
|
||||
};
|
||||
|
||||
infoItems.append({"iOS Version:", createValueLabel(QString::fromStdString(
|
||||
device->deviceInfo.productVersion))});
|
||||
infoItems.append({"Device Name:", createValueLabel(QString::fromStdString(
|
||||
device->deviceInfo.deviceName))});
|
||||
|
||||
devLayout->addWidget(new QLabel(
|
||||
"Device: " + QString::fromStdString(device->deviceInfo.productType)));
|
||||
devLayout->addWidget(
|
||||
new QLabel("iOS Version: " +
|
||||
QString::fromStdString(device->deviceInfo.productVersion)));
|
||||
devLayout->addWidget(
|
||||
new QLabel("Device Name: " +
|
||||
QString::fromStdString(device->deviceInfo.deviceName)));
|
||||
// Activation state label with color and tooltip
|
||||
QLabel *activationLabel = new QLabel;
|
||||
QString stateText;
|
||||
@@ -55,50 +122,110 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent)
|
||||
break;
|
||||
}
|
||||
|
||||
activationLabel->setText("Activation State: " + stateText);
|
||||
activationLabel->setText(stateText);
|
||||
activationLabel->setStyleSheet("color: " + color.name() + ";");
|
||||
activationLabel->setToolTip(tooltipText);
|
||||
devLayout->addWidget(activationLabel);
|
||||
devLayout->addWidget(
|
||||
new QLabel("Device Class: " +
|
||||
QString::fromStdString(device->deviceInfo.deviceClass)));
|
||||
devLayout->addWidget(
|
||||
new QLabel("Device Color: " +
|
||||
QString::fromStdString(device->deviceInfo.deviceColor)));
|
||||
devLayout->addWidget(new QLabel(
|
||||
"Jailbroken: " +
|
||||
QString::fromStdString(device->deviceInfo.jailbroken ? "Yes" : "No")));
|
||||
devLayout->addWidget(
|
||||
new QLabel("Model Number: " +
|
||||
QString::fromStdString(device->deviceInfo.modelNumber)));
|
||||
devLayout->addWidget(
|
||||
new QLabel("CPU Architecture: " +
|
||||
QString::fromStdString(device->deviceInfo.cpuArchitecture)));
|
||||
devLayout->addWidget(
|
||||
new QLabel("Build Version: " +
|
||||
QString::fromStdString(device->deviceInfo.buildVersion)));
|
||||
devLayout->addWidget(
|
||||
new QLabel("Hardware Model: " +
|
||||
QString::fromStdString(device->deviceInfo.hardwareModel)));
|
||||
devLayout->addWidget(new QLabel(
|
||||
"Hardware Platform: " +
|
||||
QString::fromStdString(device->deviceInfo.hardwarePlatform)));
|
||||
devLayout->addWidget(
|
||||
new QLabel("Ethernet Address: " +
|
||||
QString::fromStdString(device->deviceInfo.ethernetAddress)));
|
||||
devLayout->addWidget(new QLabel(
|
||||
"Bluetooth Address: " +
|
||||
QString::fromStdString(device->deviceInfo.bluetoothAddress)));
|
||||
devLayout->addWidget(
|
||||
new QLabel("Firmware Version: " +
|
||||
QString::fromStdString(device->deviceInfo.firmwareVersion)));
|
||||
infoItems.append({"Activation State:", activationLabel});
|
||||
|
||||
devWidget->setStyleSheet(
|
||||
"QWidget { border: 1px solid #ccc; margin: 8px; border-radius: 6px; "
|
||||
"background: #fff; color: #000; }");
|
||||
infoItems.append({"Device Class:", createValueLabel(QString::fromStdString(
|
||||
device->deviceInfo.deviceClass))});
|
||||
infoItems.append({"Device Color:", createValueLabel(QString::fromStdString(
|
||||
device->deviceInfo.deviceColor))});
|
||||
infoItems.append(
|
||||
{"Jailbroken:", createValueLabel(QString::fromStdString(
|
||||
device->deviceInfo.jailbroken ? "Yes" : "No"))});
|
||||
infoItems.append({"Model Number:", createValueLabel(QString::fromStdString(
|
||||
device->deviceInfo.modelNumber))});
|
||||
infoItems.append(
|
||||
{"CPU Architecture:", createValueLabel(QString::fromStdString(
|
||||
device->deviceInfo.cpuArchitecture))});
|
||||
infoItems.append({"Build Version:", createValueLabel(QString::fromStdString(
|
||||
device->deviceInfo.buildVersion))});
|
||||
infoItems.append(
|
||||
{"Hardware Model:", createValueLabel(QString::fromStdString(
|
||||
device->deviceInfo.hardwareModel))});
|
||||
infoItems.append(
|
||||
{"Hardware Platform:", createValueLabel(QString::fromStdString(
|
||||
device->deviceInfo.hardwarePlatform))});
|
||||
infoItems.append(
|
||||
{"Ethernet Address:", createValueLabel(QString::fromStdString(
|
||||
device->deviceInfo.ethernetAddress))});
|
||||
infoItems.append(
|
||||
{"Bluetooth Address:", createValueLabel(QString::fromStdString(
|
||||
device->deviceInfo.bluetoothAddress))});
|
||||
infoItems.append(
|
||||
{"Firmware Version:", createValueLabel(QString::fromStdString(
|
||||
device->deviceInfo.firmwareVersion))});
|
||||
|
||||
// Add device info widget to main layout
|
||||
mainLayout->addWidget(devWidget);
|
||||
// Battery Info
|
||||
QWidget *batteryWidget = new QWidget();
|
||||
QHBoxLayout *batteryLayout = new QHBoxLayout(batteryWidget);
|
||||
batteryLayout->setContentsMargins(0, 0, 0, 0);
|
||||
batteryLayout->setSpacing(5);
|
||||
batteryLayout->addWidget(new QLabel(device->deviceInfo.batteryInfo.health));
|
||||
QPushButton *moreButton = new QPushButton("More");
|
||||
connect(moreButton, &QPushButton::clicked, this,
|
||||
&DeviceInfoWidget::onBatteryMoreClicked);
|
||||
batteryLayout->addWidget(moreButton);
|
||||
batteryLayout->addStretch();
|
||||
infoItems.append({"Battery Health:", batteryWidget});
|
||||
|
||||
infoItems.append(
|
||||
{"Production Device:",
|
||||
createValueLabel(QString::fromStdString(
|
||||
device->deviceInfo.productionDevice ? "Yes" : "No"))});
|
||||
|
||||
// Distribute items into the grid
|
||||
int numRows = (infoItems.size() + 1) / 2;
|
||||
for (int i = 0; i < numRows; ++i) {
|
||||
// Left column item
|
||||
QLabel *keyLabelLeft = new QLabel(infoItems[i].first);
|
||||
keyLabelLeft->setStyleSheet("font-weight: bold;");
|
||||
gridLayout->addWidget(keyLabelLeft, i, 0);
|
||||
gridLayout->addWidget(infoItems[i].second, i, 1);
|
||||
|
||||
// Right column item
|
||||
int rightIndex = i + numRows;
|
||||
if (rightIndex < infoItems.size()) {
|
||||
QLabel *keyLabelRight = new QLabel(infoItems[rightIndex].first);
|
||||
keyLabelRight->setStyleSheet("font-weight: bold;");
|
||||
gridLayout->addWidget(keyLabelRight, i, 2);
|
||||
gridLayout->addWidget(infoItems[rightIndex].second, i, 3);
|
||||
}
|
||||
}
|
||||
|
||||
infoLayout->addLayout(gridLayout);
|
||||
infoLayout->addStretch(); // Pushes footer to the bottom
|
||||
|
||||
// Footer
|
||||
QLabel *footerLabel =
|
||||
new QLabel("UDID: " + QString::fromStdString(device->udid));
|
||||
footerLabel->setStyleSheet(
|
||||
"font-size: 10px; color: #666; padding-top: 5px; "
|
||||
"border-top: 1px solid #eee;");
|
||||
footerLabel->setWordWrap(true);
|
||||
infoLayout->addWidget(footerLabel);
|
||||
|
||||
// Create a vertical layout for the right side to stack info and disk usage
|
||||
QVBoxLayout *rightSideLayout = new QVBoxLayout();
|
||||
rightSideLayout->setSpacing(10);
|
||||
rightSideLayout->addWidget(infoContainer);
|
||||
rightSideLayout->addWidget(new DiskUsageWidget(device, this));
|
||||
rightSideLayout->setAlignment(Qt::AlignCenter);
|
||||
mainLayout->addLayout(rightSideLayout, 2); // Stretch factor 2
|
||||
}
|
||||
|
||||
void DeviceInfoWidget::onBatteryMoreClicked()
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle("Battery Details");
|
||||
QString details =
|
||||
"Battery Cycle Count: " +
|
||||
QString::number(device->deviceInfo.batteryInfo.cycleCount) + "\n" +
|
||||
"Battery Serial Number: " +
|
||||
QString::fromStdString(device->deviceInfo.batteryInfo.serialNumber);
|
||||
msgBox.setText(details);
|
||||
msgBox.exec();
|
||||
}
|
||||
|
||||
QPixmap DeviceInfoWidget::getDeviceIcon(const std::string &productType)
|
||||
|
||||
@@ -10,8 +10,10 @@ public:
|
||||
explicit DeviceInfoWidget(iDescriptorDevice *device,
|
||||
QWidget *parent = nullptr);
|
||||
|
||||
private slots:
|
||||
void onBatteryMoreClicked();
|
||||
|
||||
private:
|
||||
QWidget *deviceInfoWidget;
|
||||
QPixmap getDeviceIcon(const std::string &productType);
|
||||
iDescriptorDevice *device;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
#include "diskusagewidget.h"
|
||||
#include "iDescriptor.h"
|
||||
#include <QDebug>
|
||||
#include <QFutureWatcher>
|
||||
#include <QPainter>
|
||||
#include <QVariantMap>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
#include <libimobiledevice/installation_proxy.h>
|
||||
#include <libimobiledevice/libimobiledevice.h>
|
||||
#include <libimobiledevice/lockdown.h>
|
||||
|
||||
DiskUsageWidget::DiskUsageWidget(iDescriptorDevice *device, QWidget *parent)
|
||||
: QWidget(parent), m_device(device), m_state(Loading), m_totalCapacity(0),
|
||||
m_systemUsage(0), m_appsUsage(0), m_mediaUsage(0), m_othersUsage(0),
|
||||
m_freeSpace(0)
|
||||
{
|
||||
setMinimumHeight(80);
|
||||
fetchData();
|
||||
}
|
||||
|
||||
QSize DiskUsageWidget::sizeHint() const { return QSize(400, 80); }
|
||||
|
||||
void DiskUsageWidget::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
if (m_state == Loading) {
|
||||
painter.setPen(Qt::black);
|
||||
painter.drawText(rect(), Qt::AlignCenter, "Loading disk usage...");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_state == Error) {
|
||||
painter.setPen(Qt::black);
|
||||
painter.drawText(rect(), Qt::AlignCenter, "Error: " + m_errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
// Title
|
||||
painter.setPen(Qt::black);
|
||||
QFont titleFont = font();
|
||||
titleFont.setBold(true);
|
||||
painter.setFont(titleFont);
|
||||
QRectF titleRect(0, 5, width(), 20);
|
||||
painter.drawText(titleRect, Qt::AlignHCenter | Qt::AlignTop, "Disk Usage");
|
||||
painter.setFont(font()); // Reset font
|
||||
|
||||
if (m_totalCapacity == 0) {
|
||||
painter.setPen(Qt::black);
|
||||
painter.drawText(QRect(0, 30, width(), height() - 30), Qt::AlignCenter,
|
||||
"No disk information available.");
|
||||
return;
|
||||
}
|
||||
|
||||
painter.setPen(Qt::NoPen);
|
||||
|
||||
const int barHeight = 20;
|
||||
QRectF barRect(10, 30, width() - 20, barHeight);
|
||||
|
||||
double scale = (double)barRect.width() / m_totalCapacity;
|
||||
double currentX = barRect.left();
|
||||
|
||||
auto drawSegment = [&](uint64_t value, const QColor &color) {
|
||||
if (value > 0) {
|
||||
double segmentWidth = value * scale;
|
||||
painter.fillRect(
|
||||
QRectF(currentX, barRect.top(), segmentWidth, barRect.height()),
|
||||
color);
|
||||
currentX += segmentWidth;
|
||||
}
|
||||
};
|
||||
|
||||
const QColor systemColor("#E74C3C");
|
||||
const QColor appsColor("#3498DB");
|
||||
const QColor mediaColor("#2ECC71");
|
||||
const QColor othersColor("#F39C12");
|
||||
const QColor freeColor("#BDC3C7");
|
||||
|
||||
// System
|
||||
drawSegment(m_systemUsage, systemColor);
|
||||
// Apps
|
||||
drawSegment(m_appsUsage, appsColor);
|
||||
// Media
|
||||
drawSegment(m_mediaUsage, mediaColor);
|
||||
// Others
|
||||
drawSegment(m_othersUsage, othersColor);
|
||||
// Free
|
||||
drawSegment(m_freeSpace, freeColor);
|
||||
|
||||
// Legend
|
||||
painter.setPen(Qt::black);
|
||||
qreal legendY = barRect.bottom() + 15;
|
||||
const int legendBoxSize = 10;
|
||||
const int legendSpacing = 5;
|
||||
qreal currentLegendX = barRect.left();
|
||||
|
||||
auto drawLegendItem = [&](const QColor &color, const QString &text) {
|
||||
painter.fillRect(
|
||||
QRectF(currentLegendX, legendY, legendBoxSize, legendBoxSize),
|
||||
color);
|
||||
currentLegendX += legendBoxSize + legendSpacing;
|
||||
|
||||
QFontMetrics fm(font());
|
||||
QRect textRect = fm.boundingRect(text);
|
||||
painter.drawText(QPointF(currentLegendX, legendY + legendBoxSize),
|
||||
text);
|
||||
currentLegendX += textRect.width() + legendSpacing * 2;
|
||||
};
|
||||
|
||||
drawLegendItem(systemColor, "System");
|
||||
drawLegendItem(appsColor, "Apps");
|
||||
drawLegendItem(mediaColor, "Media");
|
||||
drawLegendItem(othersColor, "Others");
|
||||
drawLegendItem(freeColor, "Free");
|
||||
}
|
||||
|
||||
void DiskUsageWidget::fetchData()
|
||||
{
|
||||
auto *watcher = new QFutureWatcher<QVariantMap>(this);
|
||||
connect(watcher, &QFutureWatcher<QVariantMap>::finished, this,
|
||||
[this, watcher]() {
|
||||
QVariantMap result = watcher->result();
|
||||
if (result.contains("error")) {
|
||||
m_state = Error;
|
||||
m_errorMessage = result["error"].toString();
|
||||
} else {
|
||||
m_totalCapacity = result["totalCapacity"].toULongLong();
|
||||
m_systemUsage = result["systemUsage"].toULongLong();
|
||||
m_appsUsage = result["appsUsage"].toULongLong();
|
||||
m_mediaUsage = result["mediaUsage"].toULongLong();
|
||||
m_freeSpace = result["freeSpace"].toULongLong();
|
||||
|
||||
uint64_t usedKnown =
|
||||
m_systemUsage + m_appsUsage + m_mediaUsage;
|
||||
if (m_totalCapacity > (m_freeSpace + usedKnown)) {
|
||||
m_othersUsage =
|
||||
m_totalCapacity - m_freeSpace - usedKnown;
|
||||
} else {
|
||||
m_othersUsage = 0;
|
||||
}
|
||||
|
||||
m_state = Ready;
|
||||
}
|
||||
update(); // Trigger repaint
|
||||
watcher->deleteLater();
|
||||
});
|
||||
|
||||
QFuture<QVariantMap> future = QtConcurrent::run([this]() {
|
||||
QVariantMap result;
|
||||
if (!m_device || !m_device->device) {
|
||||
result["error"] = "Invalid device.";
|
||||
return result;
|
||||
}
|
||||
|
||||
result["totalCapacity"] = QVariant::fromValue(
|
||||
m_device->deviceInfo.diskInfo.totalDiskCapacity);
|
||||
result["freeSpace"] = QVariant::fromValue(
|
||||
m_device->deviceInfo.diskInfo.totalDataAvailable);
|
||||
result["systemUsage"] = QVariant::fromValue(
|
||||
m_device->deviceInfo.diskInfo.totalSystemCapacity);
|
||||
|
||||
// Apps usage
|
||||
uint64_t totalAppsSpace = 0;
|
||||
instproxy_client_t instproxy = nullptr;
|
||||
lockdownd_client_t lockdownClient = nullptr;
|
||||
|
||||
if (lockdownd_client_new_with_handshake(m_device->device,
|
||||
&lockdownClient, APP_LABEL) !=
|
||||
LOCKDOWN_E_SUCCESS) {
|
||||
result["error"] = "Could not connect to lockdown service.";
|
||||
return result;
|
||||
}
|
||||
lockdownd_service_descriptor_t lockdowndService = nullptr;
|
||||
if (lockdownd_start_service(lockdownClient,
|
||||
"com.apple.mobile.installation_proxy",
|
||||
&lockdowndService) != LOCKDOWN_E_SUCCESS) {
|
||||
}
|
||||
|
||||
if (instproxy_client_new(m_device->device, lockdowndService,
|
||||
&instproxy) != INSTPROXY_E_SUCCESS) {
|
||||
lockdownd_service_descriptor_free(lockdowndService);
|
||||
}
|
||||
|
||||
if (instproxy_client_new(m_device->device, lockdowndService,
|
||||
&instproxy) != INSTPROXY_E_SUCCESS) {
|
||||
result["error"] = "Could not connect to installation proxy.";
|
||||
return result;
|
||||
}
|
||||
|
||||
lockdownd_service_descriptor_free(lockdowndService);
|
||||
|
||||
plist_t client_opts = instproxy_client_options_new();
|
||||
plist_dict_set_item(client_opts, "ApplicationType",
|
||||
plist_new_string("User"));
|
||||
|
||||
plist_t return_attrs = plist_new_array();
|
||||
plist_array_append_item(return_attrs,
|
||||
plist_new_string("StaticDiskUsage"));
|
||||
plist_array_append_item(return_attrs,
|
||||
plist_new_string("DynamicDiskUsage"));
|
||||
plist_dict_set_item(client_opts, "ReturnAttributes", return_attrs);
|
||||
|
||||
plist_t apps = nullptr;
|
||||
if (instproxy_browse(instproxy, client_opts, &apps) ==
|
||||
INSTPROXY_E_SUCCESS &&
|
||||
apps) {
|
||||
if (plist_get_node_type(apps) == PLIST_ARRAY) {
|
||||
for (uint32_t i = 0; i < plist_array_get_size(apps); i++) {
|
||||
plist_t app_info = plist_array_get_item(apps, i);
|
||||
if (!app_info)
|
||||
continue;
|
||||
|
||||
plist_t static_usage =
|
||||
plist_dict_get_item(app_info, "StaticDiskUsage");
|
||||
if (static_usage &&
|
||||
plist_get_node_type(static_usage) == PLIST_UINT) {
|
||||
uint64_t static_size = 0;
|
||||
plist_get_uint_val(static_usage, &static_size);
|
||||
totalAppsSpace += static_size;
|
||||
}
|
||||
|
||||
plist_t dynamic_usage =
|
||||
plist_dict_get_item(app_info, "DynamicDiskUsage");
|
||||
if (dynamic_usage &&
|
||||
plist_get_node_type(dynamic_usage) == PLIST_UINT) {
|
||||
uint64_t dynamic_size = 0;
|
||||
plist_get_uint_val(dynamic_usage, &dynamic_size);
|
||||
totalAppsSpace += dynamic_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
plist_free(apps);
|
||||
}
|
||||
result["appsUsage"] = QVariant::fromValue(totalAppsSpace);
|
||||
plist_free(client_opts);
|
||||
instproxy_client_free(instproxy);
|
||||
|
||||
// Media usage
|
||||
uint64_t mediaSpace = 0;
|
||||
plist_t node = nullptr;
|
||||
if (lockdownd_get_value(lockdownClient, "com.apple.mobile.iTunes",
|
||||
nullptr, &node) == LOCKDOWN_E_SUCCESS &&
|
||||
node) {
|
||||
plist_t mediaNode = plist_dict_get_item(node, "MediaLibrarySize");
|
||||
if (mediaNode && plist_get_node_type(mediaNode) == PLIST_UINT) {
|
||||
plist_get_uint_val(mediaNode, &mediaSpace);
|
||||
}
|
||||
plist_free(node);
|
||||
}
|
||||
result["mediaUsage"] = QVariant::fromValue(mediaSpace);
|
||||
|
||||
return result;
|
||||
});
|
||||
watcher->setFuture(future);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef DISKUSAGEWIDGET_H
|
||||
#define DISKUSAGEWIDGET_H
|
||||
#include "iDescriptor.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <cstdint>
|
||||
|
||||
class DiskUsageWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DiskUsageWidget(iDescriptorDevice *device,
|
||||
QWidget *parent = nullptr);
|
||||
QSize sizeHint() const override;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
void fetchData();
|
||||
|
||||
enum State { Loading, Ready, Error };
|
||||
|
||||
iDescriptorDevice *m_device;
|
||||
State m_state;
|
||||
QString m_errorMessage;
|
||||
|
||||
uint64_t m_totalCapacity;
|
||||
uint64_t m_systemUsage;
|
||||
uint64_t m_appsUsage;
|
||||
uint64_t m_mediaUsage;
|
||||
uint64_t m_othersUsage;
|
||||
uint64_t m_freeSpace;
|
||||
};
|
||||
|
||||
#endif // DISKUSAGEWIDGET_H
|
||||
+54
-2
@@ -12,8 +12,36 @@
|
||||
#define RECOVERY_CLIENT_CONNECTION_TRIES 3
|
||||
#define APPLE_VENDOR_ID 0x05ac
|
||||
|
||||
struct BatteryInfo {
|
||||
QString health;
|
||||
uint64_t cycleCount;
|
||||
// uint64_t designCapacity;
|
||||
// uint64_t maxCapacity;
|
||||
// uint64_t fullChargeCapacity;
|
||||
std::string serialNumber;
|
||||
};
|
||||
|
||||
//! IOS 12
|
||||
/* {
|
||||
"AmountDataAvailable": 6663077888,
|
||||
"AmountDataReserved": 209715200,
|
||||
"AmountRestoreAvailable": 11524079616,
|
||||
"CalculateDiskUsage": "OkilyDokily",
|
||||
"NANDInfo": <01000000 01000000 01000000 00000080 ... 00 00000000 000000>,
|
||||
"TotalDataAvailable": 6872793088,
|
||||
"TotalDataCapacity": 11306721280,
|
||||
"TotalDiskCapacity": 16000000000,
|
||||
"TotalSystemAvailable": 0,
|
||||
"TotalSystemCapacity": 4693204992
|
||||
}*/
|
||||
struct DiskInfo {
|
||||
uint64_t totalDiskCapacity;
|
||||
uint64_t totalDataCapacity;
|
||||
uint64_t totalSystemCapacity;
|
||||
uint64_t totalDataAvailable;
|
||||
};
|
||||
|
||||
struct DeviceInfo {
|
||||
std::string _0;
|
||||
enum class ActivationState {
|
||||
Activated,
|
||||
FactoryActivated,
|
||||
@@ -79,6 +107,9 @@ struct DeviceInfo {
|
||||
bool systemAudioVolumeSaved;
|
||||
bool autoBoot;
|
||||
int backlightLevel;
|
||||
bool productionDevice;
|
||||
BatteryInfo batteryInfo;
|
||||
DiskInfo diskInfo;
|
||||
};
|
||||
|
||||
struct iDescriptorDevice {
|
||||
@@ -165,4 +196,25 @@ enum class AddType { Regular, Pairing };
|
||||
|
||||
#define APP_LABEL "iDescriptor"
|
||||
#define APP_VERSION "0.0.1"
|
||||
#define APP_COPYRIGHT "© 2023 Uncore. All rights reserved."
|
||||
#define APP_COPYRIGHT "© 2023 Uncore. All rights reserved."
|
||||
|
||||
class PlistNavigator
|
||||
{
|
||||
private:
|
||||
plist_t current_node;
|
||||
|
||||
public:
|
||||
PlistNavigator(plist_t node) : current_node(node) {}
|
||||
|
||||
PlistNavigator operator[](const char *key)
|
||||
{
|
||||
if (!current_node || plist_get_node_type(current_node) != PLIST_DICT) {
|
||||
return PlistNavigator(nullptr);
|
||||
}
|
||||
plist_t next = plist_dict_get_item(current_node, key);
|
||||
return PlistNavigator(next);
|
||||
}
|
||||
|
||||
operator plist_t() const { return current_node; }
|
||||
bool valid() const { return current_node != nullptr; }
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user