From ad7b5720185bbf7dbbf8dae6a952d5902752bb1b Mon Sep 17 00:00:00 2001 From: progzone122 Date: Mon, 5 Oct 2026 12:20:11 +0300 Subject: [PATCH 1/9] add get_active_slot logic --- src/callbacks/device.rs | 30 +++++++++++++++++++++++++++++- src/state.rs | 8 ++++++++ src/ui/Pages/MainPage.qml | 4 +++- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/callbacks/device.rs b/src/callbacks/device.rs index 3f7ddbd..2758183 100644 --- a/src/callbacks/device.rs +++ b/src/callbacks/device.rs @@ -3,7 +3,7 @@ use std::sync::mpsc::{self, Receiver, Sender}; use qtbridge::{QmlMethodInvoker, QmlObject, invoke_method}; -use penumbra_mtk::hacc::LockState; +use penumbra_mtk::hacc::{BootPartition, LockState}; use penumbra_mtk::port::{MtkPort, PortBackend, PortType}; use crate::logs; @@ -43,6 +43,9 @@ pub(crate) enum DeviceCommand { bootmode: penumbra_mtk::BootMode, invoker: QmlMethodInvoker, }, + RequestGetActiveSlot { + invoker: QmlMethodInvoker, + }, } /// Spawns the device worker thread and returns the command sender. The worker @@ -155,6 +158,19 @@ fn worker_loop(rx: Receiver) { ); } } + DeviceCommand::RequestGetActiveSlot { invoker } => { + let slot = match device.as_mut() { + Some(dev) => dev + .get_bootctrl() + .ok() + .map(|bootctrl| format!("{:?}", bootctrl.get_active_slot())) + .unwrap_or_default(), + + None => String::new(), + }; + + invoke_method!(invoker, "activeSlotLoaded", slot); + } } } } @@ -840,3 +856,15 @@ pub fn reboot_to_mode(state: &mut AppState, bootmode: penumbra_mtk::BootMode) { let _ = tx.send(DeviceCommand::RebootToMode { bootmode, invoker }); } + +pub fn get_active_slot(state: &mut AppState) { + let invoker = state.get_qml_method_invoker(); + + let tx = { state.device_tx.lock().unwrap().clone() }; + let Some(tx) = tx else { + state.active_slot_loaded(String::new()); + return; + }; + + let _ = tx.send(DeviceCommand::RequestGetActiveSlot { invoker }); +} diff --git a/src/state.rs b/src/state.rs index a245979..f8c10d1 100644 --- a/src/state.rs +++ b/src/state.rs @@ -219,6 +219,9 @@ impl AppState { #[qsignal] pub(crate) fn scatter_file_failed(&mut self, message: String); + #[qsignal] + pub(crate) fn active_slot_loaded(&mut self, slot: String); + #[qslot] fn request_get_templates(&mut self) { callbacks::templates::request_get_templates(self); @@ -368,6 +371,11 @@ impl AppState { callbacks::device::reboot_to_mode(self, mode); } + + #[qslot] + fn request_get_active_slot(&mut self) { + callbacks::device::get_active_slot(self); + } } impl Default for AppState { diff --git a/src/ui/Pages/MainPage.qml b/src/ui/Pages/MainPage.qml index 9a7439f..832ec2b 100644 --- a/src/ui/Pages/MainPage.qml +++ b/src/ui/Pages/MainPage.qml @@ -48,8 +48,10 @@ Page { // Fetch the real partition table when the page becomes visible with a // device connected. onVisibleChanged: { - if (page.visible && AppState.connected) + if (page.visible && AppState.connected) { AppState.requestPartitions(); + AppState.requestGetActiveSlot(); + } } Connections { From 00e3084222ea167f1726816c777367294db2db1a Mon Sep 17 00:00:00 2001 From: progzone122 Date: Mon, 5 Oct 2026 13:10:01 +0300 Subject: [PATCH 2/9] store active slot in AppState --- src/callbacks/device.rs | 5 ++++- src/state.rs | 16 +++++++++++++++- src/ui/Components/Navigation/MainMenu.qml | 2 ++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/callbacks/device.rs b/src/callbacks/device.rs index 2758183..d17a6b4 100644 --- a/src/callbacks/device.rs +++ b/src/callbacks/device.rs @@ -3,7 +3,7 @@ use std::sync::mpsc::{self, Receiver, Sender}; use qtbridge::{QmlMethodInvoker, QmlObject, invoke_method}; -use penumbra_mtk::hacc::{BootPartition, LockState}; +use penumbra_mtk::hacc::LockState; use penumbra_mtk::port::{MtkPort, PortBackend, PortType}; use crate::logs; @@ -651,6 +651,9 @@ pub fn disconnect_device(state: &mut AppState) { state.connection_error.clear(); state.connection_error_changed(); + state.active_slot.clear(); + state.active_slot_changed(); + logs::info(&mut state.logs, "Device disconnected"); state.logs_changed(); diff --git a/src/state.rs b/src/state.rs index f8c10d1..32ae488 100644 --- a/src/state.rs +++ b/src/state.rs @@ -42,6 +42,7 @@ pub struct AppState { pub(crate) setup_command: String, pub(crate) setup_installing: bool, pub(crate) templates_cancel: Arc, + pub(crate) active_slot: String, } #[qobject(Singleton, ConvertToCamelCase)] @@ -114,6 +115,12 @@ impl AppState { Notify = setup_installing_changed ); + qproperty!( + "active_slot", + Member = active_slot, + Notify = active_slot_changed + ); + #[qsignal] pub(crate) fn page_changed(&mut self); @@ -220,7 +227,7 @@ impl AppState { pub(crate) fn scatter_file_failed(&mut self, message: String); #[qsignal] - pub(crate) fn active_slot_loaded(&mut self, slot: String); + pub(crate) fn active_slot_changed(&mut self); #[qslot] fn request_get_templates(&mut self) { @@ -376,6 +383,12 @@ impl AppState { fn request_get_active_slot(&mut self) { callbacks::device::get_active_slot(self); } + + #[qslot] + pub(crate) fn active_slot_loaded(&mut self, slot: String) { + self.active_slot = slot; + self.active_slot_changed(); + } } impl Default for AppState { @@ -403,6 +416,7 @@ impl Default for AppState { setup_command: String::new(), setup_installing: false, templates_cancel: Arc::new(AtomicBool::new(false)), + active_slot: String::new(), } } } diff --git a/src/ui/Components/Navigation/MainMenu.qml b/src/ui/Components/Navigation/MainMenu.qml index 521ade2..ebea531 100644 --- a/src/ui/Components/Navigation/MainMenu.qml +++ b/src/ui/Components/Navigation/MainMenu.qml @@ -11,6 +11,8 @@ Item { Layout.fillHeight: true Layout.preferredWidth: 280 + property string activeSlot: "" + property bool bootloaderExpanded: false property bool flashingExpanded: false property bool otherExpanded: false From 27b11e91d6b81e43d437bbb4ae932f2420a1975c Mon Sep 17 00:00:00 2001 From: progzone122 Date: Mon, 5 Oct 2026 13:27:11 +0300 Subject: [PATCH 3/9] replace disconnect button with a UButton from UmbrageKit --- src/ui/Components/Navigation/MainMenu.qml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/ui/Components/Navigation/MainMenu.qml b/src/ui/Components/Navigation/MainMenu.qml index ebea531..ade174d 100644 --- a/src/ui/Components/Navigation/MainMenu.qml +++ b/src/ui/Components/Navigation/MainMenu.qml @@ -2,6 +2,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import umbrage +import UmbrageKit 1.0 import UmbrageStyles 1.0 import Components 1.0 @@ -11,8 +12,6 @@ Item { Layout.fillHeight: true Layout.preferredWidth: 280 - property string activeSlot: "" - property bool bootloaderExpanded: false property bool flashingExpanded: false property bool otherExpanded: false @@ -176,21 +175,19 @@ Item { } } - Button { + UButton { Layout.preferredWidth: 42 Layout.preferredHeight: 48 - display: Button.IconOnly + iconDisplay: Button.TextBesideIcon icon.source: "qrc:/assets/disconnect-icon.svg" icon.color: Styles.surfaceForeground icon.width: 20 icon.height: 20 - background: Rectangle { - radius: Styles.radiusMedium - color: Styles.surfaceHigh - } + text: AppState.active_slot + backgroundColor: Styles.surfaceHigh onClicked: { AppState.disconnectDevice(); From 46cf63f50737a8c53da282f5041c70ae93f8ddb5 Mon Sep 17 00:00:00 2001 From: progzone122 Date: Mon, 5 Oct 2026 13:29:25 +0300 Subject: [PATCH 4/9] remove text --- src/ui/Components/Navigation/MainMenu.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ui/Components/Navigation/MainMenu.qml b/src/ui/Components/Navigation/MainMenu.qml index ade174d..60af258 100644 --- a/src/ui/Components/Navigation/MainMenu.qml +++ b/src/ui/Components/Navigation/MainMenu.qml @@ -186,7 +186,6 @@ Item { icon.width: 20 icon.height: 20 - text: AppState.active_slot backgroundColor: Styles.surfaceHigh onClicked: { From 7a4ac122ed007d8ddac99d368141408335158fb5 Mon Sep 17 00:00:00 2001 From: progzone122 Date: Mon, 5 Oct 2026 13:44:35 +0300 Subject: [PATCH 5/9] add icons --- src/ui/Assets/slot-a-icon.svg | 3 +++ src/ui/Assets/slot-b-icon.svg | 3 +++ src/ui/resources.qrc | 2 ++ 3 files changed, 8 insertions(+) create mode 100644 src/ui/Assets/slot-a-icon.svg create mode 100644 src/ui/Assets/slot-b-icon.svg diff --git a/src/ui/Assets/slot-a-icon.svg b/src/ui/Assets/slot-a-icon.svg new file mode 100644 index 0000000..a2d0171 --- /dev/null +++ b/src/ui/Assets/slot-a-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/Assets/slot-b-icon.svg b/src/ui/Assets/slot-b-icon.svg new file mode 100644 index 0000000..146c3e8 --- /dev/null +++ b/src/ui/Assets/slot-b-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/resources.qrc b/src/ui/resources.qrc index bd2fdc7..a4da819 100644 --- a/src/ui/resources.qrc +++ b/src/ui/resources.qrc @@ -24,6 +24,8 @@ Assets/collapse-icon.svg Assets/more-icon.svg Assets/trash-icon.svg + Assets/slot-a-icon.svg + Assets/slot-b-icon.svg From fe91fd46f212001d84f204a1ae6cbc107fbde143 Mon Sep 17 00:00:00 2001 From: progzone122 Date: Mon, 5 Oct 2026 14:21:13 +0300 Subject: [PATCH 6/9] add slot button --- src/state.rs | 4 +-- src/ui/Components/Navigation/MainMenu.qml | 42 +++++++++++++++++------ 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/state.rs b/src/state.rs index 32ae488..db8bb85 100644 --- a/src/state.rs +++ b/src/state.rs @@ -397,7 +397,7 @@ impl Default for AppState { da_file: String::new(), auth_file: String::new(), preloader_file: String::new(), - page: Page::Steps as u8, + page: Page::Main as u8, skip_conn_page: env::args().any(|arg| arg == "--skip-conn"), logs: Vec::new(), repo: serde_json::Value::Null, @@ -405,7 +405,7 @@ impl Default for AppState { connecting: false, chip_name: String::new(), chip_platform: String::new(), - device_name: String::new(), + device_name: "Lorem ipsum".to_string(), selected_codename: String::new(), connection_error: String::new(), device_tx: Arc::new(Mutex::new(None)), diff --git a/src/ui/Components/Navigation/MainMenu.qml b/src/ui/Components/Navigation/MainMenu.qml index 60af258..e11e32a 100644 --- a/src/ui/Components/Navigation/MainMenu.qml +++ b/src/ui/Components/Navigation/MainMenu.qml @@ -175,21 +175,41 @@ Item { } } - UButton { - Layout.preferredWidth: 42 - Layout.preferredHeight: 48 + RowLayout { - iconDisplay: Button.TextBesideIcon + spacing: Styles.spacing + + UButton { + Layout.preferredWidth: 42 + Layout.preferredHeight: 48 + + iconDisplay: Button.IconOnly - icon.source: "qrc:/assets/disconnect-icon.svg" - icon.color: Styles.surfaceForeground - icon.width: 20 - icon.height: 20 + icon.source: "qrc:/assets/slot-a-icon.svg" + icon.color: Styles.surfaceForeground + icon.width: 20 + icon.height: 20 + + text: AppState.active_slot + backgroundColor: Styles.surfaceHigh + } - backgroundColor: Styles.surfaceHigh + UButton { + Layout.preferredWidth: 42 + Layout.preferredHeight: 48 - onClicked: { - AppState.disconnectDevice(); + iconDisplay: Button.IconOnly + + icon.source: "qrc:/assets/disconnect-icon.svg" + icon.color: Styles.surfaceForeground + icon.width: 20 + icon.height: 20 + + backgroundColor: Styles.surfaceHigh + + onClicked: { + AppState.disconnectDevice(); + } } } } From b359b3124e62981f6ab637633e60d1855bc54657 Mon Sep 17 00:00:00 2001 From: progzone122 Date: Mon, 5 Oct 2026 14:43:53 +0300 Subject: [PATCH 7/9] add change slots logic --- src/ui/Components/Navigation/MainMenu.qml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ui/Components/Navigation/MainMenu.qml b/src/ui/Components/Navigation/MainMenu.qml index e11e32a..548578c 100644 --- a/src/ui/Components/Navigation/MainMenu.qml +++ b/src/ui/Components/Navigation/MainMenu.qml @@ -182,16 +182,19 @@ Item { UButton { Layout.preferredWidth: 42 Layout.preferredHeight: 48 - iconDisplay: Button.IconOnly - icon.source: "qrc:/assets/slot-a-icon.svg" + visible: AppState.active_slot !== "" + icon.source: AppState.active_slot === "A" ? "qrc:/assets/slot-a-icon.svg" : "qrc:/assets/slot-b-icon.svg" icon.color: Styles.surfaceForeground icon.width: 20 icon.height: 20 - text: AppState.active_slot backgroundColor: Styles.surfaceHigh + + onClicked: { + AppState.requestSetActiveSlot(AppState.active_slot === "A" ? "B" : "A"); + } } UButton { From 7d1d415fdb6dd22836ed606ca3f0665a690b51f9 Mon Sep 17 00:00:00 2001 From: progzone122 Date: Mon, 5 Oct 2026 20:21:36 +0300 Subject: [PATCH 8/9] add set active slot logic & dialog --- src/callbacks/device.rs | 109 +++++++++++++++++++++- src/state.rs | 14 +++ src/ui/Components/ModalDialog.qml | 7 +- src/ui/Components/Navigation/MainMenu.qml | 6 +- src/ui/Pages/MainPage.qml | 28 ++++++ 5 files changed, 159 insertions(+), 5 deletions(-) diff --git a/src/callbacks/device.rs b/src/callbacks/device.rs index d17a6b4..4ff13e3 100644 --- a/src/callbacks/device.rs +++ b/src/callbacks/device.rs @@ -3,7 +3,7 @@ use std::sync::mpsc::{self, Receiver, Sender}; use qtbridge::{QmlMethodInvoker, QmlObject, invoke_method}; -use penumbra_mtk::hacc::LockState; +use penumbra_mtk::hacc::{BootPartition, IntoBytes, LockState, OFFSET_SLOT_SUFFIX}; use penumbra_mtk::port::{MtkPort, PortBackend, PortType}; use crate::logs; @@ -46,6 +46,10 @@ pub(crate) enum DeviceCommand { RequestGetActiveSlot { invoker: QmlMethodInvoker, }, + RequestSetActiveSlot { + slot: BootPartition, + invoker: QmlMethodInvoker, + }, } /// Spawns the device worker thread and returns the command sender. The worker @@ -171,6 +175,18 @@ fn worker_loop(rx: Receiver) { invoke_method!(invoker, "activeSlotLoaded", slot); } + DeviceCommand::RequestSetActiveSlot { slot, invoker } => { + if let Some(dev) = device.as_mut() { + set_active_slot_on_worker(dev, slot, &invoker); + } else { + invoke_method!( + invoker, + "slotSwitchFinished", + false, + "No device connected".to_string() + ); + } + } } } } @@ -871,3 +887,94 @@ pub fn get_active_slot(state: &mut AppState) { let _ = tx.send(DeviceCommand::RequestGetActiveSlot { invoker }); } + +fn set_active_slot_on_worker( + dev: &mut penumbra_mtk::Device<'static, PortType>, + slot: BootPartition, + invoker: &QmlMethodInvoker, +) { + let name = format!("{slot:?}"); + + let log = |msg: String| { + invoke_method!(invoker, "appendLog", msg.clone()); + invoke_method!(invoker, "actionProgress", msg); + }; + + log("[Switch slot] Acquiring device handle...".to_string()); + + let mut bootctrl = match dev.get_bootctrl() { + Ok(b) => b, + Err(e) => { + let msg = format!( + "Failed to switch the active slot: {e}. The device may not support A/B slots." + ); + log(format!("[Switch slot] ERROR: {msg}")); + invoke_method!(invoker, "slotSwitchFinished", false, msg); + return; + } + }; + + if bootctrl.get_active_slot() == slot { + log(format!("[Switch slot] Active slot is already {name}.")); + invoke_method!( + invoker, + "slotSwitchFinished", + true, + format!("Active slot is already {name}.") + ); + return; + } + + bootctrl.set_active_slot(slot); + + // Boot control sits at a fixed offset in misc. + let bytes = bootctrl.as_bytes(); + let mut data = vec![0u8; OFFSET_SLOT_SUFFIX + bytes.len()]; + data[OFFSET_SLOT_SUFFIX..].copy_from_slice(bytes); + + if let Err(e) = dev.write_partition("misc", data.len(), &data[..], |_, _| {}) { + let msg = format!("Failed to write the boot control to 'misc': {e}."); + log(format!("[Switch slot] ERROR: {msg}")); + invoke_method!(invoker, "slotSwitchFinished", false, msg); + return; + } + + // get_bootctrl() serves a cached copy, so store the slot we just wrote; + // otherwise the next toggle reads the old one and short-circuits above. + dev.devinfo().set_bootctrl(bootctrl); + + log(format!("[Switch slot] Active slot set to {name}.")); + + // Update the badge before ending the dialog's wait. + invoke_method!(invoker, "activeSlotLoaded", name.clone()); + invoke_method!( + invoker, + "slotSwitchFinished", + true, + format!("Active slot set to {name}.") + ); +} + +pub fn set_active_slot(state: &mut AppState, slot: BootPartition) { + if !state.connected { + state.append_log("ERROR: No device connected".to_string()); + return; + } + + let invoker = state.get_qml_method_invoker(); + + let tx = match state.device_tx.lock().unwrap().as_ref() { + Some(tx) => tx.clone(), + None => { + invoke_method!( + invoker, + "slotSwitchFinished", + false, + "No device connection available".to_string() + ); + return; + } + }; + + let _ = tx.send(DeviceCommand::RequestSetActiveSlot { slot, invoker }); +} diff --git a/src/state.rs b/src/state.rs index db8bb85..e9db16d 100644 --- a/src/state.rs +++ b/src/state.rs @@ -208,6 +208,9 @@ impl AppState { #[qsignal] pub(crate) fn reboot_to_mode_finished(&mut self, success: bool, message: String); + #[qsignal] + pub(crate) fn slot_switch_finished(&mut self, success: bool, message: String); + #[qsignal] pub(crate) fn partition_progress(&mut self, message: String, percent: i32); @@ -384,6 +387,17 @@ impl AppState { callbacks::device::get_active_slot(self); } + #[qslot] + fn request_set_active_slot(&mut self, slot: String) { + let slot = match slot.as_str() { + "A" => penumbra_mtk::hacc::BootPartition::A, + "B" => penumbra_mtk::hacc::BootPartition::B, + _ => panic!("unknown boot slot: {slot}"), + }; + + callbacks::device::set_active_slot(self, slot); + } + #[qslot] pub(crate) fn active_slot_loaded(&mut self, slot: String) { self.active_slot = slot; diff --git a/src/ui/Components/ModalDialog.qml b/src/ui/Components/ModalDialog.qml index b043aec..cd35620 100644 --- a/src/ui/Components/ModalDialog.qml +++ b/src/ui/Components/ModalDialog.qml @@ -29,6 +29,9 @@ Popup { property bool showCancel: true property bool showConfirm: true + // Set false once an operation succeeds to block a second press; onOpened resets it. + property bool confirmEnabled: true + // Progress in 0..1 range. Negative hides the bar. property real progress: -1 property string progressText: "" @@ -50,6 +53,8 @@ Popup { focus: true + onOpened: root.confirmEnabled = true + background: Rectangle { color: Styles.surface radius: Styles.radiusMedium @@ -202,7 +207,7 @@ Popup { UButton { visible: root.showConfirm text: root.confirmText - disabled: root.busy + disabled: root.busy || !root.confirmEnabled onClicked: root.confirmed() } diff --git a/src/ui/Components/Navigation/MainMenu.qml b/src/ui/Components/Navigation/MainMenu.qml index 548578c..1e2b7c2 100644 --- a/src/ui/Components/Navigation/MainMenu.qml +++ b/src/ui/Components/Navigation/MainMenu.qml @@ -20,6 +20,8 @@ Item { // `key` matches an entry in the caller-provided `actions`. signal actionRequested(string key) + signal slotSwitchRequested + // Each entry: { key, section: "bootloader"|"flashing", text } property var actions: [] @@ -192,9 +194,7 @@ Item { backgroundColor: Styles.surfaceHigh - onClicked: { - AppState.requestSetActiveSlot(AppState.active_slot === "A" ? "B" : "A"); - } + onClicked: root.slotSwitchRequested() } UButton { diff --git a/src/ui/Pages/MainPage.qml b/src/ui/Pages/MainPage.qml index 832ec2b..4a6569e 100644 --- a/src/ui/Pages/MainPage.qml +++ b/src/ui/Pages/MainPage.qml @@ -320,6 +320,17 @@ Page { confirmDialog.open(); } } + + onSlotSwitchRequested: { + var target = AppState.active_slot === "A" ? "B" : "A"; + confirmDialog.actionKey = "switch_slots"; + confirmDialog.pendingSlot = target; + confirmDialog.title = qsTr("Switch to slot " + target + "?"); + confirmDialog.description = qsTr("The device will switch the active slot to " + target + "." + "\nBefore switching, make sure that the " + target + " slot contains a working preloader and an lk with the correct signature and version. Otherwise, the device may end up in a HARD BRICK state!"); + confirmDialog.confirmText = qsTr("Switch"); + confirmDialog.logText = "Please confirm that you are aware of all the risks and that you really do wish to proceed."; + confirmDialog.open(); + } } ColumnLayout { @@ -456,6 +467,7 @@ Page { id: confirmDialog property string actionKey: "" + property string pendingSlot: "" // No percentage is available for the seccfg write, so show a spinner. showSpinner: confirmDialog.busy @@ -501,6 +513,11 @@ Page { confirmDialog.logText += "\nReboot to TEST mode…"; AppState.rebootToMode("test"); } + + if (actionKey === "switch_slots") { + confirmDialog.logText += "\nSwitching active slot to " + confirmDialog.pendingSlot + "…"; + AppState.requestSetActiveSlot(confirmDialog.pendingSlot); + } } // Stream operation progress into the dialog's log panel. @@ -512,6 +529,7 @@ Page { function onBootloaderLockFinished(success, message) { confirmDialog.busy = false; if (success) { + confirmDialog.confirmEnabled = false; confirmDialog.logText += "\n" + qsTr("Done. Reboot the device to apply changes."); } else { confirmDialog.logText += "\n" + qsTr("Operation failed: ") + message; @@ -520,11 +538,21 @@ Page { function onRebootToModeFinished(success, message) { confirmDialog.busy = false; if (success) { + confirmDialog.confirmEnabled = false; confirmDialog.logText += "\n" + qsTr("Done. The device is rebooting."); } else { confirmDialog.logText += "\n" + qsTr("Operation failed: ") + message; } } + function onSlotSwitchFinished(success, message) { + confirmDialog.busy = false; + if (success) { + confirmDialog.confirmEnabled = false; + confirmDialog.logText += "\n" + qsTr("Done. The active slot has been switched to " + AppState.active_slot); + } else { + confirmDialog.logText += "\n" + qsTr("Operation failed: ") + message; + } + } } } From 128a305b3d28631af0dc957864e6af9ae587b35f Mon Sep 17 00:00:00 2001 From: progzone122 Date: Mon, 5 Oct 2026 20:22:24 +0300 Subject: [PATCH 9/9] revert default values in AppState --- src/state.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/state.rs b/src/state.rs index e9db16d..b56163b 100644 --- a/src/state.rs +++ b/src/state.rs @@ -411,7 +411,7 @@ impl Default for AppState { da_file: String::new(), auth_file: String::new(), preloader_file: String::new(), - page: Page::Main as u8, + page: Page::Steps as u8, skip_conn_page: env::args().any(|arg| arg == "--skip-conn"), logs: Vec::new(), repo: serde_json::Value::Null, @@ -419,7 +419,7 @@ impl Default for AppState { connecting: false, chip_name: String::new(), chip_platform: String::new(), - device_name: "Lorem ipsum".to_string(), + device_name: String::new(), selected_codename: String::new(), connection_error: String::new(), device_tx: Arc::new(Mutex::new(None)),