Repository navigation
feat(ux): central actionable toast for PTP Ethernet failures and board events, including Advanced #273
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(ux): central actionable toast for PTP Ethernet failures and board events, including Advanced #273
Changes from all commits
b6a45ca
2cda834
2736431
7583906
9bbe201
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -210,6 +210,10 @@ ApplicationWindow { | |
| function onDeviceMessage(message) { | ||
| root.showMessage(message, false) | ||
| } | ||
| function onLastErrorChanged() { | ||
| if (device.lastError && device.lastError.length > 0) | ||
| root.showMessage(device.lastError, true) | ||
| } | ||
| function onSvStopReasonChanged() { | ||
| if (!device.running && device.svStopReason !== "" && | ||
| device.svStopReason !== "AWAITING_BOARD_CAUSE") { | ||
|
|
@@ -310,18 +314,51 @@ ApplicationWindow { | |
| ListElement { timeText: "--:--:--"; messageText: "ARStack Studio ready."; isError: false } | ||
| } | ||
|
|
||
| property string lastToastKey: "" | ||
| property double lastToastAt: 0 | ||
| function explainFailure(message) { | ||
| const m = String(message || "") | ||
| if (m.indexOf("ETHERNET_LINK_DOWN") >= 0 || | ||
| m.indexOf("Ethernet PHY link is DOWN") >= 0 || | ||
| m.indexOf("source did not emit") >= 0 || | ||
| m.indexOf("no verified Announce") >= 0) | ||
| return "PTP belum bisa aktif. Sambungkan kabel LAN ESP32-P4 ke switch/port Ethernet aktif, tunggu PHY UP, lalu START PTP." | ||
| if (m.indexOf("ETHERNET_DRIVER_NOT_STARTED") >= 0 || | ||
| m.indexOf("ETHERNET_DRIVER_UNAVAILABLE") >= 0) | ||
| return "Driver Ethernet ESP32-P4 belum siap. Periksa koneksi board, lalu restart perangkat bila driver tetap STOPPED." | ||
| if (m.indexOf("ETHERNET_TX_INVALID_STATE") >= 0 || | ||
| m.indexOf("ESP_ERR_INVALID_STATE") >= 0) | ||
| return "PTP TX ditolak EMAC. Periksa Driver/PHY di Advanced → Time Sync; salin diagnostics jika PHY sudah UP." | ||
| if (m.indexOf("LEASE_EXPIRED") >= 0) | ||
| return "Injeksi SV berhenti: heartbeat kontrol USB terputus. Periksa kabel USB/COM lalu START kembali." | ||
| if (m.indexOf("RUNTIME_FAULT") >= 0) | ||
| return "Board menghentikan injeksi SV karena gangguan runtime. Buka Copy diagnostics sebelum START ulang." | ||
| return m | ||
| } | ||
| function showMessage(message, error) { | ||
| if (!message || String(message).trim().length === 0) return | ||
| statusMessage = message | ||
| transientMessage = error === true ? message : "" | ||
| transientError = error === true | ||
| const critical = error === true | ||
| const userMessage = critical ? explainFailure(message) : String(message) | ||
| const key = (critical ? "E:" : "I:") + userMessage | ||
| const now = Date.now() | ||
| const duplicate = key === lastToastKey && now - lastToastAt < 4000 | ||
|
Comment on lines
+343
to
+345
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The four-second deduplication cannot provide another toast for a repeated native error because Useful? React with 👍 / 👎. |
||
| const meaningful = critical || /accepted|ready|connected|installed|updated|stopped|started|saved|completed|success/i.test(userMessage) | ||
| if (meaningful && !duplicate) { | ||
| lastToastKey = key | ||
| lastToastAt = now | ||
| transientMessage = userMessage | ||
| transientError = critical | ||
| messageTimer.interval = critical ? 4200 : 2300 | ||
| messageTimer.restart() | ||
| } | ||
| statusHistoryModel.append({ | ||
| timeText: new Date().toLocaleTimeString(Qt.locale(), "HH:mm:ss"), | ||
| messageText: message, | ||
| isError: error === true | ||
| }) | ||
| while (statusHistoryModel.count > 100) | ||
| statusHistoryModel.remove(0) | ||
| messageTimer.restart() | ||
| } | ||
|
|
||
| function detachPhasor() { | ||
|
|
@@ -847,6 +884,15 @@ ApplicationWindow { | |
| configurationWindow.hide() | ||
| } | ||
|
|
||
| StatusToast { | ||
| anchors.centerIn: parent | ||
| z: 1500 | ||
| theme: studioTheme | ||
| uiFont: root.uiFont | ||
| message: root.toastMessage | ||
| error: root.toastError | ||
| } | ||
|
|
||
| DockFrame { | ||
| anchors.fill: parent | ||
| anchors.margins: 10 | ||
|
|
@@ -1370,9 +1416,8 @@ ApplicationWindow { | |
| } | ||
|
|
||
| StatusToast { | ||
| anchors.horizontalCenter: parent.horizontalCenter | ||
| anchors.bottom: parent.bottom | ||
| anchors.bottomMargin: 38 | ||
| anchors.centerIn: parent | ||
| z: 1500 | ||
| theme: studioTheme | ||
| uiFont: root.uiFont | ||
| message: root.toastMessage | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DeviceController::setError()emitslastErrorChangedand thendeviceMessagefor the same failure, so this new handler first records/displays it as critical and the existingonDeviceMessageimmediately processes it again as informational. Every native error therefore creates duplicate history entries with conflicting severity, and errors containing words matched bymeaningful—for example the Ethernet-driver message containing “not STARTED”—replace the critical 4.2-second toast with a non-error 2.3-second toast. Suppress the paired informational handling or expose a single severity-aware event.Useful? React with 👍 / 👎.