From 813b84482e3e6abd45dede1ed177f520a196b82b Mon Sep 17 00:00:00 2001 From: Macitron <117962989+Macitron@users.noreply.github.com> Date: Mon, 5 Oct 2026 21:27:44 -0700 Subject: [PATCH 1/8] Platform selection scaffolding - created UI page - created "Platform" installer KV --- .../meta/installscript.qs | 24 ++++++ .../meta/package.xml | 1 + .../meta/platformSelection.ui | 74 +++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 installer/packages/com.committeeofzero.installer/meta/platformSelection.ui diff --git a/installer/packages/com.committeeofzero.installer/meta/installscript.qs b/installer/packages/com.committeeofzero.installer/meta/installscript.qs index d4c8f80..839bca1 100644 --- a/installer/packages/com.committeeofzero.installer/meta/installscript.qs +++ b/installer/packages/com.committeeofzero.installer/meta/installscript.qs @@ -15,6 +15,30 @@ const targetChooserImpactoMobileCallback = () => Component.prototype.chooseTarge function Component() { installer.wizardPageInsertionRequested.connect(this, Component.prototype.onWizardPageInsertionRequested); installer.wizardPageRemovalRequested.connect(this, Component.prototype.onWizardPageRemovalRequested); + + // Select platform to install on + installer.setValue("Platform", "desktop"); + + if (!installer.isInstaller()) return; + + if (installer.addWizardPage(component, "PlatformSelection", QInstaller.ComponentSelection)) { + const widget = gui.pageWidgetByObjectName("DynamicPlatformSelection"); + widget.platformAndroid.toggled.connect(this, checked => { + if (checked) { + installer.setValue("Platform", "android"); + } + }); + widget.platformDesktop.toggled.connect(this, checked => { + if (checked) { + installer.setValue("Platform", "desktop"); + } + }); + widget.platformSwitch.toggled.connect(this, checked => { + if (checked) { + installer.setValue("Platform", "switch"); + } + }); + } } Component.prototype.isDefault = function () { diff --git a/installer/packages/com.committeeofzero.installer/meta/package.xml b/installer/packages/com.committeeofzero.installer/meta/package.xml index b7325fa..b100053 100644 --- a/installer/packages/com.committeeofzero.installer/meta/package.xml +++ b/installer/packages/com.committeeofzero.installer/meta/package.xml @@ -10,6 +10,7 @@ selectionValidation.ui targetDirectories.ui targetDirectoriesMobile.ui + platformSelection.ui \ No newline at end of file diff --git a/installer/packages/com.committeeofzero.installer/meta/platformSelection.ui b/installer/packages/com.committeeofzero.installer/meta/platformSelection.ui new file mode 100644 index 0000000..fa3c791 --- /dev/null +++ b/installer/packages/com.committeeofzero.installer/meta/platformSelection.ui @@ -0,0 +1,74 @@ + + + PlatformSelection + + + + 0 + 0 + 636 + 465 + + + + + 0 + 0 + + + + + 491 + 190 + + + + Installation Configuration + + + + + + On which platform are you installing Impacto? + + + + + + + Desktop + + + + + + + Android + + + + + + + Switch + + + + + + + Qt::Orientation::Vertical + + + + 20 + 317 + + + + + + + + + From 78e7f117af75f9bfbba62f23415d1dcd4a3638cf Mon Sep 17 00:00:00 2001 From: Macitron <117962989+Macitron@users.noreply.github.com> Date: Tue, 6 Oct 2026 18:44:57 -0700 Subject: [PATCH 2/8] Clean it up a lil --- .../meta/installscript.qs | 12 +++--------- .../meta/platformSelection.ui | 2 +- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/installer/packages/com.committeeofzero.installer/meta/installscript.qs b/installer/packages/com.committeeofzero.installer/meta/installscript.qs index 839bca1..f512f92 100644 --- a/installer/packages/com.committeeofzero.installer/meta/installscript.qs +++ b/installer/packages/com.committeeofzero.installer/meta/installscript.qs @@ -24,19 +24,13 @@ function Component() { if (installer.addWizardPage(component, "PlatformSelection", QInstaller.ComponentSelection)) { const widget = gui.pageWidgetByObjectName("DynamicPlatformSelection"); widget.platformAndroid.toggled.connect(this, checked => { - if (checked) { - installer.setValue("Platform", "android"); - } + if (checked) installer.setValue("Platform", "android"); }); widget.platformDesktop.toggled.connect(this, checked => { - if (checked) { - installer.setValue("Platform", "desktop"); - } + if (checked) installer.setValue("Platform", "desktop"); }); widget.platformSwitch.toggled.connect(this, checked => { - if (checked) { - installer.setValue("Platform", "switch"); - } + if (checked) installer.setValue("Platform", "switch"); }); } } diff --git a/installer/packages/com.committeeofzero.installer/meta/platformSelection.ui b/installer/packages/com.committeeofzero.installer/meta/platformSelection.ui index fa3c791..73d2455 100644 --- a/installer/packages/com.committeeofzero.installer/meta/platformSelection.ui +++ b/installer/packages/com.committeeofzero.installer/meta/platformSelection.ui @@ -23,7 +23,7 @@ - Installation Configuration + Platform Selection From 93adaad941cb2dac95e7c20917d39551e2375bbb Mon Sep 17 00:00:00 2001 From: Macitron <117962989+Macitron@users.noreply.github.com> Date: Sat, 10 Oct 2026 22:37:17 -0700 Subject: [PATCH 3/8] Working refactor for detecting platform - improvements to follow --- installer/config/controller.qs | 94 ------------------- .../meta/package.xml | 1 + .../meta/installscript.qs | 50 ++++++++++ .../meta/package.xml | 1 - .../meta/selectionValidation.ui | 26 ----- 5 files changed, 51 insertions(+), 121 deletions(-) delete mode 100644 installer/packages/com.committeeofzero.installer/meta/selectionValidation.ui diff --git a/installer/config/controller.qs b/installer/config/controller.qs index 0b4933f..ef1a86a 100644 --- a/installer/config/controller.qs +++ b/installer/config/controller.qs @@ -166,35 +166,6 @@ Controller.prototype.onSelectionChange = function () { } } - // Make Impacto Selections Mutually Exclusive - const impactoComponents = [ - "com.committeeofzero.impacto.windows", - "com.committeeofzero.impacto.linux", - "com.committeeofzero.impacto.macos_arm64", - "com.committeeofzero.impacto.macos_x64", - "com.committeeofzero.impacto.switch", - "com.committeeofzero.impacto.android", - ]; - let selectedImpactoComponent = null; - for (const componentName of impactoComponents) { - const component = installer.componentByName(componentName); - if (componentIsSelected(component)) { - selectedImpactoComponent = componentName; - break; - } - } - - // TODO use radio buttons page. - for (const componentName of impactoComponents) { - const component = installer.componentByName(componentName); - if(!component) continue; - if(selectedImpactoComponent == null) { - component.enabled = true; // Enable all if none selected - } else if (componentName !== selectedImpactoComponent) { - component.enabled = !selectedImpactoComponent; // Disable if another is selected - } - } - validateSelection(); page.completeChanged.connect(this, Controller.prototype.onSelectionChange); @@ -207,67 +178,6 @@ Controller.prototype.ComponentSelectionPageCallback = function () { Controller.prototype.onSelectionChange(); }; -function checkImpactoDesktopInstall() { - const componentInstaller = installer.componentByName("com.committeeofzero.installer"); - - if (componentInstaller) { - const errors = []; - - const impactoGroup = installer.componentByName("com.committeeofzero.impacto"); - - if (!componentIsSelected(impactoGroup)) { - errors.push( - "Please select an Impacto component." - ); - } - const pageTargetDesktop = gui.pageWidgetByObjectName("DynamicTargetWidget"); - const pageTargetMobile = gui.pageWidgetByObjectName("DynamicTargetWidgetMobile"); - const componentImpactoWin = installer.componentByName("com.committeeofzero.impacto.windows"); - const componentImpactoLin = installer.componentByName("com.committeeofzero.impacto.linux"); - const componentImpactoMacArm = installer.componentByName("com.committeeofzero.impacto.macos_arm64"); - const componentImpactoMacX64 = installer.componentByName("com.committeeofzero.impacto.macos_x64"); - const componentImpactoSwitch = installer.componentByName("com.committeeofzero.impacto.switch"); - const componentImpactoAndroid = installer.componentByName("com.committeeofzero.impacto.android"); - - const requestDesktopInstall = - componentImpactoWin?.installationRequested() || - componentImpactoLin?.installationRequested() || - componentImpactoMacArm?.installationRequested() || - componentImpactoMacX64?.installationRequested(); - - const requestMobileInstall = - componentImpactoSwitch?.installationRequested() || - componentImpactoAndroid?.installationRequested(); - - if (installer.isInstaller() && requestMobileInstall && !pageTargetMobile) { - installer.addWizardPage(componentInstaller, "TargetWidgetMobile", QInstaller.ReadyForInstallation); - } else if (installer.isInstaller() && !requestMobileInstall && pageTargetMobile) { - installer.removeWizardPage(componentInstaller, "TargetWidgetMobile"); - } - - if (installer.isInstaller() && requestDesktopInstall && !pageTargetDesktop) { - installer.addWizardPage(componentInstaller, "TargetWidget", QInstaller.ReadyForInstallation); - } else if (installer.isInstaller() && !requestDesktopInstall && pageTargetDesktop) { - installer.removeWizardPage(componentInstaller, "TargetWidget"); - } - - // Add block continue page w/ error if impacto is not selected - if (errors.length > 0) { - let page = gui.pageWidgetByObjectName("DynamicSelectionValidationPage"); - if (!page) { - installer.addWizardPage(componentInstaller, "SelectionValidationPage", QInstaller.LicenseCheck); - page = gui.pageWidgetByObjectName("DynamicSelectionValidationPage"); - } - if (page) { - page.label.text = errors.join("\n"); - page.complete = false; - } - } else { - installer.removeWizardPage(componentInstaller, "SelectionValidationPage"); - } - } -} - function addCclccPs4AssetsInstallPage() { const componentCclccPs4Assets = installer.componentByName("com.committeeofzero.cclcc.ps4.assets"); if (componentCclccPs4Assets) { @@ -297,10 +207,6 @@ function addChlccPs3AssetsInstallPage() { } function validateSelection() { - - // Desktop path selection page - checkImpactoDesktopInstall(); - addCclccPs4AssetsInstallPage(); addChlccPs3AssetsInstallPage(); } diff --git a/installer/packages/com.committeeofzero.impacto/meta/package.xml b/installer/packages/com.committeeofzero.impacto/meta/package.xml index d411ee9..52e6350 100644 --- a/installer/packages/com.committeeofzero.impacto/meta/package.xml +++ b/installer/packages/com.committeeofzero.impacto/meta/package.xml @@ -5,4 +5,5 @@ 0.10.8.810 2026-10-05 + true diff --git a/installer/packages/com.committeeofzero.installer/meta/installscript.qs b/installer/packages/com.committeeofzero.installer/meta/installscript.qs index f512f92..e93a11c 100644 --- a/installer/packages/com.committeeofzero.installer/meta/installscript.qs +++ b/installer/packages/com.committeeofzero.installer/meta/installscript.qs @@ -23,6 +23,7 @@ function Component() { if (installer.addWizardPage(component, "PlatformSelection", QInstaller.ComponentSelection)) { const widget = gui.pageWidgetByObjectName("DynamicPlatformSelection"); + widget.platformDesktop.setChecked(true); widget.platformAndroid.toggled.connect(this, checked => { if (checked) installer.setValue("Platform", "android"); }); @@ -32,6 +33,55 @@ function Component() { widget.platformSwitch.toggled.connect(this, checked => { if (checked) installer.setValue("Platform", "switch"); }); + + const page = gui.pageByObjectName("DynamicPlatformSelection"); + page.left.connect(() => { + const impactoGroup = "com.committeeofzero.impacto"; + const componentSuffix = GetTargetPlatformComponent(); + const platformComponentName = impactoGroup + "." + componentSuffix; + installer.deselectComponent(impactoGroup); + installer.selectComponent(platformComponentName) + console.log(`selected component ${platformComponentName}`); + + const platform = installer.value("Platform"); + const componentInstaller = installer.componentByName("com.committeeofzero.installer"); + const pageTargetDesktop = gui.pageWidgetByObjectName("DynamicTargetWidget"); + const pageTargetMobile = gui.pageWidgetByObjectName("DynamicTargetWidgetMobile"); + + // only add the desktop install page if desktop is selected and the page doesn't already exist + if (platform === "desktop" && !pageTargetDesktop) { + installer.addWizardPage(componentInstaller, "TargetWidget", QInstaller.ReadyForInstallation); + } else if (platform !== "desktop" && pageTargetDesktop) { + installer.removeWizardPage(componentInstaller, "TargetWidget"); + } + + // switch/android + if (platform !== "desktop" && !pageTargetMobile) { + installer.addWizardPage(componentInstaller, "TargetWidgetMobile", QInstaller.ReadyForInstallation); + } else if (platform === "desktop" && pageTargetMobile) { + installer.removeWizardPage(componentInstaller, "TargetWidgetMobile"); + } + }) + } +} + +function GetTargetPlatformComponent() { + const platform = installer.value("Platform"); + if (platform === "android" || platform === "switch") { + return platform; + } + + // Otherwise it's desktop, so detect which OS + switch (systemInfo.productType) { + case "windows": + return "windows"; + case "macos": + return systemInfo.currentCpuArchitecture === "arm64" + ? "macos_arm64" + : "macos_x64"; + default: + // TempleOS users get fucked lmao + return "linux"; } } diff --git a/installer/packages/com.committeeofzero.installer/meta/package.xml b/installer/packages/com.committeeofzero.installer/meta/package.xml index b100053..04fed55 100644 --- a/installer/packages/com.committeeofzero.installer/meta/package.xml +++ b/installer/packages/com.committeeofzero.installer/meta/package.xml @@ -7,7 +7,6 @@ true true - selectionValidation.ui targetDirectories.ui targetDirectoriesMobile.ui platformSelection.ui diff --git a/installer/packages/com.committeeofzero.installer/meta/selectionValidation.ui b/installer/packages/com.committeeofzero.installer/meta/selectionValidation.ui deleted file mode 100644 index e7d70fc..0000000 --- a/installer/packages/com.committeeofzero.installer/meta/selectionValidation.ui +++ /dev/null @@ -1,26 +0,0 @@ - - - SelectionValidationPage - - - Component Selection Validation - - - - - - - - - true - - - color: red; font-weight: bold; - - - - - - - - \ No newline at end of file From e1a81effc7a571e0c0dbd07cb6bcfb1057d9c807 Mon Sep 17 00:00:00 2001 From: Macitron <117962989+Macitron@users.noreply.github.com> Date: Sun, 11 Oct 2026 00:04:56 -0700 Subject: [PATCH 4/8] Updater working with platform detection --- installer/config/controller.qs | 157 +++++------------- .../meta/installscript.qs | 137 ++++++++++++--- .../meta/package.xml | 1 + .../meta/updateWaitingRoom.ui | 53 ++++++ 4 files changed, 205 insertions(+), 143 deletions(-) create mode 100644 installer/packages/com.committeeofzero.installer/meta/updateWaitingRoom.ui diff --git a/installer/config/controller.qs b/installer/config/controller.qs index ef1a86a..81eed58 100644 --- a/installer/config/controller.qs +++ b/installer/config/controller.qs @@ -1,130 +1,18 @@ -let existingMaintenanceTool = ""; -let maintenanceToolStatus = 0; - function Controller() { installer.setDefaultPageVisible(QInstaller.TargetDirectory, false); - - const existingInstall = getExistingInstall(); - if (existingInstall && installer.isInstaller()) { - existingMaintenanceTool = existingInstall; - - installer.setDefaultPageVisible(QInstaller.TargetDirectory, false); - installer.setDefaultPageVisible(QInstaller.ReadyForInstallation, false); - installer.setDefaultPageVisible(QInstaller.ComponentSelection, false); - installer.setDefaultPageVisible(QInstaller.StartMenuSelection, false); - installer.setDefaultPageVisible(QInstaller.PerformInstallation, false); - installer.setDefaultPageVisible(QInstaller.LicenseCheck, false); - } -} - -Controller.prototype.IntroductionPageCallback = function () { - if (existingMaintenanceTool) { - const introPage = gui.currentPageWidget(); - introPage.setComplete(false); - introPage.MessageLabel.text = "Waiting for Maintenance Tool to Complete"; - const tempRepo = `${QDesktopServices.storageLocation(QDesktopServices.TempLocation)}/tmpImpactoInstallRepository`; - const tempCache = `${QDesktopServices.storageLocation(QDesktopServices.TempLocation)}/tmpImpactoInstallCache`; - installer.performOperation("CreateLocalRepository", ["@InstallerFilePath@", tempRepo]); - const output = - (() => { - if (systemInfo.productType === "windows") { - return installer.execute( - "cmd", ["/c", "start", "", "/wait", existingMaintenanceTool, "--set-temp-repository", tempRepo, "--cache-path", tempCache] - ); - } else if (systemInfo.productType === "macos") { - return installer.execute( - "open", - ["-W", existingMaintenanceTool, "--args", - "--set-temp-repository", tempRepo, - "--cache-path", tempCache] - ); - } else { - return installer.execute( - existingMaintenanceTool, - ["--set-temp-repository", tempRepo, "--cache-path", tempCache] - ); - } - })(); - console.log(`Maintenance Tool Output: ${output[0]}`) - console.log(`Maintenance Tool Status Code: ${output[1]}`) - maintenanceToolStatus = Number(output[1]); - installer.performOperation("Rmdir", [tempRepo, "FORCE"]); - installer.performOperation("Rmdir", [tempCache, "FORCE"]); - introPage.setComplete(true); - gui.clickButton(buttons.NextButton); - } } Controller.prototype.FinishedPageCallback = function () { - if (existingMaintenanceTool) { + const wasUpdated = installer.containsValue("ExistingMaintenanceTool"); + if (wasUpdated) { const finishedPage = gui.currentPageWidget(); + const maintenanceToolStatus = Number(installer.value("MaintenanceToolStatus")); if (maintenanceToolStatus == 0) finishedPage.MessageLabel.text = `Operation completed.`; if (maintenanceToolStatus == 1) finishedPage.MessageLabel.text = `Operation failed.`; if (maintenanceToolStatus == 3) finishedPage.MessageLabel.text = `Operation canceled.`; } } -function getConfigDir() { - const productName = installer.value("Name"); - const publisher = installer.value("Publisher"); - if (systemInfo.productType === "windows") { - const roaming = installer.fromNativeSeparators(QDesktopServices.storageLocation(QDesktopServices.AppDataLocation)); - const roamingSlash = roaming.lastIndexOf("/"); - const configDir = roaming.slice(0, roamingSlash) + `/${publisher}/${productName}`; - return installer.toNativeSeparators(configDir); - } - - if (systemInfo.productType === "macos") { - const configDir = `${QDesktopServices.storageLocation(QDesktopServices.GenericDataLocation)}/${publisher}/${productName}`; - return configDir; - } - - const configDir = `${QDesktopServices.storageLocation(QDesktopServices.ConfigLocation)}/${publisher}/${productName}`; - return configDir; -} - -function getExistingInstall() { - const configDir = getConfigDir(); - console.log(configDir); - const basePathsFilePath = installer.toNativeSeparators(`${configDir}/basepaths.lua`); - console.log(basePathsFilePath); - const basePaths = installer.readFile(basePathsFilePath, "UTF-8"); - console.log(basePaths); - - if (basePaths.length === 0) return null; - // 1. Strip out Lua block comments --[[ ... ]] so we do not match dead code - let cleanContent = basePaths.replace(/--\[\[[\s\S]*?\]\]/g, ""); - - // 2. Strip out single line comments -- ... - cleanContent = basePaths.replace(/--.*$/gm, ""); - - // 3. Regex matching the Lua standard for strings: - // Pattern 1: "..." or '...' using (["'])(.*?)\1 - // Pattern 2: [[...]] using \[\[([\s\S]*?)\]\] - let regex = /RootInstallDir\s*=\s*(?:(["'])(.*?)\1|\[\[([\s\S]*?)\]\])/g; - let match; - - - // Loop through all matches in the file string - while ((match = regex.exec(cleanContent)) !== null) { - // If it matched a quoted string, the path is in match[2] - // If it matched a Lua long bracket [[ ]], the path is in match[3] - let extractedPath = match[2] || match[3]; - - console.log("Extracted Lua RootInstallDir: " + extractedPath); - if (extractedPath.length > 0) { - let maintenanceToolName = installer.value("MaintenanceToolName"); - if (systemInfo.productType === "windows") maintenanceToolName += ".exe"; - if (systemInfo.productType === "macos") maintenanceToolName += ".dmg"; - const maintenanceTool = installer.findPath(maintenanceToolName, [extractedPath]); - if (maintenanceTool.length > 0) { - console.log(`Found Maintenance Tool at ${maintenanceTool}`); - return maintenanceTool; - } - } - } - return null; -} function componentIsSelected(widget) { if (!widget) return false; @@ -214,4 +102,41 @@ function validateSelection() { Controller.prototype.DynamicTargetWidgetMobileCallback = function () { console.log("Setting to portable install"); installer.setPortableInstaller(); -} \ No newline at end of file +} + +Controller.prototype.DynamicUpdateWaitingRoomCallback = function () { + const waitingPage = gui.pageByObjectName("DynamicUpdateWaitingRoom"); + waitingPage.setComplete(false); + const tempRepo = `${QDesktopServices.storageLocation(QDesktopServices.TempLocation)}/tmpImpactoInstallRepository`; + const tempCache = `${QDesktopServices.storageLocation(QDesktopServices.TempLocation)}/tmpImpactoInstallCache`; + installer.performOperation("CreateLocalRepository", ["@InstallerFilePath@", tempRepo]); + const existingInstall = installer.value("ExistingMaintenanceTool"); + const output = + (() => { + if (systemInfo.productType === "windows") { + return installer.execute( + "cmd", ["/c", "start", "", "/wait", existingInstall, "--set-temp-repository", tempRepo, "--cache-path", tempCache] + ); + } else if (systemInfo.productType === "macos") { + return installer.execute( + "open", + ["-W", existingInstall, "--args", + "--set-temp-repository", tempRepo, + "--cache-path", tempCache] + ); + } else { + return installer.execute( + existingInstall, + ["--set-temp-repository", tempRepo, "--cache-path", tempCache] + ); + } + })(); + console.log(`Maintenance Tool Output: ${output[0]}`) + console.log(`Maintenance Tool Status Code: ${output[1]}`) + installer.setValue("MaintenanceToolStatus", output[1]); + installer.performOperation("Rmdir", [tempRepo, "FORCE"]); + installer.performOperation("Rmdir", [tempCache, "FORCE"]); + waitingPage.setComplete(true); + gui.clickButton(buttons.NextButton); + gui.setVisible(true); +} diff --git a/installer/packages/com.committeeofzero.installer/meta/installscript.qs b/installer/packages/com.committeeofzero.installer/meta/installscript.qs index e93a11c..5443c56 100644 --- a/installer/packages/com.committeeofzero.installer/meta/installscript.qs +++ b/installer/packages/com.committeeofzero.installer/meta/installscript.qs @@ -35,33 +35,54 @@ function Component() { }); const page = gui.pageByObjectName("DynamicPlatformSelection"); - page.left.connect(() => { - const impactoGroup = "com.committeeofzero.impacto"; - const componentSuffix = GetTargetPlatformComponent(); - const platformComponentName = impactoGroup + "." + componentSuffix; - installer.deselectComponent(impactoGroup); - installer.selectComponent(platformComponentName) - console.log(`selected component ${platformComponentName}`); - - const platform = installer.value("Platform"); - const componentInstaller = installer.componentByName("com.committeeofzero.installer"); - const pageTargetDesktop = gui.pageWidgetByObjectName("DynamicTargetWidget"); - const pageTargetMobile = gui.pageWidgetByObjectName("DynamicTargetWidgetMobile"); - - // only add the desktop install page if desktop is selected and the page doesn't already exist - if (platform === "desktop" && !pageTargetDesktop) { - installer.addWizardPage(componentInstaller, "TargetWidget", QInstaller.ReadyForInstallation); - } else if (platform !== "desktop" && pageTargetDesktop) { - installer.removeWizardPage(componentInstaller, "TargetWidget"); - } + page.left.connect(OnPlatformSelectionLeave) + } +} - // switch/android - if (platform !== "desktop" && !pageTargetMobile) { - installer.addWizardPage(componentInstaller, "TargetWidgetMobile", QInstaller.ReadyForInstallation); - } else if (platform === "desktop" && pageTargetMobile) { - installer.removeWizardPage(componentInstaller, "TargetWidgetMobile"); - } - }) +function OnPlatformSelectionLeave() { + const impactoGroup = "com.committeeofzero.impacto"; + const componentSuffix = GetTargetPlatformComponent(); + const platformComponentName = impactoGroup + "." + componentSuffix; + installer.deselectComponent(impactoGroup); + installer.selectComponent(platformComponentName) + console.log(`selected component ${platformComponentName}`); + + const platform = installer.value("Platform"); + const componentInstaller = installer.componentByName("com.committeeofzero.installer"); + const pageTargetDesktop = gui.pageWidgetByObjectName("DynamicTargetWidget"); + const pageTargetMobile = gui.pageWidgetByObjectName("DynamicTargetWidgetMobile"); + + // give the illusion of an updater if an existing install is detected, a la controller.qs + const existingInstall = getExistingInstall(); + if (platform === "desktop" && existingInstall) { + installer.setValue("ExistingMaintenanceTool", existingInstall); + + installer.setDefaultPageVisible(QInstaller.TargetDirectory, false); + installer.setDefaultPageVisible(QInstaller.ReadyForInstallation, false); + installer.setDefaultPageVisible(QInstaller.ComponentSelection, false); + installer.setDefaultPageVisible(QInstaller.StartMenuSelection, false); + installer.setDefaultPageVisible(QInstaller.PerformInstallation, false); + installer.setDefaultPageVisible(QInstaller.LicenseCheck, false); + + installer.addWizardPage(componentInstaller, "UpdateWaitingRoom", QInstaller.LicenseCheck) + gui.setVisible(false); + gui.clickButton(buttons.NextButton); + + return; + } + + // only add the desktop install page if desktop is selected and the page doesn't already exist + if (platform === "desktop" && !pageTargetDesktop) { + installer.addWizardPage(componentInstaller, "TargetWidget", QInstaller.ReadyForInstallation); + } else if (platform !== "desktop" && pageTargetDesktop) { + installer.removeWizardPage(componentInstaller, "TargetWidget"); + } + + // switch/android + if (platform !== "desktop" && !pageTargetMobile) { + installer.addWizardPage(componentInstaller, "TargetWidgetMobile", QInstaller.ReadyForInstallation); + } else if (platform === "desktop" && pageTargetMobile) { + installer.removeWizardPage(componentInstaller, "TargetWidgetMobile"); } } @@ -372,4 +393,66 @@ Component.prototype.targetChangedImpactoMobile = function (text) { targetDirectoriesValidationState.Patches = true; targetDirectoriesValidationState.Profiles = true; -} \ No newline at end of file +} + +function getConfigDir() { + const productName = installer.value("Name"); + const publisher = installer.value("Publisher"); + if (systemInfo.productType === "windows") { + const roaming = installer.fromNativeSeparators(QDesktopServices.storageLocation(QDesktopServices.AppDataLocation)); + const roamingSlash = roaming.lastIndexOf("/"); + const configDir = roaming.slice(0, roamingSlash) + `/${publisher}/${productName}`; + return installer.toNativeSeparators(configDir); + } + + if (systemInfo.productType === "macos") { + const configDir = `${QDesktopServices.storageLocation(QDesktopServices.GenericDataLocation)}/${publisher}/${productName}`; + return configDir; + } + + const configDir = `${QDesktopServices.storageLocation(QDesktopServices.ConfigLocation)}/${publisher}/${productName}`; + return configDir; +} + +function getExistingInstall() { + const configDir = getConfigDir(); + console.log(configDir); + const basePathsFilePath = installer.toNativeSeparators(`${configDir}/basepaths.lua`); + console.log(basePathsFilePath); + const basePaths = installer.readFile(basePathsFilePath, "UTF-8"); + console.log(basePaths); + + if (basePaths.length === 0) return null; + // 1. Strip out Lua block comments --[[ ... ]] so we do not match dead code + let cleanContent = basePaths.replace(/--\[\[[\s\S]*?\]\]/g, ""); + + // 2. Strip out single line comments -- ... + cleanContent = basePaths.replace(/--.*$/gm, ""); + + // 3. Regex matching the Lua standard for strings: + // Pattern 1: "..." or '...' using (["'])(.*?)\1 + // Pattern 2: [[...]] using \[\[([\s\S]*?)\]\] + let regex = /RootInstallDir\s*=\s*(?:(["'])(.*?)\1|\[\[([\s\S]*?)\]\])/g; + let match; + + + // Loop through all matches in the file string + while ((match = regex.exec(cleanContent)) !== null) { + // If it matched a quoted string, the path is in match[2] + // If it matched a Lua long bracket [[ ]], the path is in match[3] + let extractedPath = match[2] || match[3]; + + console.log("Extracted Lua RootInstallDir: " + extractedPath); + if (extractedPath.length > 0) { + let maintenanceToolName = installer.value("MaintenanceToolName"); + if (systemInfo.productType === "windows") maintenanceToolName += ".exe"; + if (systemInfo.productType === "macos") maintenanceToolName += ".dmg"; + const maintenanceTool = installer.findPath(maintenanceToolName, [extractedPath]); + if (maintenanceTool.length > 0) { + console.log(`Found Maintenance Tool at ${maintenanceTool}`); + return maintenanceTool; + } + } + } + return null; +} diff --git a/installer/packages/com.committeeofzero.installer/meta/package.xml b/installer/packages/com.committeeofzero.installer/meta/package.xml index 04fed55..b0c60f1 100644 --- a/installer/packages/com.committeeofzero.installer/meta/package.xml +++ b/installer/packages/com.committeeofzero.installer/meta/package.xml @@ -10,6 +10,7 @@ targetDirectories.ui targetDirectoriesMobile.ui platformSelection.ui + updateWaitingRoom.ui \ No newline at end of file diff --git a/installer/packages/com.committeeofzero.installer/meta/updateWaitingRoom.ui b/installer/packages/com.committeeofzero.installer/meta/updateWaitingRoom.ui new file mode 100644 index 0000000..b23a2b9 --- /dev/null +++ b/installer/packages/com.committeeofzero.installer/meta/updateWaitingRoom.ui @@ -0,0 +1,53 @@ + + + UpdateWaitingRoom + + + + 0 + 0 + 636 + 465 + + + + + 0 + 0 + + + + + 491 + 190 + + + + Update Waiting Room + + + + + + Waiting for Maintenance Tool to Complete... + + + + + + + Qt::Orientation::Vertical + + + + 20 + 317 + + + + + + + + + From c2b09647e2ca053bfcfeecf90e6b8589f4196508 Mon Sep 17 00:00:00 2001 From: Macitron <117962989+Macitron@users.noreply.github.com> Date: Sun, 11 Oct 2026 00:16:00 -0700 Subject: [PATCH 5/8] Updated installer-framework submodule - includes the `setVisible()` addition --- installer-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installer-framework b/installer-framework index e5528be..d1d0274 160000 --- a/installer-framework +++ b/installer-framework @@ -1 +1 @@ -Subproject commit e5528bea17b11ff1981d2a113da862bd49d2445e +Subproject commit d1d0274d6d6bcf31b7580e37529ed8d2e0254745 From 225e4dcfe9e70ca5af91192d9d04d29d0b017148 Mon Sep 17 00:00:00 2001 From: Macitron <117962989+Macitron@users.noreply.github.com> Date: Sat, 3 Oct 2026 01:05:38 -0700 Subject: [PATCH 6/8] Fixed build script on some systems (mine) - `qt.py` was calling `init-repository` with only the submodules needed, but then the actual `configure` command didn't specify those same modules - adding the `-submodules {submodules}` flag makes it so it only compiles those which we need, avoiding compilation errors down the line --- scripts/lib/qt.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/scripts/lib/qt.py b/scripts/lib/qt.py index 327bf85..8411418 100644 --- a/scripts/lib/qt.py +++ b/scripts/lib/qt.py @@ -6,6 +6,8 @@ QT_PREFIX = Path() +QT_MODULES = "qtbase,qtdeclarative,qttools,qttranslations,qt5compat" + def set_qt_prefix(new_prefix: str): global QT_PREFIX QT_PREFIX = Path(new_prefix) @@ -27,7 +29,7 @@ def init_qt(): common.run( [ str(qt_script("init-repository")), - "--module-subset=qtbase,qtdeclarative,qttools,qttranslations,qt5compat", + f"--module-subset={QT_MODULES}", ], cwd=common.QT, ) @@ -97,8 +99,7 @@ def build_qt(rebuild=False, symbols = False): args = [ str(qt_script("configure")), - "-prefix", - str(qt_prefix()), + "-prefix", str(qt_prefix()), "-static", "-release", @@ -108,11 +109,11 @@ def build_qt(rebuild=False, symbols = False): "-opensource", "-confirm-license", - "-nomake", - "examples", + "-submodules", QT_MODULES, + + "-nomake", "examples", - "-nomake", - "tests", + "-nomake", "tests", "-no-sql-sqlite", "-no-qml-debug" From b3950ead51f8cf4329d14790d6ba2465e6fbfeb7 Mon Sep 17 00:00:00 2001 From: Macitron <117962989+Macitron@users.noreply.github.com> Date: Sun, 11 Oct 2026 20:44:48 -0700 Subject: [PATCH 7/8] Call `apt update` before installing deps because SOME PEOPLE don't check their linux pipelines --- .github/workflows/pipeline.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index b69ebc8..40c980e 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -39,7 +39,8 @@ jobs: - name: Build Linux Deps if: matrix.os == 'ubuntu-latest' run: | - sudo apt install \ + sudo apt update && \ + sudo apt install -y \ libfontconfig1-dev \ libfreetype-dev \ libgtk-3-dev \ From 4ceacf9202f7a10a2c3d75605c42ed6d676af212 Mon Sep 17 00:00:00 2001 From: Dextinfire <> Date: Mon, 12 Oct 2026 01:41:00 -0700 Subject: [PATCH 8/8] Deselect all impacto components when switching plat --- .../com.committeeofzero.installer/meta/installscript.qs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/installer/packages/com.committeeofzero.installer/meta/installscript.qs b/installer/packages/com.committeeofzero.installer/meta/installscript.qs index 5443c56..6d9331c 100644 --- a/installer/packages/com.committeeofzero.installer/meta/installscript.qs +++ b/installer/packages/com.committeeofzero.installer/meta/installscript.qs @@ -40,10 +40,18 @@ function Component() { } function OnPlatformSelectionLeave() { + const componentSuffixes = ["windows", "macos_x64", "macos_arm64", "linux", "android", "switch"]; const impactoGroup = "com.committeeofzero.impacto"; const componentSuffix = GetTargetPlatformComponent(); const platformComponentName = impactoGroup + "." + componentSuffix; installer.deselectComponent(impactoGroup); + for (const suffix of componentSuffixes) { + const componentName = "com.committeeofzero.impacto." + suffix; + const componentWidget = installer.componentByName(componentName); + if (componentWidget) { + installer.deselectComponent(componentName); + } + } installer.selectComponent(platformComponentName) console.log(`selected component ${platformComponentName}`);