Skip to content

Commit b2b13c0

Browse files
committed
+ add model name
1 parent 587280f commit b2b13c0

6 files changed

Lines changed: 282 additions & 11 deletions

File tree

Src/appledb.cpp

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#include "appledb.h"
2+
3+
#include "simplerequest.h"
4+
#include "utils.h"
5+
6+
#include <QDir>
7+
#include <QFile>
8+
#include <QJsonArray>
9+
#include <QJsonDocument>
10+
#include <QJsonObject>
11+
#include <QRegularExpression>
12+
#include <QSaveFile>
13+
14+
AppleDB::AppleDB(QObject* parent)
15+
: QObject(parent)
16+
, m_request(new SimpleRequest())
17+
, m_localFilePath(GetDirectory(DIRECTORY_TYPE::LOCALDATA) + LOCAL_FILE_NAME)
18+
, m_isRefreshing(false)
19+
{
20+
LoadLocal();
21+
}
22+
23+
AppleDB::~AppleDB()
24+
{
25+
delete m_request;
26+
}
27+
28+
void AppleDB::EnsureDownloadedAtLaunch()
29+
{
30+
if (!QFile::exists(m_localFilePath))
31+
RefreshFromNetwork(false);
32+
}
33+
34+
QString AppleDB::ResolveProductType(const QString& productType, const std::function<void(const QString&)>& onResolved)
35+
{
36+
if (productType.isEmpty())
37+
return "";
38+
39+
const QString display = BuildDisplayName(productType);
40+
if (display != productType)
41+
return display;
42+
43+
if (onResolved)
44+
m_pendingCallbacks[productType].append(onResolved);
45+
RefreshFromNetwork(true);
46+
return EstimateSeries(productType);
47+
}
48+
49+
void AppleDB::LoadLocal()
50+
{
51+
QFile file(m_localFilePath);
52+
if (!file.exists())
53+
return;
54+
if (!file.open(QIODevice::ReadOnly))
55+
return;
56+
57+
ParseAndStore(file.readAll(), false);
58+
}
59+
60+
void AppleDB::RefreshFromNetwork(bool force)
61+
{
62+
if (m_isRefreshing)
63+
return;
64+
if (!force && QFile::exists(m_localFilePath))
65+
return;
66+
67+
m_isRefreshing = true;
68+
m_request->Download(REMOTE_URL,
69+
[this](SimpleRequest::RequestState state, int, QNetworkReply::NetworkError error, QByteArray data)
70+
{
71+
if (state != SimpleRequest::RequestState::STATE_FINISH &&
72+
state != SimpleRequest::RequestState::STATE_ERROR)
73+
{
74+
return;
75+
}
76+
77+
if (state == SimpleRequest::RequestState::STATE_FINISH && error == QNetworkReply::NoError)
78+
ParseAndStore(data, true);
79+
80+
m_isRefreshing = false;
81+
ResolvePending();
82+
});
83+
}
84+
85+
bool AppleDB::ParseAndStore(const QByteArray& jsonData, bool persistToDisk)
86+
{
87+
QJsonParseError error;
88+
const QJsonDocument document = QJsonDocument::fromJson(jsonData, &error);
89+
if (error.error != QJsonParseError::NoError || !document.isArray())
90+
return false;
91+
92+
QHash<QString, QString> parsed;
93+
const QJsonArray devices = document.array();
94+
for (const QJsonValue& value : devices)
95+
{
96+
if (!value.isObject())
97+
continue;
98+
99+
const QJsonObject device = value.toObject();
100+
const QString name = device["name"].toString();
101+
if (name.isEmpty())
102+
continue;
103+
104+
const QJsonValue identifierValue = device["identifier"];
105+
if (identifierValue.isArray())
106+
{
107+
for (const QJsonValue& identifier : identifierValue.toArray())
108+
{
109+
const QString productType = identifier.toString();
110+
if (!productType.isEmpty())
111+
parsed[productType] = name;
112+
}
113+
}
114+
else
115+
{
116+
const QString productType = identifierValue.toString();
117+
if (!productType.isEmpty())
118+
parsed[productType] = name;
119+
}
120+
}
121+
122+
if (parsed.isEmpty())
123+
return false;
124+
125+
m_deviceNameByIdentifier = parsed;
126+
if (persistToDisk)
127+
{
128+
QDir().mkpath(GetDirectory(DIRECTORY_TYPE::LOCALDATA));
129+
QSaveFile file(m_localFilePath);
130+
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate))
131+
{
132+
file.write(jsonData);
133+
file.commit();
134+
}
135+
}
136+
return true;
137+
}
138+
139+
QString AppleDB::BuildDisplayName(const QString& productType) const
140+
{
141+
const QString resolved = m_deviceNameByIdentifier.value(productType);
142+
if (resolved.isEmpty())
143+
return productType;
144+
return resolved;
145+
}
146+
147+
QString AppleDB::EstimateSeries(const QString& productType) const
148+
{
149+
QRegularExpressionMatch match = QRegularExpression("^iPhone(\\d+),\\d+$").match(productType);
150+
if (match.hasMatch())
151+
{
152+
const int hardwareSeries = match.captured(1).toInt();
153+
int estimatedSeries = hardwareSeries;
154+
if (hardwareSeries >= 11)
155+
estimatedSeries = hardwareSeries - 1;
156+
else if (hardwareSeries >= 8)
157+
estimatedSeries = hardwareSeries - 2;
158+
159+
return QString("Estimated iPhone %1 series").arg(estimatedSeries);
160+
}
161+
return "Unknown model";
162+
}
163+
164+
void AppleDB::ResolvePending()
165+
{
166+
const auto pendingMap = m_pendingCallbacks;
167+
m_pendingCallbacks.clear();
168+
169+
for (auto it = pendingMap.constBegin(); it != pendingMap.constEnd(); ++it)
170+
{
171+
const QString productType = it.key();
172+
const QString display = BuildDisplayName(productType);
173+
const QString resolved = display == productType ? EstimateSeries(productType) : display;
174+
for (const auto& callback : it.value())
175+
callback(resolved);
176+
}
177+
}

