diff --git a/CMakeLists.txt b/CMakeLists.txt
index a473410..43e4bc1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -22,17 +22,18 @@ if(WIN32)
set(PKG_CONFIG_EXECUTABLE "C:/msys64/mingw64/bin/pkg-config.exe")
list(APPEND CMAKE_PREFIX_PATH "C:/lxqt")
set(CUSTOM_LIB_PATH "C:/msys64/mingw64/lib")
- set(CUSTOM_BIN_PATH "C:/msys64/mingw64/bin")
set(CUSTOM_INCLUDE_PATH "C:/msys64/mingw64/include")
set(CUSTOM_PKGCONFIG_PATH "C:/msys64/mingw64/lib/pkgconfig")
- # Use Windows path separator for environment variables
set(ENV{PKG_CONFIG_PATH} "${CUSTOM_PKGCONFIG_PATH};$ENV{PKG_CONFIG_PATH}")
-else()
+elseif(APPLE)
set(CUSTOM_LIB_PATH "/usr/local/lib")
set(CUSTOM_INCLUDE_PATH "/usr/local/include")
set(CUSTOM_PKGCONFIG_PATH "/usr/local/lib/pkgconfig")
- # Use Unix path separator for environment variables
set(ENV{PKG_CONFIG_PATH} "${CUSTOM_PKGCONFIG_PATH}:$ENV{PKG_CONFIG_PATH}")
+else ()
+ set(CUSTOM_LIB_PATH "/usr/local/lib")
+ set(CUSTOM_PKGCONFIG_PATH "/usr/local/lib/pkgconfig")
+ set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${CUSTOM_PKGCONFIG_PATH}")
endif()
include_directories(${CUSTOM_INCLUDE_PATH})
@@ -80,24 +81,34 @@ if(WIN32)
message(STATUS "Found Qt bin directory: ${QT_BIN_PATH}")
endif()
+# Define library search behavior based on platform
+if(LINUX)
+ # On Linux (AUR builds), let CMake search default system paths first.
+ # The custom path /usr/local/lib will be checked if it's in the default search paths.
+ set(CUSTOM_FIND_LIB_ARGS "")
+else()
+ # On other platforms, only search the custom path for our specific libraries.
+ set(CUSTOM_FIND_LIB_ARGS
+ PATHS ${CUSTOM_LIB_PATH}
+ NO_DEFAULT_PATH
+ )
+endif()
+
find_library(IMOBILEDEVICE_LIBRARY
NAMES imobiledevice-1.0
- PATHS ${CUSTOM_LIB_PATH}
- NO_DEFAULT_PATH
+ ${CUSTOM_FIND_LIB_ARGS}
REQUIRED
)
find_library(IMOBILEDEVICE_GLUE_LIBRARY
NAMES imobiledevice-glue-1.0
- PATHS ${CUSTOM_LIB_PATH}
- NO_DEFAULT_PATH
+ ${CUSTOM_FIND_LIB_ARGS}
REQUIRED
)
find_library(TATSU_LIBRARY
NAMES tatsu
- PATHS ${CUSTOM_LIB_PATH}
- NO_DEFAULT_PATH
+ ${CUSTOM_FIND_LIB_ARGS}
REQUIRED
)
@@ -120,8 +131,7 @@ endif()
find_library(USBMUXD_LIBRARY
NAMES usbmuxd-2.0
- PATHS ${CUSTOM_LIB_PATH}
- NO_DEFAULT_PATH
+ ${CUSTOM_FIND_LIB_ARGS}
REQUIRED
)
@@ -130,17 +140,8 @@ if(WIN32)
find_library(SSL_LIBRARY NAMES ssl PATHS C:/msys64/mingw64/lib REQUIRED)
find_library(CRYPTO_LIBRARY NAMES crypto PATHS C:/msys64/mingw64/lib REQUIRED)
else()
- find_library(SSL_LIBRARY
- NAMES ssl
- PATHS /usr/local/lib /usr/lib /usr/lib/x86_64-linux-gnu
- REQUIRED
- )
-
- find_library(CRYPTO_LIBRARY
- NAMES crypto
- PATHS /usr/local/lib /usr/lib /usr/lib/x86_64-linux-gnu
- REQUIRED
- )
+ find_library(SSL_LIBRARY NAMES ssl REQUIRED)
+ find_library(CRYPTO_LIBRARY NAMES crypto REQUIRED)
endif()
# Add libssh for SSH connections
@@ -322,10 +323,29 @@ set_target_properties(iDescriptor PROPERTIES
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
# Control library search order - system libs first, then /usr/local/lib
- INSTALL_RPATH "/usr/local/lib:/usr/lib/x86_64-linux-gnu:/usr/lib:$ORIGIN"
- # INSTALL_RPATH "/usr/local/lib:/usr/lib/"
+ INSTALL_RPATH "/usr/lib/x86_64-linux-gnu:/usr/lib:/usr/local/lib:$ORIGIN"
BUILD_WITH_INSTALL_RPATH TRUE
)
+if (UNIX AND NOT APPLE)
+# Add install rules for the project
+include(GNUInstallDirs)
+
+# Install the main executable
+install(TARGETS iDescriptor
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+)
+
+# Install the .desktop file
+install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/iDescriptor.desktop
+ DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
+)
+
+# Install the application icon
+install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/icons/app-icon/icon.png
+ RENAME iDescriptor.png
+ DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/256x256/apps
+)
+endif()
include(GNUInstallDirs)
diff --git a/resources.qrc b/resources.qrc
index 21645c9..5d6e357 100644
--- a/resources.qrc
+++ b/resources.qrc
@@ -31,6 +31,9 @@
resources/icons/MaterialSymbolsAndroidWifi3BarPlus.png
resources/icons/IconParkTwotoneMoreTwo.png
resources/icons/BxBxsTerminal.png
+ resources/icons/ClarityEyeHideLine.png
+ resources/icons/ClarityEyeLine.png
+ resources/icons/MaterialSymbolsLightImageOutlineSharp.png
qml/MapView.qml
resources/iphone.png
resources/ios-wallpapers/iphone-ios4.png
diff --git a/resources/icons/ClarityEyeHideLine.png b/resources/icons/ClarityEyeHideLine.png
new file mode 100644
index 0000000..f3b8280
Binary files /dev/null and b/resources/icons/ClarityEyeHideLine.png differ
diff --git a/resources/icons/ClarityEyeLine.png b/resources/icons/ClarityEyeLine.png
new file mode 100644
index 0000000..a60e450
Binary files /dev/null and b/resources/icons/ClarityEyeLine.png differ
diff --git a/resources/icons/MaterialSymbolsLightImageOutlineSharp.png b/resources/icons/MaterialSymbolsLightImageOutlineSharp.png
new file mode 100644
index 0000000..8efacb8
Binary files /dev/null and b/resources/icons/MaterialSymbolsLightImageOutlineSharp.png differ
diff --git a/src/core/services/init_device.cpp b/src/core/services/init_device.cpp
index 3076d06..7bdc40f 100644
--- a/src/core/services/init_device.cpp
+++ b/src/core/services/init_device.cpp
@@ -104,7 +104,7 @@ void parseOldDevice(PlistNavigator &ioreg, DeviceInfo &d)
int healthPercent =
(designCapacity != 0) ? (maxCapacity * 100) / designCapacity : 0;
healthPercent = std::min(healthPercent, 100);
- d.batteryInfo.health = QString::number(healthPercent) + "%";
+ d.batteryInfo.health = QString::number(qBound(0, healthPercent, 100)) + "%";
d.batteryInfo.cycleCount = cycleCount;
d.batteryInfo.serialNumber = !batterySerialNumber.empty()
? batterySerialNumber
@@ -322,7 +322,9 @@ DeviceInfo fullDeviceInfo(const pugi::xml_document &doc,
// seems to be to the most accurate way to get health
d.batteryInfo.health =
- QString::number((maxCapacity * 100) / designCapacity) + "%";
+ QString::number(
+ qBound(0, (maxCapacity * 100) / designCapacity, 100)) +
+ "%";
d.batteryInfo.cycleCount = cycleCount;
d.batteryInfo.serialNumber = !batterySerialNumber.empty()
? batterySerialNumber
diff --git a/src/deviceinfowidget.cpp b/src/deviceinfowidget.cpp
index 0e6f37f..243cb3e 100644
--- a/src/deviceinfowidget.cpp
+++ b/src/deviceinfowidget.cpp
@@ -24,6 +24,7 @@
#include "iDescriptor-ui.h"
#include "iDescriptor.h"
#include "infolabel.h"
+#include "privateinfolabel.h"
#include "toolboxwidget.h"
#include
#include
@@ -283,6 +284,24 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent)
createValueLabel(QString::fromStdString(
device->deviceInfo.productionDevice ? "Yes" : "No"))});
+ // Serial Number with privacy
+ if (!device->deviceInfo.serialNumber.empty()) {
+ infoItems.append(
+ {"Serial Number:",
+ new PrivateInfoLabel(
+ QString::fromStdString(device->deviceInfo.serialNumber),
+ this)});
+ }
+
+ // IMEI with privacy (Mobile Equipment Identifier)
+ if (!device->deviceInfo.mobileEquipmentIdentifier.empty()) {
+ infoItems.append(
+ {"IMEI:", new PrivateInfoLabel(
+ QString::fromStdString(
+ device->deviceInfo.mobileEquipmentIdentifier),
+ this)});
+ }
+
// Distribute items into the grid
int numRows = (infoItems.size() + 1) / 2;
for (int i = 0; i < numRows; ++i) {
diff --git a/src/infolabel.cpp b/src/infolabel.cpp
index 76f72bb..4c604b2 100644
--- a/src/infolabel.cpp
+++ b/src/infolabel.cpp
@@ -75,3 +75,5 @@ void InfoLabel::restoreOriginalText()
setStyleSheet("QLabel:hover { background-color: rgba(255, 255, 255, 0.1); "
"border-radius: 2px; }");
}
+
+void InfoLabel::setOriginalText(const QString &text) { m_originalText = text; }
diff --git a/src/infolabel.h b/src/infolabel.h
index 01bc7fe..6a6d723 100644
--- a/src/infolabel.h
+++ b/src/infolabel.h
@@ -31,6 +31,9 @@ public:
explicit InfoLabel(const QString &text = QString(),
QWidget *parent = nullptr);
+ // Allow updating the original text (useful for PrivateInfoLabel)
+ void setOriginalText(const QString &text);
+
protected:
void mousePressEvent(QMouseEvent *event) override;
void enterEvent(QEnterEvent *event);
diff --git a/src/privateinfolabel.cpp b/src/privateinfolabel.cpp
new file mode 100644
index 0000000..6c7c9bc
--- /dev/null
+++ b/src/privateinfolabel.cpp
@@ -0,0 +1,68 @@
+/*
+ * iDescriptor: A free and open-source idevice management tool.
+ *
+ * Copyright (C) 2025 Uncore
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+#include "privateinfolabel.h"
+
+PrivateInfoLabel::PrivateInfoLabel(const QString &fullText, QWidget *parent)
+ : QWidget(parent), m_fullText(fullText), m_isVisible(false)
+{
+ m_maskedText = getMaskedText(fullText);
+
+ QHBoxLayout *layout = new QHBoxLayout(this);
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(5);
+
+ m_textLabel = new InfoLabel(m_maskedText, this);
+ layout->addWidget(m_textLabel);
+
+ m_toggleButton = new ZIconWidget(
+ QIcon(":/resources/icons/ClarityEyeHideLine.png"), "Show", this);
+ m_toggleButton->setIconSize(QSize(20, 20));
+ connect(m_toggleButton, &ZIconWidget::clicked, this,
+ &PrivateInfoLabel::toggleVisibility);
+ layout->addWidget(m_toggleButton);
+
+ layout->addStretch();
+}
+
+QString PrivateInfoLabel::getMaskedText(const QString &text)
+{
+ if (text.length() <= 4) {
+ return QString("*").repeated(text.length());
+ }
+ // Show first 4 characters, hide the rest
+ return text.left(4) + QString("*").repeated(text.length() - 4);
+}
+
+void PrivateInfoLabel::toggleVisibility()
+{
+ m_isVisible = !m_isVisible;
+ if (m_isVisible) {
+ m_textLabel->setText(m_fullText);
+ m_textLabel->setOriginalText(m_fullText);
+ m_toggleButton->setIcon(QIcon(":/resources/icons/ClarityEyeLine.png"));
+ m_toggleButton->setToolTip("Hide");
+ } else {
+ m_textLabel->setText(m_maskedText);
+ m_textLabel->setOriginalText(m_fullText);
+ m_toggleButton->setIcon(
+ QIcon(":/resources/icons/ClarityEyeHideLine.png"));
+ m_toggleButton->setToolTip("Show");
+ }
+}
diff --git a/src/privateinfolabel.h b/src/privateinfolabel.h
new file mode 100644
index 0000000..3ef5f92
--- /dev/null
+++ b/src/privateinfolabel.h
@@ -0,0 +1,49 @@
+/*
+ * iDescriptor: A free and open-source idevice management tool.
+ *
+ * Copyright (C) 2025 Uncore
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef PRIVATEINFOLABEL_H
+#define PRIVATEINFOLABEL_H
+
+#include "iDescriptor-ui.h"
+#include "infolabel.h"
+#include
+#include
+
+class PrivateInfoLabel : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit PrivateInfoLabel(const QString &fullText,
+ QWidget *parent = nullptr);
+
+private slots:
+ void toggleVisibility();
+
+private:
+ QString m_fullText;
+ QString m_maskedText;
+ bool m_isVisible;
+ InfoLabel *m_textLabel;
+ ZIconWidget *m_toggleButton;
+
+ QString getMaskedText(const QString &text);
+};
+
+#endif // PRIVATEINFOLABEL_H