diff --git a/CMakeLists.txt b/CMakeLists.txt index 1099c48..372189c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,10 +95,6 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") endif() -set(CMAKE_AUTOMOC ON) -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - set(CXXQT_QTCOMPONENTS Core Gui Qml QuickControls2 QuickTest Widgets Test) if(NOT BUILD_WASM) set(CXXQT_QTCOMPONENTS ${CXXQT_QTCOMPONENTS}) @@ -138,7 +134,7 @@ endif() cxx_qt_import_crate( MANIFEST_PATH src/rust/Cargo.toml CRATES idescriptor_rust_codebase - LOCKED + # LOCKED QT_MODULES Qt::Core Qt::Gui Qt::Qml Qt::QuickControls2 ) @@ -188,13 +184,16 @@ else() endif() file(GLOB PROJECT_SOURCES -src/*.h -src/*.cpp -src/core/helpers/*.cpp -src/core/services/*.cpp -src/base/*.cpp -src/base/*.h +# src/*.h +# src/*.cpp +# src/core/helpers/*.cpp +# src/core/services/*.cpp +# src/base/*.cpp +# src/base/*.h +src/main.cpp +src/constants.h resources.qrc +resources.ui.qrc ) @@ -283,6 +282,7 @@ target_link_libraries(iDescriptor PRIVATE Qt6::Location Qt6::Positioning Qt6::QuickWidgets + Qt6::Qml Qt6::QuickControls2 PkgConfig::SSH ${SSH_LIBRARY} @@ -312,7 +312,6 @@ if(ENABLE_RECOVERY_DEVICE_SUPPORT) endif() target_include_directories(iDescriptor PRIVATE - # Put idevice-rs includes FIRST ${CMAKE_CURRENT_SOURCE_DIR}/lib ${CMAKE_CURRENT_SOURCE_DIR}/lib/zupdater/src ) diff --git a/resources.ui.qrc b/resources.ui.qrc new file mode 100644 index 0000000..618fc86 --- /dev/null +++ b/resources.ui.qrc @@ -0,0 +1,11 @@ + + + src/qml/Main.qml + src/qml/Index.qml + src/qml/Tabs.qml + src/qml/HowToConnect.qml + src/qml/Welcome.qml + src/qml/TabButton.qml + src/qml/Device.qml + + \ No newline at end of file diff --git a/src/constants.h b/src/constants.h new file mode 100644 index 0000000..f25ea37 --- /dev/null +++ b/src/constants.h @@ -0,0 +1,18 @@ +#ifndef CONSTANTS_H +#define CONSTANTS_H + +#include "iDescriptor.h" +#include + +class Constants : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QString REPO_URL READ REPO_URL CONSTANT) +public: + explicit Constants(QObject *parent = nullptr) : QObject(parent) {} + + QString REPO_URL() const { return QStringLiteral(IDESCRIPTOR_REPO_URL); } +}; + +#endif // CONSTANTS_H diff --git a/src/iDescriptor.h b/src/iDescriptor.h index f7b331e..391f323 100644 --- a/src/iDescriptor.h +++ b/src/iDescriptor.h @@ -47,7 +47,7 @@ using u_int64_t = uint64_t; "© 2026 The iDescriptor Project contributors. See AUTHORS for details." #define RECOVERY_CLIENT_CONNECTION_TRIES 3 #define APPLE_VENDOR_ID 0x05ac -#define REPO_URL "https://github.com/iDescriptor/iDescriptor" +#define IDESCRIPTOR_REPO_URL "https://github.com/iDescriptor/iDescriptor" #define SPONSORS_JSON_URL \ "https://raw.githubusercontent.com/iDescriptor/iDescriptor/refs/heads/" \ "main/sponsors.json" @@ -86,13 +86,13 @@ using u_int64_t = uint64_t; #endif // rust codebase -#include "idescriptor_rust_codebase/src/afc2_services.cxxqt.h" -#include "idescriptor_rust_codebase/src/afc_services.cxxqt.h" -#include "idescriptor_rust_codebase/src/hause_arrest.cxxqt.h" -#include "idescriptor_rust_codebase/src/io_manager.cxxqt.h" -#include "idescriptor_rust_codebase/src/lib.cxxqt.h" -#include "idescriptor_rust_codebase/src/screenshot.cxxqt.h" -#include "idescriptor_rust_codebase/src/service_manager.cxxqt.h" +// #include "idescriptor_rust_codebase/src/afc2_services.cxxqt.h" +// #include "idescriptor_rust_codebase/src/afc_services.cxxqt.h" +// #include "idescriptor_rust_codebase/src/hause_arrest.cxxqt.h" +// #include "idescriptor_rust_codebase/src/io_manager.cxxqt.h" +// #include "idescriptor_rust_codebase/src/lib.cxxqt.h" +// #include "idescriptor_rust_codebase/src/screenshot.cxxqt.h" +// #include "idescriptor_rust_codebase/src/service_manager.cxxqt.h" namespace iDescriptor { @@ -233,9 +233,9 @@ struct iDescriptorDevice { iDescriptor::IdeviceConnectionType conn_type; DeviceInfo deviceInfo; unsigned int ios_version; - CXX::ServiceManager *service_manager; - CXX::AfcBackend *afc_backend; - CXX::Afc2Backend *afc2_backend; + QObject *service_manager; + QObject *afc_backend; + QObject *afc2_backend; }; void fullDeviceInfo(const pugi::xml_document &doc, DeviceInfo &d); diff --git a/src/main.cpp b/src/main.cpp index 5298655..feeeb2e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,8 +17,8 @@ * along with this program. If not, see . */ +#include "constants.h" #include "iDescriptor.h" -#include "mainwindow.h" #include "settingsmanager.h" #include #include @@ -32,43 +32,55 @@ #include "platform/windows/win_common.h" #endif +#include +#include +#include +#include +#include +#define FLUENTUI_BUILD_STATIC_LIB 1 + int main(int argc, char *argv[]) { +#ifdef WIN32 + // ::SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); + qputenv("QT_QPA_PLATFORM", "windows:darkmode=2"); +#endif +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + qputenv("QT_QUICK_CONTROLS_STYLE", "Basic"); +#else + qputenv("QT_QUICK_CONTROLS_STYLE", "Default"); +#endif +#ifdef Q_OS_LINUX + // fix bug UOSv20 v-sync does not work + qputenv("QSG_RENDER_LOOP", "basic"); +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL); +#endif +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + QApplication::setHighDpiScaleFactorRoundingPolicy( + Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); +#endif +#endif + QApplication a(argc, argv); QCoreApplication::setOrganizationName("iDescriptor"); QCoreApplication::setApplicationName("iDescriptor"); QCoreApplication::setApplicationVersion(APP_VERSION); if (a.arguments().contains("--reset-settings")) { - SettingsManager::sharedInstance()->clear(); + // SettingsManager::sharedInstance()->clear(); QMessageBox::information(nullptr, "Settings Reset", "All application settings have been reset to " "their default values."); } + QQmlApplicationEngine engine; + #ifdef WIN32 - bool enableMica = !a.arguments().contains("--disable-mica") && - !SettingsManager::sharedInstance()->disableMica(); - if (!enableMica) { - SettingsManager::sharedInstance()->setDisableMica(true); - qDebug() << "Mica effect disabled"; - } - - QApplication::setEffectEnabled(Qt::UI_AnimateCombo, false); - - QOperatingSystemVersion osVersion = QOperatingSystemVersion::current(); - if (enableMica && osVersion >= QOperatingSystemVersion::Windows11) { - QFile styleFile(detectDarkModeWindows() ? ":/resources/win.dark.qcss" - : ":/resources/win.light.qcss"); - if (styleFile.open(QFile::ReadOnly | QFile::Text)) { - const QString style = QString::fromUtf8(styleFile.readAll()) - .arg(COLOR_ACCENT_BLUE.name()); - qDebug() << "Loaded Windows style sheet successfully."; - a.setStyleSheet(style); - } - } else { - qDebug() << "Not applying WinUI stylesheet."; - } - QString appPath = QCoreApplication::applicationDirPath(); QString gstPluginPath = QDir::toNativeSeparators(appPath + "/gstreamer-1.0"); @@ -103,7 +115,26 @@ int main(int argc, char *argv[]) setenv("GST_PLUGIN_SYSTEM_PATH", gstPluginPath.toUtf8().constData(), 1); setenv("GST_PLUGIN_SCANNER", gstPluginScannerPath.toUtf8().constData(), 1); #endif - MainWindow *w = MainWindow::sharedInstance(); - w->show(); + + const QUrl url(QStringLiteral("qrc:/src/qml/Main.qml")); + QObject::connect( + &engine, &QQmlApplicationEngine::objectCreated, &a, + [url](QObject *obj, const QUrl &objUrl) { + if (!obj && url == objUrl) { + QCoreApplication::exit(-1); + } + }, + Qt::QueuedConnection); + +// FIXME: for some reason we have to set this +// dont let this end up in final build +#ifdef WIN32 + engine.addImportPath("C:/Qt/6.8.3/mingw_64/qml"); +#endif + Constants constants; + + engine.rootContext()->setContextProperty("CONSTANTS", &constants); + engine.load(url); + return a.exec(); } diff --git a/src/platform/windows/blur_imp.cpp b/src/platform/windows/blur_imp.cpp index 32d7b7b..78f84b2 100644 --- a/src/platform/windows/blur_imp.cpp +++ b/src/platform/windows/blur_imp.cpp @@ -71,44 +71,44 @@ void enableMica(HWND hwnd) { if (!hwnd) return; - SettingsManager *sm = SettingsManager::sharedInstance(); - WIN_BACKDROP type = sm->winBackdropType(); - MARGINS margins = {-1}; - DwmExtendFrameIntoClientArea(hwnd, &margins); + // SettingsManager *sm = SettingsManager::sharedInstance(); + // WIN_BACKDROP type = sm->winBackdropType(); + // MARGINS margins = {-1}; + // DwmExtendFrameIntoClientArea(hwnd, &margins); - DWORD build = 0; - RTL_OSVERSIONINFOW rovi = {0}; - rovi.dwOSVersionInfoSize = sizeof(rovi); + // DWORD build = 0; + // RTL_OSVERSIONINFOW rovi = {0}; + // rovi.dwOSVersionInfoSize = sizeof(rovi); - using RtlGetVersionPtr = LONG(WINAPI *)(PRTL_OSVERSIONINFOW); - HMODULE ntdll = GetModuleHandleW(L"ntdll.dll"); - if (ntdll) { - auto pRtlGetVersion = reinterpret_cast( - GetProcAddress(ntdll, "RtlGetVersion")); - if (pRtlGetVersion && pRtlGetVersion(&rovi) == 0) { - build = rovi.dwBuildNumber; - } - } + // using RtlGetVersionPtr = LONG(WINAPI *)(PRTL_OSVERSIONINFOW); + // HMODULE ntdll = GetModuleHandleW(L"ntdll.dll"); + // if (ntdll) { + // auto pRtlGetVersion = reinterpret_cast( + // GetProcAddress(ntdll, "RtlGetVersion")); + // if (pRtlGetVersion && pRtlGetVersion(&rovi) == 0) { + // build = rovi.dwBuildNumber; + // } + // } - if (build >= 22523) { - DwmSetWindowAttribute(hwnd, DWMWA_SYSTEMBACKDROP_TYPE, &type, - sizeof(type)); - } else if (build >= 22000) { - // Undocumented old method - BOOL mica = TRUE; - DwmSetWindowAttribute(hwnd, DWMWA_MICA_EFFECT, &mica, sizeof(mica)); - } + // if (build >= 22523) { + // DwmSetWindowAttribute(hwnd, DWMWA_SYSTEMBACKDROP_TYPE, &type, + // sizeof(type)); + // } else if (build >= 22000) { + // // Undocumented old method + // BOOL mica = TRUE; + // DwmSetWindowAttribute(hwnd, DWMWA_MICA_EFFECT, &mica, sizeof(mica)); + // } } void setupWinWindow(QWidget *window) { - QOperatingSystemVersion osVersion = QOperatingSystemVersion::current(); - if (osVersion < QOperatingSystemVersion::Windows11 || - SettingsManager::sharedInstance()->disableMica()) - return; - window->setAttribute(Qt::WA_TranslucentBackground); - HWND hwnd = reinterpret_cast(window->winId()); - enableMica(hwnd); + // QOperatingSystemVersion osVersion = QOperatingSystemVersion::current(); + // if (osVersion < QOperatingSystemVersion::Windows11 || + // SettingsManager::sharedInstance()->disableMica()) + // return; + // window->setAttribute(Qt::WA_TranslucentBackground); + // HWND hwnd = reinterpret_cast(window->winId()); + // enableMica(hwnd); /* normally we had plans to enable acrylic on win 10 but since it's diff --git a/src/qml/Device.qml b/src/qml/Device.qml new file mode 100644 index 0000000..bffb5d2 --- /dev/null +++ b/src/qml/Device.qml @@ -0,0 +1,56 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 +import "." +import com.kdab.cxx_qt.demo 1.0 + +Item { + id: root + property ListModel devices: ListModel {} + + property bool showWelcomePage : true + readonly property Core core: Core {} + + Component.onCompleted: { + root.core.init() + } + + Connections { + target: root.core + + function onDevice_event(eventType, udid, info) { + console.log("Device event:", eventType, udid, info) + root.showWelcomePage = false; + if (eventType === 1) { + // Use append to add items to the ListModel + devices.append({ udid: udid, info: info }) + } + } + } + + Repeater { + model: devices + delegate: Label { + text: model.info + font.pixelSize: 16 + padding: 10 + Layout.fillWidth: true + //MouseArea { + // anchors.fill: parent + // onClicked: { + // root.currentIndex = index + 1 + // root.showWelcomePage = false + // } + //} + } + } + + + Welcome { + id: welcomePage + visible : showWelcomePage + Layout.fillWidth: true + Layout.fillHeight: true + } + +} diff --git a/src/qml/HowToConnect.qml b/src/qml/HowToConnect.qml new file mode 100644 index 0000000..5667b78 --- /dev/null +++ b/src/qml/HowToConnect.qml @@ -0,0 +1,207 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +Dialog { + id: dlg + modal: true + focus: true + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside + + width: 560 + height: 560 + + property int currentIndex: 0 + property bool loading: true + + onOpened: { + loading = true + currentIndex = 0 + loadTimer.restart() + } + + Timer { + id: loadTimer + interval: 500 + repeat: false + onTriggered: dlg.loading = false + } + + function updateNav() { + prevBtn.enabled = dlg.currentIndex > 0 + nextBtn.enabled = dlg.currentIndex < (stack.count - 1) + } + + onCurrentIndexChanged: updateNav() + Component.onCompleted: updateNav() + + background: Rectangle { + radius: 10 + color: palette.window + border.color: Qt.rgba(0, 0, 0, 0.12) + border.width: 1 + } + + contentItem: Item { + anchors.fill: parent + + ColumnLayout { + anchors.fill: parent + anchors.margins: 16 + spacing: 12 + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + + StackLayout { + id: stack + anchors.fill: parent + currentIndex: dlg.currentIndex + + // Page 1 + Item { + ColumnLayout { + anchors.fill: parent + spacing: 10 + + Item { Layout.fillHeight: true } + + Text { + Layout.fillWidth: true + text: "Connect your device" + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + font.pixelSize: 16 + font.bold: true + color: palette.text + } + + Image { + Layout.alignment: Qt.AlignHCenter + source: "qrc:/resources/connect.png" + fillMode: Image.PreserveAspectFit + smooth: true + mipmap: true + Layout.preferredWidth: 200 + Layout.preferredHeight: 200 + } + + Item { Layout.fillHeight: true } + } + } + + // Page 2 + Item { + ColumnLayout { + anchors.fill: parent + spacing: 10 + + Item { Layout.fillHeight: true } + + Text { + Layout.fillWidth: true + text: "Accept the pairing dialog" + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + font.pixelSize: 16 + font.bold: true + color: palette.text + } + + Image { + Layout.alignment: Qt.AlignHCenter + source: "qrc:/resources/trust.png" + fillMode: Image.PreserveAspectFit + smooth: true + mipmap: true + Layout.preferredWidth: 200 + Layout.preferredHeight: 200 + } + + Item { Layout.fillHeight: true } + } + } + + // Page 3 + Item { + ColumnLayout { + anchors.fill: parent + spacing: 10 + + Item { Layout.fillHeight: true } + + Text { + Layout.fillWidth: true + text: { + if (Qt.platform.os === "windows") + return "You can now unplug the device. iDescriptor will connect to it automatically (requires iOS 15 or later and the Bonjour service)." + if (Qt.platform.os === "linux") + return "You can now unplug the device. iDescriptor will connect to it automatically (requires iOS 15 or later and the Avahi daemon)." + return "You can now unplug the device. iDescriptor will connect to it automatically (requires iOS 15 or later)." + } + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + font.pixelSize: 16 + font.bold: true + color: palette.text + } + + Image { + Layout.alignment: Qt.AlignHCenter + source: "qrc:/resources/ios-version.png" + fillMode: Image.PreserveAspectFit + smooth: true + mipmap: true + Layout.preferredWidth: 200 + Layout.preferredHeight: 200 + } + + Item { Layout.fillHeight: true } + } + } + } + + Rectangle { + anchors.fill: parent + visible: dlg.loading + color: Qt.rgba(0, 0, 0, 0.06) + + BusyIndicator { + anchors.centerIn: parent + running: dlg.loading + } + } + } + + RowLayout { + Layout.fillWidth: true + spacing: 10 + + Item { Layout.fillWidth: true } + + Button { + id: prevBtn + text: "Previous" + icon.source: "qrc:/resources/icons/MaterialSymbolsArrowLeftAlt.png" + Layout.preferredWidth: 48 + onClicked: { + if (dlg.currentIndex > 0) dlg.currentIndex -= 1 + } + } + + Button { + id: nextBtn + text: "Next" + icon.source: "qrc:/resources/icons/MaterialSymbolsArrowRightAlt.png" + Layout.preferredWidth: 48 + onClicked: { + if (dlg.currentIndex < stack.count - 1) dlg.currentIndex += 1 + } + } + + Item { Layout.fillWidth: true } + } + } + } +} \ No newline at end of file diff --git a/src/qml/Index.qml b/src/qml/Index.qml new file mode 100644 index 0000000..d5b5fac --- /dev/null +++ b/src/qml/Index.qml @@ -0,0 +1,60 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import FluentUI 1.0 +import QtQuick.Layouts 1.15 +import "." + +FluWindow { + + id:window + title: "iDescriptor" + width: 1000 + height: 668 + minimumWidth: 668 + minimumHeight: 320 + launchMode: FluWindowType.SingleTask + fitsAppBarWindows: true + property int currentIndex: 0 + + appBar: FluAppBar { + height: 28 + showDark: true + z: 7 + + RowLayout{ + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.topMargin: 10 + spacing: 0 + TabButton { + text: qsTr("iDevice") + onClicked: currentIndex = 0 + active: currentIndex == 0 + } + + TabButton { + text: qsTr("Apps") + onClicked: currentIndex = 1 + active: currentIndex == 1 + } + TabButton { + text: qsTr("Toolbox") + onClicked: currentIndex = 2 + active: currentIndex == 2 + } + TabButton { + text: qsTr("Jailbroken") + onClicked: currentIndex = 3 + active: currentIndex == 3 + } + } + } + + + Tabs { + currentIndex: window.currentIndex + anchors.fill: parent + anchors.topMargin: appBar.height + } +} diff --git a/src/qml/Main.qml b/src/qml/Main.qml new file mode 100644 index 0000000..183a69a --- /dev/null +++ b/src/qml/Main.qml @@ -0,0 +1,50 @@ +import QtQuick 2.15 +import QtQuick.Window 2.15 +// import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 +import FluentUI 1.0 + +FluLauncher { + id: app + // Connections{ + // target: FluTheme + // function onDarkModeChanged(){ + // SettingsHelper.saveDarkMode(FluTheme.darkMode) + // } + // } + // Connections{ + // target: FluApp + // function onUseSystemAppBarChanged(){ + // SettingsHelper.saveUseSystemAppBar(FluApp.useSystemAppBar) + // } + // } + // Connections{ + // target: TranslateHelper + // function onCurrentChanged(){ + // SettingsHelper.saveLanguage(TranslateHelper.current) + // } + // } + Component.onCompleted: { + // Network.openLog = false + // Network.setInterceptor(function(param){ + // param.addHeader("Token","000000000000000000000") + // }) + FluApp.init(app,Qt.locale()) + // FluApp.windowIcon = "qrc:/example/res/image/favicon.ico" + // FluApp.useSystemAppBar = SettingsHelper.getUseSystemAppBar() + FluApp.useSystemAppBar = false + // FluTheme.darkMode = SettingsHelper.getDarkMode() + FluTheme.darkMode = false + FluTheme.animationEnabled = true + FluRouter.routes = { + "/":"qrc:/src/qml/Index.qml", + } + var args = Qt.application.arguments + if(args.length>=2 && args[1].startsWith("-crashed=")){ + FluRouter.navigate("/crash",{crashFilePath:args[1].replace("-crashed=","")}) + }else{ + FluRouter.navigate("/") + } + } + +} diff --git a/src/qml/TabButton.qml b/src/qml/TabButton.qml new file mode 100644 index 0000000..aa11211 --- /dev/null +++ b/src/qml/TabButton.qml @@ -0,0 +1,22 @@ +import QtQuick 2.15 +import QtQuick.Controls +import QtQuick.Layouts + +Button { + id: btn + property bool active: false + + contentItem : Text { + text : btn.text + color : btn.active ? "#888888" : "red" + font.pixelSize: 22 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + Layout.fillWidth: true + Layout.fillHeight: true + background: Rectangle { + color : "transparent" + } +} diff --git a/src/qml/Tabs.qml b/src/qml/Tabs.qml new file mode 100644 index 0000000..61d4360 --- /dev/null +++ b/src/qml/Tabs.qml @@ -0,0 +1,28 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 +import "." +import com.kdab.cxx_qt.demo 1.0 + +Item { + id: root + anchors.fill: parent + property int currentIndex : 0 + + + Device { + id : device + visible : currentIndex == 0 + opacity: root.currentIndex === 0 ? 1 : 0 + property real slideY: root.currentIndex === 0 ? 0 : 20 + transform: Translate { y: device.slideY } + + Behavior on opacity { + NumberAnimation { duration: 167; easing.type: Easing.OutCubic } + } + Behavior on slideY { + NumberAnimation { duration: 167; easing.type: Easing.OutCubic } + } + } + +} diff --git a/src/qml/Welcome.qml b/src/qml/Welcome.qml new file mode 100644 index 0000000..e73df3b --- /dev/null +++ b/src/qml/Welcome.qml @@ -0,0 +1,163 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +Item { + id: root + anchors.fill: parent + + // FIXME: theming + property color linkColor: "#3b82f6" + + + ColumnLayout { + id: mainLayout + anchors.fill: parent + spacing: 0 + + Item { Layout.preferredHeight: 10 } + + Item { Layout.fillHeight: true } + + Text { + id: title + Layout.fillWidth: true + text: "Welcome to iDescriptor" + horizontalAlignment: Text.AlignHCenter + font.pixelSize: 28 + font.weight: Font.DemiBold + wrapMode: Text.WordWrap + color: palette.text + } + + Item { Layout.preferredHeight: 6 } + + Text { + id: subtitle + Layout.fillWidth: true + text: "Open-Source & Free" + horizontalAlignment: Text.AlignHCenter + font.pixelSize: 10 + font.weight: Font.Normal + wrapMode: Text.WordWrap + color: palette.text + } + + Item { Layout.preferredHeight: 12 } + + RowLayout { + id: imageAndWirelessDevicesLayout + Layout.alignment: Qt.AlignHCenter + spacing: 75 + + Image { + id: connectImage + source: "qrc:/resources/connect.png" + fillMode: Image.PreserveAspectFit + mipmap: true + smooth: true + + sourceSize.width: 0 + sourceSize.height: 0 + Layout.preferredWidth: implicitWidth + Layout.preferredHeight: implicitHeight + } + + ColumnLayout { + id: explorerWithInstructionLayout + spacing: 12 + + // FIXME: implement + Rectangle { + Layout.preferredWidth: 360 + Layout.preferredHeight: 180 + radius: 8 + color: "#1e40af" // blue + border.color: "#0b2a7a" + border.width: 1 + + Text { + anchors.centerIn: parent + text: "NetworkDevicesToConnectWidget" + color: "white" + font.pixelSize: 14 + font.weight: Font.DemiBold + } + } + + Text { + id: howToConnectLink + Layout.alignment: Qt.AlignHCenter + text: "How to connect a wireless device?" + color: root.linkColor + font.pixelSize: 12 + font.weight: Font.DemiBold + wrapMode: Text.NoWrap + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + onClicked: root.howToConnectRequested() + } + } + + Item { Layout.preferredHeight: 20 } + } + } + + Item { Layout.preferredHeight: 10 } + + Text { + id: instruction + Layout.fillWidth: true + text: "Connect an iDevice to get started" + horizontalAlignment: Text.AlignHCenter + font.pixelSize: 14 + wrapMode: Text.WordWrap + color: palette.text + } + + Item { Layout.preferredHeight: 10 } + + Text { + id: githubLink + Layout.alignment: Qt.AlignHCenter + text: "Found an issue? Report it on GitHub" + color: root.linkColor + font.pixelSize: 12 + font.weight: Font.DemiBold + wrapMode: Text.NoWrap + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + onClicked: Qt.openUrlExternally(CONSTANTS.REPO_URL) + } + } + + Item { Layout.preferredHeight: 10 } + + // FIXME: implement + Rectangle { + Layout.alignment: Qt.AlignHCenter + visible: Qt.platform.os !== "osx" + Layout.preferredWidth: 520 + Layout.preferredHeight: 90 + radius: 8 + color: "#b91c1c" // red + border.color: "#7f1d1d" + border.width: 1 + + Text { + anchors.centerIn: parent + text: "DiagnoseWidget" + color: "white" + font.pixelSize: 14 + font.weight: Font.DemiBold + } + } + + // bottom stretch + Item { Layout.fillHeight: true } + } +} diff --git a/src/rust/build.rs b/src/rust/build.rs index 3e73a93..7b9ba57 100644 --- a/src/rust/build.rs +++ b/src/rust/build.rs @@ -1,13 +1,10 @@ -use cxx_qt_build::CxxQtBuilder; +use cxx_qt_build::{CxxQtBuilder, QmlModule}; fn main() { - CxxQtBuilder::new() - .file("src/lib.rs") - .file("src/afc_services.rs") - .file("src/afc2_services.rs") - .file("src/service_manager.rs") - .file("src/screenshot.rs") - .file("src/hause_arrest.rs") - .file("src/io_manager.rs") - .build(); -} + CxxQtBuilder::new_qml_module( + QmlModule::new("com.kdab.cxx_qt.demo").qml_file("../qml/Tabs.qml"), + ) + .qt_module("Qml") + .files(["src/lib.rs","src/afc_services.rs","src/afc2_services.rs","src/service_manager.rs","src/screenshot.rs","src/hause_arrest.rs","src/io_manager.rs"]) + .build(); +} \ No newline at end of file diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index 449252d..c9d8839 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -79,9 +79,8 @@ where rx.recv().expect("Tokio runtime worker panicked") } -#[cxx_qt::bridge(namespace = "CXX")] +#[cxx_qt::bridge] mod qobject { - #[namespace = ""] unsafe extern "C++" { include!("cxx-qt-lib/qstring.h"); include!("cxx-qt-lib/qlist.h"); @@ -93,6 +92,7 @@ mod qobject { extern "RustQt" { #[qobject] + #[qml_element] type Core = super::RCore; #[qinvokable]