Src/appledb.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#ifndef APPLEDB_H
2+
#define APPLEDB_H
3+
4+
#include <QByteArray>
5+
#include <QHash>
6+
#include <QList>
7+
#include <QObject>
8+
#include <QString>
9+
#include <functional>
10+
11+
class SimpleRequest;
12+
13+
class AppleDB : public QObject
14+
{
15+
Q_OBJECT
16+
17+
public:
18+
explicit AppleDB(QObject* parent = nullptr);
19+
~AppleDB();
20+
21+
void EnsureDownloadedAtLaunch();
22+
QString ResolveProductType(const QString& productType, const std::function<void(const QString&)>& onResolved = nullptr);
23+
24+
private:
25+
static constexpr const char* REMOTE_URL = "https://api.appledb.dev/device/main.json";
26+
static constexpr const char* LOCAL_FILE_NAME = "appledb-main.json";
27+
28+
SimpleRequest* m_request;
29+
QString m_localFilePath;
30+
QHash<QString, QString> m_deviceNameByIdentifier;
31+
QHash<QString, QList<std::function<void(const QString&)>>> m_pendingCallbacks;
32+
bool m_isRefreshing;
33+
34+
void LoadLocal();
35+
void RefreshFromNetwork(bool force);
36+
bool ParseAndStore(const QByteArray& jsonData, bool persistToDisk);
37+
QString BuildDisplayName(const QString& productType) const;
38+
QString EstimateSeries(const QString& productType) const;
39+
void ResolvePending();
40+
};
41+
42+
#endif // APPLEDB_H

