mirror of
https://github.com/iDescriptor/iDescriptor.git
synced 2026-06-22 03:45:51 +08:00
integrate ZUpdater & refactor device management and UI components
- Integrated ZUpdater to handle auto updating - Updated DeviceManagerWidget to improve device selection logic and ensure current device is set correctly when devices are added or removed. - Enhanced FileExplorerWidget to reset the view when sidebar items are clicked. - Changed ZIconWidget to inherit from QAbstractButton for better button behavior and removed unnecessary mouse event handling. - Updated iDescriptor to include device version parsing and improved device version retrieval logic. - Refactored iFuseDiskUnmountButton and iFuseDiskUnmountButton to use ZIconWidget for a consistent UI. - Improved iFuseWidget to handle device selection more robustly and update UI accordingly. - Added SponsorAppCard and SponsorWidget to promote sponsorship within the app. - Updated ToolboxWidget to streamline device selection and toolbox functionality. - General code cleanup and comments for better maintainability.
This commit is contained in:
+386
-67
@@ -6,10 +6,12 @@
|
||||
#include "appstoremanager.h"
|
||||
#include "iDescriptor-ui.h"
|
||||
#include "logindialog.h"
|
||||
#include "sponsorwidget.h"
|
||||
#include "zlineedit.h"
|
||||
#include <QApplication>
|
||||
#include <QComboBox>
|
||||
#include <QDebug>
|
||||
#include <QDesktopServices>
|
||||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
#include <QGridLayout>
|
||||
@@ -23,11 +25,15 @@
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QMessageBox>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QPixmap>
|
||||
#include <QProgressBar>
|
||||
#include <QPushButton>
|
||||
#include <QRegularExpression>
|
||||
#include <QScrollArea>
|
||||
#include <QStyle>
|
||||
#include <QTimer>
|
||||
@@ -35,7 +41,90 @@
|
||||
#include <QWidget>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
// Helper struct for semantic version comparison
|
||||
struct AppVersion {
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
int patch = 0;
|
||||
|
||||
static AppVersion fromString(QString versionString)
|
||||
{
|
||||
// Keep only digits and dots for comparison
|
||||
versionString.remove(QRegularExpression("[^\\d.]"));
|
||||
AppVersion v;
|
||||
QStringList parts = versionString.split('.');
|
||||
if (parts.size() > 0)
|
||||
v.major = parts[0].toInt();
|
||||
if (parts.size() > 1)
|
||||
v.minor = parts[1].toInt();
|
||||
if (parts.size() > 2)
|
||||
v.patch = parts[2].toInt();
|
||||
return v;
|
||||
}
|
||||
|
||||
bool operator<(const AppVersion &other) const
|
||||
{
|
||||
if (major != other.major)
|
||||
return major < other.major;
|
||||
if (minor != other.minor)
|
||||
return minor < other.minor;
|
||||
return patch < other.patch;
|
||||
}
|
||||
|
||||
bool operator==(const AppVersion &other) const
|
||||
{
|
||||
return major == other.major && minor == other.minor &&
|
||||
patch == other.patch;
|
||||
}
|
||||
|
||||
bool operator>(const AppVersion &other) const
|
||||
{
|
||||
return !(*this < other || *this == other);
|
||||
}
|
||||
bool operator<=(const AppVersion &other) const
|
||||
{
|
||||
return (*this < other || *this == other);
|
||||
}
|
||||
bool operator>=(const AppVersion &other) const { return !(*this < other); }
|
||||
};
|
||||
|
||||
// Checks if the current app version matches a given version condition
|
||||
bool versionMatches(const QString ¤tVersionStr,
|
||||
const QString &conditionStr)
|
||||
{
|
||||
AppVersion currentVersion = AppVersion::fromString(currentVersionStr);
|
||||
AppVersion conditionVersion = AppVersion::fromString(conditionStr);
|
||||
|
||||
if (conditionStr.startsWith("<="))
|
||||
return currentVersion <= conditionVersion;
|
||||
if (conditionStr.startsWith(">="))
|
||||
return currentVersion >= conditionVersion;
|
||||
if (conditionStr.startsWith("<"))
|
||||
return currentVersion < conditionVersion;
|
||||
if (conditionStr.startsWith(">"))
|
||||
return currentVersion > conditionVersion;
|
||||
|
||||
// Exact match
|
||||
return currentVersion == conditionVersion;
|
||||
}
|
||||
|
||||
QJsonObject getVersionedConfig(const QJsonObject &rootObj)
|
||||
{
|
||||
QStringList keys = rootObj.keys();
|
||||
for (const QString &key : keys) {
|
||||
if (versionMatches(APP_VERSION, key)) {
|
||||
return rootObj[key].toObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// watch for login and logout events
|
||||
AppsWidget *AppsWidget::sharedInstance()
|
||||
{
|
||||
static AppsWidget instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
AppsWidget::AppsWidget(QWidget *parent) : QWidget(parent), m_isLoggedIn(false)
|
||||
{
|
||||
m_debounceTimer = new QTimer(this);
|
||||
@@ -47,8 +136,9 @@ void AppsWidget::setupUI()
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
mainLayout->setSpacing(0);
|
||||
|
||||
// Header with login
|
||||
m_networkManager = new QNetworkAccessManager(this);
|
||||
|
||||
QWidget *headerWidget = new QWidget();
|
||||
headerWidget->setFixedHeight(60);
|
||||
headerWidget->setStyleSheet("border-bottom: 1px solid #363d32;");
|
||||
@@ -110,7 +200,7 @@ void AppsWidget::setupUI()
|
||||
mainLayout->addWidget(m_stackedWidget);
|
||||
|
||||
// Show default apps initially
|
||||
showDefaultApps();
|
||||
showLoading("Loading apps...");
|
||||
// Connections
|
||||
connect(m_loginButton, &QPushButton::clicked, this,
|
||||
&AppsWidget::onLoginClicked);
|
||||
@@ -123,6 +213,60 @@ void AppsWidget::setupUI()
|
||||
&AppsWidget::onAppStoreInitialized);
|
||||
connect(m_manager, &AppStoreManager::loggedOut, this,
|
||||
&AppsWidget::onAppStoreInitialized);
|
||||
|
||||
// fetch sponsors
|
||||
QUrl sponsorsUrl("http://localhost:5173/sponsors.json");
|
||||
QNetworkRequest request(sponsorsUrl);
|
||||
QNetworkReply *reply = m_networkManager->get(request);
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
|
||||
try {
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QByteArray responseData = reply->readAll();
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(responseData);
|
||||
if (jsonDoc.isNull() || !jsonDoc.isObject()) {
|
||||
qDebug() << "Failed to parse sponsors JSON";
|
||||
showDefaultApps();
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject rootObj = jsonDoc.object();
|
||||
QJsonObject versioned = getVersionedConfig(rootObj);
|
||||
|
||||
if (versioned.isEmpty()) {
|
||||
qDebug() << "No sponsor configuration found for version"
|
||||
<< APP_VERSION << "or default.";
|
||||
showDefaultApps();
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject sponsorObj = versioned["sponsors"].toObject();
|
||||
QJsonObject platinumObj = sponsorObj["platinum"].toObject();
|
||||
QJsonObject goldObj = sponsorObj["gold"].toObject();
|
||||
QJsonObject silverObj = sponsorObj["silver"].toObject();
|
||||
QJsonObject bronzeObj = sponsorObj["bronze"].toObject();
|
||||
|
||||
// Store the platinum members to be used when populating the
|
||||
// grid
|
||||
m_platinumSponsors = platinumObj["members"].toArray();
|
||||
m_goldSponsors = goldObj["members"].toArray();
|
||||
m_silverSponsors = silverObj["members"].toArray();
|
||||
m_bronzeSponsors = bronzeObj["members"].toArray();
|
||||
|
||||
if (!m_platinumSponsors.isEmpty()) {
|
||||
qDebug() << "Platinum Sponsors found";
|
||||
}
|
||||
}
|
||||
qDebug() << "Sponsors fetch completed";
|
||||
showDefaultApps();
|
||||
reply->deleteLater();
|
||||
} catch (...) {
|
||||
qDebug() << "Exception occurred while processing sponsors";
|
||||
showDefaultApps();
|
||||
reply->deleteLater();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void AppsWidget::onAppStoreInitialized(const QJsonObject &accountInfo)
|
||||
@@ -242,26 +386,102 @@ void AppsWidget::populateDefaultApps()
|
||||
if (!gridLayout)
|
||||
return;
|
||||
|
||||
// Create sample app cards
|
||||
createAppCard("Instagram", "com.burbn.instagram",
|
||||
"Photo & Video sharing social network", "", gridLayout, 0, 0);
|
||||
createAppCard("WhatsApp", "net.whatsapp.WhatsApp",
|
||||
"Free messaging and video calling", "", gridLayout, 0, 1);
|
||||
createAppCard("Spotify", "com.spotify.client",
|
||||
"Music streaming and podcast platform", "", gridLayout, 0, 2);
|
||||
createAppCard("YouTube", "com.google.ios.youtube",
|
||||
"Video sharing and streaming platform", "", gridLayout, 1, 0);
|
||||
createAppCard("X", "com.atebits.Tweetie2", "Social media and microblogging",
|
||||
"", gridLayout, 1, 1);
|
||||
createAppCard("TikTok", "com.zhiliaoapp.musically",
|
||||
"Short-form video hosting service", "", gridLayout, 1, 2);
|
||||
createAppCard("Twitch", "tv.twitch", "Live streaming platform", "",
|
||||
gridLayout, 2, 0);
|
||||
createAppCard("Telegram", "ph.telegra.Telegraph",
|
||||
"Cloud-based instant messaging", "", gridLayout, 2, 1);
|
||||
createAppCard("Reddit", "com.reddit.Reddit",
|
||||
"Social news aggregation platform", "", gridLayout, 2, 2);
|
||||
int row = 0;
|
||||
int col = 0;
|
||||
const int maxCols = 3;
|
||||
|
||||
// Helper lambda to advance the grid position
|
||||
auto advanceGridPos = [&]() {
|
||||
col++;
|
||||
if (col >= maxCols) {
|
||||
col = 0;
|
||||
row++;
|
||||
}
|
||||
};
|
||||
|
||||
for (const QJsonValue &sponsorValue : m_platinumSponsors) {
|
||||
QJsonObject sponsorObj = sponsorValue.toObject();
|
||||
QString name = sponsorObj.value("name").toString();
|
||||
QString bundleId = sponsorObj.value("bundleId").toString();
|
||||
QString logoUrl = sponsorObj.value("logo").toString();
|
||||
QString description = sponsorObj.value("description").toString();
|
||||
QString url = sponsorObj.value("url").toString();
|
||||
|
||||
createAppCard(name, bundleId, description, logoUrl, url, gridLayout,
|
||||
row, col, SponsorType(SponsorType::Platinum));
|
||||
advanceGridPos();
|
||||
}
|
||||
|
||||
for (const QJsonValue &sponsorValue : m_goldSponsors) {
|
||||
QJsonObject sponsorObj = sponsorValue.toObject();
|
||||
QString name = sponsorObj.value("name").toString();
|
||||
QString bundleId = sponsorObj.value("bundleId").toString();
|
||||
QString description = sponsorObj.value("description").toString();
|
||||
QString logoUrl = sponsorObj.value("logo").toString();
|
||||
QString url = sponsorObj.value("url").toString();
|
||||
createAppCard(name, bundleId, description, logoUrl, url, gridLayout,
|
||||
row, col, SponsorType(SponsorType::Gold));
|
||||
advanceGridPos();
|
||||
}
|
||||
|
||||
if (m_platinumSponsors.empty() && m_goldSponsors.empty()) {
|
||||
createSponsorCard(gridLayout, row, col);
|
||||
advanceGridPos();
|
||||
}
|
||||
|
||||
createAppCard("Instagram", "com.burbn.instagram",
|
||||
"Photo & Video sharing social network", "", "", gridLayout,
|
||||
row, col);
|
||||
advanceGridPos();
|
||||
createAppCard("Spotify", "com.spotify.client",
|
||||
"Music streaming and podcast platform", "", "", gridLayout,
|
||||
row, col);
|
||||
advanceGridPos();
|
||||
createAppCard("YouTube", "com.google.ios.youtube",
|
||||
"Video sharing and streaming platform", "", "", gridLayout,
|
||||
row, col);
|
||||
advanceGridPos();
|
||||
createAppCard("X", "com.atebits.Tweetie2", "Social media and microblogging",
|
||||
"", "", gridLayout, row, col);
|
||||
advanceGridPos();
|
||||
createAppCard("TikTok", "com.zhiliaoapp.musically",
|
||||
"Short-form video hosting service", "", "", gridLayout, row,
|
||||
col);
|
||||
advanceGridPos();
|
||||
createAppCard("Twitch", "tv.twitch", "Live streaming platform", "", "",
|
||||
gridLayout, row, col);
|
||||
advanceGridPos();
|
||||
createAppCard("Telegram", "ph.telegra.Telegraph",
|
||||
"Cloud-based instant messaging", "", "", gridLayout, row,
|
||||
col);
|
||||
advanceGridPos();
|
||||
createAppCard("Reddit", "com.reddit.Reddit",
|
||||
"Social news aggregation platform", "", "", gridLayout, row,
|
||||
col);
|
||||
advanceGridPos();
|
||||
|
||||
for (const QJsonValue &sponsorValue : m_silverSponsors) {
|
||||
QJsonObject sponsorObj = sponsorValue.toObject();
|
||||
QString name = sponsorObj.value("name").toString();
|
||||
QString bundleId = sponsorObj.value("bundleId").toString();
|
||||
QString description = sponsorObj.value("description").toString();
|
||||
QString url = sponsorObj.value("url").toString();
|
||||
|
||||
createAppCard(name, bundleId, description, "", url, gridLayout, row,
|
||||
col, SponsorType(SponsorType::Silver));
|
||||
advanceGridPos();
|
||||
}
|
||||
|
||||
for (const QJsonValue &sponsorValue : m_bronzeSponsors) {
|
||||
QJsonObject sponsorObj = sponsorValue.toObject();
|
||||
QString name = sponsorObj.value("name").toString();
|
||||
QString bundleId = sponsorObj.value("bundleId").toString();
|
||||
QString description = sponsorObj.value("description").toString();
|
||||
QString url = sponsorObj.value("url").toString();
|
||||
createAppCard(name, bundleId, description, "", url, gridLayout, row,
|
||||
col, SponsorType(SponsorType::Bronze));
|
||||
advanceGridPos();
|
||||
}
|
||||
gridLayout->setRowStretch(gridLayout->rowCount(), 1);
|
||||
}
|
||||
|
||||
@@ -281,10 +501,37 @@ void AppsWidget::clearAppGrid()
|
||||
}
|
||||
}
|
||||
|
||||
void AppsWidget::createSponsorCard(QGridLayout *gridLayout, int row, int col)
|
||||
{
|
||||
if (!gridLayout)
|
||||
return;
|
||||
|
||||
ClickableWidget *sponsorCard = new ClickableWidget();
|
||||
sponsorCard->setStyleSheet("border: 1px solid #ddd; border-radius: 8px;");
|
||||
sponsorCard->setCursor(Qt::PointingHandCursor);
|
||||
connect(sponsorCard, &ClickableWidget::clicked, this, [this]() {
|
||||
auto sWidget = new SponsorWidget();
|
||||
sWidget->setAttribute(Qt::WA_DeleteOnClose);
|
||||
sWidget->show();
|
||||
});
|
||||
QVBoxLayout *sponsorLayout = new QVBoxLayout(sponsorCard);
|
||||
sponsorLayout->setContentsMargins(12, 12, 12, 12);
|
||||
sponsorLayout->setSpacing(8);
|
||||
|
||||
QLabel *sponsorLabel = new QLabel("Become a Sponsor!");
|
||||
sponsorLabel->setAlignment(Qt::AlignCenter);
|
||||
sponsorLabel->setStyleSheet("font-size: 14px; font-weight: bold;");
|
||||
sponsorLayout->addWidget(sponsorLabel);
|
||||
|
||||
gridLayout->addWidget(sponsorCard, row, col);
|
||||
}
|
||||
|
||||
void AppsWidget::createAppCard(const QString &name, const QString &bundleId,
|
||||
const QString &description,
|
||||
const QString &iconPath, QGridLayout *gridLayout,
|
||||
int row, int col)
|
||||
const QString &logoUrl,
|
||||
const QString &websiteUrl,
|
||||
QGridLayout *gridLayout, int row, int col,
|
||||
const SponsorType &sponsorType)
|
||||
{
|
||||
QWidget *cardWidget = new QWidget();
|
||||
|
||||
@@ -301,74 +548,146 @@ void AppsWidget::createAppCard(const QString &name, const QString &bundleId,
|
||||
iconLabel->setAlignment(Qt::AlignCenter);
|
||||
cardLayout->addWidget(iconLabel);
|
||||
|
||||
fetchAppIconFromApple(
|
||||
bundleId,
|
||||
[iconLabel](const QPixmap &pixmap) {
|
||||
if (!pixmap.isNull()) {
|
||||
QPixmap scaled =
|
||||
pixmap.scaled(64, 64, Qt::KeepAspectRatioByExpanding,
|
||||
Qt::SmoothTransformation);
|
||||
QPixmap rounded(64, 64);
|
||||
rounded.fill(Qt::transparent);
|
||||
// If logoUrl is provided and bundleId is empty, use the logo directly
|
||||
if (!logoUrl.isEmpty()) {
|
||||
QUrl url(logoUrl);
|
||||
QNetworkRequest request(url);
|
||||
QNetworkReply *reply = m_networkManager->get(request);
|
||||
connect(reply, &QNetworkReply::finished, [reply, iconLabel]() {
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QByteArray data = reply->readAll();
|
||||
QPixmap pixmap;
|
||||
if (pixmap.loadFromData(data)) {
|
||||
QPixmap scaled =
|
||||
pixmap.scaled(64, 64, Qt::KeepAspectRatioByExpanding,
|
||||
Qt::SmoothTransformation);
|
||||
QPixmap rounded(64, 64);
|
||||
rounded.fill(Qt::transparent);
|
||||
|
||||
QPainter painter(&rounded);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
QPainterPath path;
|
||||
path.addRoundedRect(QRectF(0, 0, 64, 64), 16, 16);
|
||||
painter.setClipPath(path);
|
||||
painter.drawPixmap(0, 0, scaled);
|
||||
painter.end();
|
||||
QPainter painter(&rounded);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
QPainterPath path;
|
||||
path.addRoundedRect(QRectF(0, 0, 64, 64), 16, 16);
|
||||
painter.setClipPath(path);
|
||||
painter.drawPixmap(0, 0, scaled);
|
||||
painter.end();
|
||||
|
||||
iconLabel->setPixmap(rounded);
|
||||
iconLabel->setPixmap(rounded);
|
||||
}
|
||||
}
|
||||
},
|
||||
cardWidget);
|
||||
reply->deleteLater();
|
||||
});
|
||||
} else if (!bundleId.isEmpty()) {
|
||||
// Use Apple's API for app icons
|
||||
fetchAppIconFromApple(
|
||||
bundleId,
|
||||
[iconLabel](const QPixmap &pixmap) {
|
||||
if (!pixmap.isNull()) {
|
||||
QPixmap scaled =
|
||||
pixmap.scaled(64, 64, Qt::KeepAspectRatioByExpanding,
|
||||
Qt::SmoothTransformation);
|
||||
QPixmap rounded(64, 64);
|
||||
rounded.fill(Qt::transparent);
|
||||
|
||||
QPainter painter(&rounded);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
QPainterPath path;
|
||||
path.addRoundedRect(QRectF(0, 0, 64, 64), 16, 16);
|
||||
painter.setClipPath(path);
|
||||
painter.drawPixmap(0, 0, scaled);
|
||||
painter.end();
|
||||
|
||||
iconLabel->setPixmap(rounded);
|
||||
}
|
||||
},
|
||||
cardWidget);
|
||||
}
|
||||
|
||||
// Vertical layout for name and description
|
||||
QVBoxLayout *textLayout = new QVBoxLayout();
|
||||
|
||||
// App name
|
||||
// App name with sponsor indicator
|
||||
QHBoxLayout *nameLayout = new QHBoxLayout();
|
||||
QLabel *nameLabel = new QLabel(name);
|
||||
nameLabel->setStyleSheet("font-size: 16px;");
|
||||
nameLabel->setAlignment(Qt::AlignCenter);
|
||||
nameLabel->setWordWrap(true);
|
||||
textLayout->addWidget(nameLabel);
|
||||
nameLayout->addWidget(nameLabel);
|
||||
|
||||
// Add sponsor type indicator
|
||||
if (!sponsorType.isEmpty()) {
|
||||
QLabel *sponsorLabel = new QLabel(sponsorType.name);
|
||||
QString textColor = (sponsorType.level == SponsorType::Platinum ||
|
||||
sponsorType.level == SponsorType::Silver)
|
||||
? "#333"
|
||||
: "white";
|
||||
sponsorLabel->setStyleSheet(QString("font-size: 10px; "
|
||||
"font-weight: bold; "
|
||||
"color: %1; "
|
||||
"background-color: %2; "
|
||||
"border-radius: 4px; "
|
||||
"padding: 2px 6px; "
|
||||
"margin-left: 8px;")
|
||||
.arg(textColor, sponsorType.color));
|
||||
sponsorLabel->setAlignment(Qt::AlignCenter);
|
||||
nameLayout->addWidget(sponsorLabel);
|
||||
}
|
||||
|
||||
nameLayout->addStretch();
|
||||
textLayout->addLayout(nameLayout);
|
||||
|
||||
// App description
|
||||
QLabel *descLabel = new QLabel(description);
|
||||
descLabel->setStyleSheet("font-size: 12px; color: #666;");
|
||||
descLabel->setAlignment(Qt::AlignCenter);
|
||||
descLabel->setAlignment(Qt::AlignLeft);
|
||||
descLabel->setWordWrap(true);
|
||||
textLayout->addWidget(descLabel);
|
||||
|
||||
cardLayout->addStretch();
|
||||
cardLayout->addLayout(textLayout);
|
||||
|
||||
QVBoxLayout *buttonsLayout = new QVBoxLayout();
|
||||
|
||||
// Install button placeholder
|
||||
ZLabel *installLabel = new ZLabel("Install");
|
||||
installLabel->setAlignment(Qt::AlignCenter);
|
||||
installLabel->setStyleSheet("font-size: 12px; color: #007AFF; font-weight: "
|
||||
"bold; background-color: transparent;");
|
||||
installLabel->setCursor(Qt::PointingHandCursor);
|
||||
installLabel->setFixedHeight(30);
|
||||
if (!bundleId.isEmpty()) {
|
||||
ZLabel *installLabel = new ZLabel("Install");
|
||||
installLabel->setAlignment(Qt::AlignCenter);
|
||||
installLabel->setStyleSheet(
|
||||
"font-size: 12px; color: #007AFF; font-weight: "
|
||||
"bold; background-color: transparent;");
|
||||
installLabel->setCursor(Qt::PointingHandCursor);
|
||||
installLabel->setFixedHeight(30);
|
||||
|
||||
ZLabel *downloadIpaLabel = new ZLabel("Download IPA");
|
||||
downloadIpaLabel->setAlignment(Qt::AlignCenter);
|
||||
downloadIpaLabel->setCursor(Qt::PointingHandCursor);
|
||||
buttonsLayout->addStretch();
|
||||
buttonsLayout->addWidget(installLabel);
|
||||
connect(installLabel, &ZLabel::clicked, this,
|
||||
[this, name, bundleId, description]() {
|
||||
onAppCardClicked(name, bundleId, description);
|
||||
});
|
||||
}
|
||||
if (websiteUrl.isEmpty()) {
|
||||
ZLabel *downloadIpaLabel = new ZLabel("Download IPA");
|
||||
downloadIpaLabel->setAlignment(Qt::AlignCenter);
|
||||
downloadIpaLabel->setStyleSheet("font-size: 12px; font-weight: "
|
||||
"bold; background-color: transparent;");
|
||||
downloadIpaLabel->setCursor(Qt::PointingHandCursor);
|
||||
|
||||
connect(installLabel, &ZLabel::clicked, this,
|
||||
[this, name, bundleId, description]() {
|
||||
onAppCardClicked(name, bundleId, description);
|
||||
});
|
||||
|
||||
connect(downloadIpaLabel, &ZLabel::clicked, this,
|
||||
connect(
|
||||
downloadIpaLabel, &ZLabel::clicked, this,
|
||||
[this, name, bundleId]() { onDownloadIpaClicked(name, bundleId); });
|
||||
|
||||
buttonsLayout->addStretch();
|
||||
buttonsLayout->addWidget(installLabel);
|
||||
buttonsLayout->addWidget(downloadIpaLabel);
|
||||
buttonsLayout->addWidget(downloadIpaLabel);
|
||||
} else {
|
||||
ZLabel *websiteLabel = new ZLabel("Website");
|
||||
websiteLabel->setStyleSheet("font-size: 12px; font-weight: "
|
||||
"bold; background-color: transparent;");
|
||||
websiteLabel->setAlignment(Qt::AlignCenter);
|
||||
websiteLabel->setCursor(Qt::PointingHandCursor);
|
||||
|
||||
connect(websiteLabel, &ZLabel::clicked, this, [this, websiteUrl]() {
|
||||
QDesktopServices::openUrl(QUrl(websiteUrl));
|
||||
});
|
||||
buttonsLayout->addWidget(websiteLabel);
|
||||
}
|
||||
|
||||
buttonsLayout->addStretch();
|
||||
|
||||
cardLayout->addLayout(buttonsLayout);
|
||||
@@ -434,7 +753,6 @@ void AppsWidget::onSearchTextChanged() { m_debounceTimer->start(300); }
|
||||
|
||||
void AppsWidget::performSearch()
|
||||
{
|
||||
|
||||
QString searchTerm = m_searchEdit->text().trimmed();
|
||||
if (searchTerm.isEmpty()) {
|
||||
showDefaultApps();
|
||||
@@ -510,7 +828,8 @@ void AppsWidget::onSearchFinished(bool success, const QString &results)
|
||||
QString bundleId = appObj.value("bundleId").toString();
|
||||
QString description = "Version: " + appObj.value("version").toString();
|
||||
|
||||
createAppCard(name, bundleId, description, "", gridLayout, row, col);
|
||||
createAppCard(name, bundleId, description, "", "", gridLayout, row,
|
||||
col);
|
||||
|
||||
col++;
|
||||
if (col >= maxCols) {
|
||||
|
||||
Reference in New Issue
Block a user