Src/mainwindow.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <iostream>
44
#include "utils.h"
55
#include "appinfo.h"
6+
#include "appledb.h"
67
#include "userconfigs.h"
78
#include "crashsymbolicator.h"
89
#include "asyncmanager.h"
@@ -23,6 +24,7 @@ MainWindow::MainWindow(QWidget *parent)
2324
, m_textDialog(new TextViewer(this))
2425
, m_proxyDialog(new ProxyDialog(this))
2526
, m_aboutDialog(new AboutDialog(&m_appInfo, this))
27+
, m_appleDb(new AppleDB(this))
2628
, m_loadingDevice(new LoadingDialog(this))
2729
, m_devicesModel(nullptr)
2830
, m_maxCachedLogs(UserConfigs::Get()->GetData("MaxShownLogs", "1000").toUInt())
@@ -36,6 +38,7 @@ MainWindow::MainWindow(QWidget *parent)
3638
, m_imageMounter(new ImageMounter(this))
3739
{
3840
ui->setupUi(this);
41+
m_appleDb->EnsureDownloadedAtLaunch();
3942

4043
AsyncManager::Get()->Init(4);
4144
QMainWindow::setWindowTitle(m_appInfo->GetFullname());
@@ -193,6 +196,7 @@ MainWindow::~MainWindow()
193196
delete m_imageMounter;
194197
delete m_proxyDialog;
195198
delete m_aboutDialog;
199+
delete m_appleDb;
196200
delete m_loadingDevice;
197201
delete m_loadingCodesign;
198202
delete m_loadingSymbolicate;

Src/mainwindow.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ namespace Ui { class MainWindow; }
2525
QT_END_NAMESPACE
2626

2727
class AppInfo;
28+
class AppleDB;
2829
class MainWindow : public QMainWindow
2930
{
3031
Q_OBJECT
@@ -50,6 +51,7 @@ class MainWindow : public QMainWindow
5051
ProxyDialog *m_proxyDialog;
5152
AboutDialog *m_aboutDialog;
5253
QMutex m_mutex;
54+
AppleDB* m_appleDb;
5355

5456
private slots:
5557
void OnTopSplitterMoved(int pos, int index);

Src/mainwindow.ui

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,18 @@ color: rgb(255, 255, 255);</string>
477477
<verstretch>0</verstretch>
478478
</sizepolicy>
479479
</property>
480+
<property name="minimumSize">
481+
<size>
482+
<width>90</width>
483+
<height>0</height>
484+
</size>
485+
</property>
486+
<property name="maximumSize">
487+
<size>
488+
<width>90</width>
489+
<height>16777215</height>
490+
</size>
491+
</property>
480492
<layout class="QVBoxLayout" name="verticalLayout_6">
481493
<property name="spacing">
482494
<number>6</number>
@@ -494,7 +506,7 @@ color: rgb(255, 255, 255);</string>
494506
<number>0</number>
495507
</property>
496508
<item>
497-
<widget class="QLabel" name="label_5">
509+
<widget class="QLabel" name="label_model">
498510
<property name="sizePolicy">
499511
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
500512
<horstretch>0</horstretch>
@@ -508,12 +520,15 @@ color: rgb(255, 255, 255);</string>
508520
</font>
509521
</property>
510522
<property name="text">
511-
<string>Product Type</string>
523+
<string>Model</string>
524+
</property>
525+
<property name="alignment">
526+
<set>Qt::AlignRight|Qt::AlignVCenter</set>
512527
</property>
513528
</widget>
514529
</item>
515530
<item>
516-
<widget class="QLabel" name="label_6">
531+
<widget class="QLabel" name="label_5">
517532
<property name="sizePolicy">
518533
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
519534
<horstretch>0</horstretch>
@@ -527,7 +542,10 @@ color: rgb(255, 255, 255);</string>
527542
</font>
528543
</property>
529544
<property name="text">
530-
<string>OS Name</string>
545+
<string>Product Type</string>
546+
</property>
547+
<property name="alignment">
548+
<set>Qt::AlignRight|Qt::AlignVCenter</set>
531549
</property>
532550
</widget>
533551
</item>
@@ -548,6 +566,9 @@ color: rgb(255, 255, 255);</string>
548566
<property name="text">
549567
<string>OS Version</string>
550568
</property>
569+
<property name="alignment">
570+
<set>Qt::AlignRight|Qt::AlignVCenter</set>
571+
</property>
551572
</widget>
552573
</item>
553574
<item>
@@ -567,6 +588,9 @@ color: rgb(255, 255, 255);</string>
567588
<property name="text">
568589
<string>CPU Arch</string>
569590
</property>
591+
<property name="alignment">
592+
<set>Qt::AlignRight|Qt::AlignVCenter</set>
593+
</property>
570594
</widget>
571595
</item>
572596
<item>
@@ -586,6 +610,9 @@ color: rgb(255, 255, 255);</string>
586610
<property name="text">
587611
<string>UDID</string>
588612
</property>
613+
<property name="alignment">
614+
<set>Qt::AlignRight|Qt::AlignVCenter</set>
615+
</property>
589616
</widget>
590617
</item>
591618
</layout>
@@ -601,7 +628,7 @@ color: rgb(255, 255, 255);</string>
601628
</property>
602629
<layout class="QVBoxLayout" name="verticalLayout_8">
603630
<property name="spacing">
604-
<number>4</number>
631+
<number>6</number>
605632
</property>
606633
<property name="leftMargin">
607634
<number>0</number>
@@ -616,7 +643,7 @@ color: rgb(255, 255, 255);</string>
616643
<number>0</number>
617644
</property>
618645
<item>
619-
<widget class="QLabel" name="ProductType">
646+
<widget class="QLabel" name="Model">
620647
<property name="text">
621648
<string>....</string>
622649
</property>
@@ -626,7 +653,7 @@ color: rgb(255, 255, 255);</string>
626653
</widget>
627654
</item>
628655
<item>
629-
<widget class="QLabel" name="OSName">
656+
<widget class="QLabel" name="ProductType">
630657
<property name="text">
631658
<string>....</string>
632659
</property>

0 commit comments

Comments
 (0)