Skip to content

Commit ee72732

Browse files
committed
lil more
1 parent 68ec674 commit ee72732

File tree

3 files changed

+67
-83
lines changed

3 files changed

+67
-83
lines changed

src/app/Flash.jsx

Lines changed: 37 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,6 @@ const errors = {
145145
},
146146
}
147147

148-
// Note: qcserial unbind hint is added dynamically in the component based on device type
149-
150148

151149
function LinearProgress({ value, barColor }) {
152150
if (value === -1 || value > 100) value = 100
@@ -501,12 +499,14 @@ const screenToStep = {
501499
}
502500

503501
export default function Flash() {
504-
const [step, setStep] = useState(StepCode.INITIALIZING)
505-
const [message, setMessage] = useState('')
506-
const [progress, setProgress] = useState(-1)
507-
const [error, setError] = useState(ErrorCode.NONE)
508-
const [connected, setConnected] = useState(false)
509-
const [serial, setSerial] = useState(null)
502+
const [status, setStatus] = useState({
503+
step: StepCode.INITIALIZING,
504+
message: '',
505+
progress: -1,
506+
error: ErrorCode.NONE,
507+
connected: false,
508+
serial: null,
509+
})
510510
const [selectedDevice, setSelectedDevice] = useState(null)
511511
const [wizardScreen, setWizardScreen] = useState('landing') // 'landing', 'device', 'zadig', 'connect', 'unbind', 'webusb', 'flash'
512512

@@ -524,51 +524,40 @@ export default function Flash() {
524524
.then((res) => res.arrayBuffer())
525525
.then((programmer) => {
526526
// Create QDL manager with callbacks that update React state
527-
qdlManager.current = new FlashManager(programmer, {
528-
onStepChange: setStep,
529-
onMessageChange: setMessage,
530-
onProgressChange: setProgress,
531-
onErrorChange: setError,
532-
onConnectionChange: setConnected,
533-
onSerialChange: setSerial
527+
qdlManager.current = new FlashManager(programmer, (update) => {
528+
setStatus((prev) => ({ ...prev, ...update }))
534529
})
535530

536531
// Initialize the manager
537532
return qdlManager.current.initialize(imageManager.current)
538533
})
539534
.catch((err) => {
540535
console.error('Error initializing Flash manager:', err)
541-
setError(ErrorCode.UNKNOWN)
536+
setStatus((prev) => ({ ...prev, error: ErrorCode.UNKNOWN }))
542537
})
543538
}, [config, imageManager.current])
544539

545540
// Transition to flash screen when connected
546541
useEffect(() => {
547-
if (connected && wizardScreen === 'webusb') {
542+
if (status.connected && wizardScreen === 'webusb') {
548543
setWizardScreen('flash')
549544
}
550-
}, [connected, wizardScreen])
545+
}, [status.connected, wizardScreen])
551546

552547
// Handle user clicking start on landing page
553548
const handleStart = () => {
554-
setStep(StepCode.DEVICE_PICKER)
549+
setStatus((prev) => ({ ...prev, step: StepCode.DEVICE_PICKER }))
555550
setWizardScreen('device')
556551
}
557552

558553
// Handle device selection
559554
const handleDeviceSelect = (deviceType) => {
560555
setSelectedDevice(deviceType)
561-
if (isWindows) {
562-
setWizardScreen('zadig')
563-
} else {
564-
setWizardScreen('connect')
565-
}
556+
setWizardScreen(isWindows ? 'zadig' : 'connect')
566557
}
567558

568559
// Handle zadig done
569-
const handleZadigDone = () => {
570-
setWizardScreen('connect')
571-
}
560+
const handleZadigDone = () => setWizardScreen('connect')
572561

573562
// Handle connect instructions next
574563
const handleConnectNext = () => {
@@ -581,21 +570,17 @@ export default function Flash() {
581570
}
582571

583572
// Handle linux unbind done
584-
const handleUnbindDone = () => {
585-
setWizardScreen('webusb')
586-
}
573+
const handleUnbindDone = () => setWizardScreen('webusb')
587574

588575
// Handle WebUSB connect button
589-
const handleWebUSBConnect = () => {
590-
qdlManager.current?.start()
591-
}
576+
const handleWebUSBConnect = () => qdlManager.current?.start()
592577

593578
// Handle going back in wizard
594579
const handleWizardBack = (toStep) => {
595580
const stepName = wizardSteps[toStep]
596581
const backMapping = {
597582
Device: () => {
598-
setStep(StepCode.DEVICE_PICKER)
583+
setStatus((prev) => ({ ...prev, step: StepCode.DEVICE_PICKER }))
599584
setWizardScreen('device')
600585
setSelectedDevice(null)
601586
},
@@ -610,19 +595,22 @@ export default function Flash() {
610595
const handleRetry = () => window.location.reload()
611596

612597
// Transitions & UI State
613-
const uiState = steps[step] || {}
614-
if (error) {
615-
Object.assign(uiState, errors[ErrorCode.UNKNOWN], errors[error])
598+
// FIX: use spread to avoid mutating constant 'steps'
599+
const uiState = { ...(steps[status.step] || {}) }
600+
if (status.error !== ErrorCode.NONE) {
601+
Object.assign(uiState, errors[ErrorCode.UNKNOWN], errors[status.error])
616602
}
617-
let { status, description, bgColor = 'bg-gray-400', icon = bolt, iconStyle = 'invert', hideRetry = false } = uiState
603+
let { status: statusText, description, bgColor = 'bg-gray-400', icon = bolt, iconStyle = 'invert', hideRetry = false } = uiState
618604

619-
if (error === ErrorCode.LOST_CONNECTION && isLinux && selectedDevice === DeviceType.COMMA_3) {
605+
if (status.error === ErrorCode.LOST_CONNECTION && isLinux && selectedDevice === DeviceType.COMMA_3) {
620606
description += ' Did you forget to unbind the device from qcserial?'
621607
}
622608

623-
let title = (message && !error) ? `${message}...${progress >= 0 ? ` (${(progress * 100).toFixed(0)}%)` : ''}` : (error === ErrorCode.STORAGE_SPACE ? message : status)
609+
let title = (status.message && status.error === ErrorCode.NONE)
610+
? `${status.message}...${status.progress >= 0 ? ` (${(status.progress * 100).toFixed(0)}%)` : ''}`
611+
: (status.error === ErrorCode.STORAGE_SPACE ? status.message : statusText)
624612

625-
if (step >= StepCode.REPAIR_PARTITION_TABLES && step <= StepCode.FINALIZING && error === ErrorCode.NONE) {
613+
if (status.step >= StepCode.REPAIR_PARTITION_TABLES && status.step <= StepCode.FINALIZING && status.error === ErrorCode.NONE) {
626614
window.addEventListener("beforeunload", beforeUnloadListener, { capture: true })
627615
} else {
628616
window.removeEventListener("beforeunload", beforeUnloadListener, { capture: true })
@@ -636,7 +624,7 @@ export default function Flash() {
636624
webusb: <WebUSBConnect onConnect={handleWebUSBConnect} />,
637625
}
638626

639-
if (wizardScreen === 'landing' && !error) {
627+
if (wizardScreen === 'landing' && status.error === ErrorCode.NONE) {
640628
return (
641629
<>
642630
<ImagePreloader />
@@ -645,8 +633,8 @@ export default function Flash() {
645633
)
646634
}
647635

648-
const canGoBack = (step === StepCode.CONNECTING && !connected) || (wizardStep >= 0 && wizardStep < wizardSteps.indexOf('Flash'))
649-
const activeWizardScreen = !error && WIZARD_SCREENS[wizardScreen]
636+
const canGoBack = (status.step === StepCode.CONNECTING && !status.connected) || (wizardStep >= 0 && wizardStep < wizardSteps.indexOf('Flash'))
637+
const activeWizardScreen = status.error === ErrorCode.NONE && WIZARD_SCREENS[wizardScreen]
650638

651639
return (
652640
<div id="flash" className="wizard-screen relative flex flex-col gap-8 justify-center items-center h-full">
@@ -665,23 +653,23 @@ export default function Flash() {
665653
alt="status"
666654
width={128}
667655
height={128}
668-
className={`${iconStyle} ${!error && step !== StepCode.DONE ? 'animate-pulse' : ''}`}
656+
className={`${iconStyle} ${status.error === ErrorCode.NONE && status.step !== StepCode.DONE ? 'animate-pulse' : ''}`}
669657
/>
670658
</div>
671-
<div className="w-full max-w-3xl px-8 transition-opacity duration-300" style={{ opacity: progress === -1 ? 0 : 1 }}>
672-
<LinearProgress value={progress * 100} barColor={bgColor} />
659+
<div className="w-full max-w-3xl px-8 transition-opacity duration-300" style={{ opacity: status.progress === -1 ? 0 : 1 }}>
660+
<LinearProgress value={status.progress * 100} barColor={bgColor} />
673661
</div>
674662
<span className="text-3xl font-mono font-light">{title}</span>
675663
<span className="text-xl px-8 max-w-xl text-center">{description}</span>
676-
{error !== ErrorCode.NONE && !hideRetry && (
664+
{status.error !== ErrorCode.NONE && !hideRetry && (
677665
<button
678666
className="px-4 py-2 rounded-md bg-gray-200 hover:bg-gray-300 text-gray-800 transition-colors"
679667
onClick={handleRetry}
680668
>
681669
Retry
682670
</button>
683671
)}
684-
{connected && <DeviceState serial={serial} />}
672+
{status.connected && <DeviceState serial={status.serial} />}
685673
</>
686674
)}
687675
</div>

src/utils/manager.js

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -101,34 +101,32 @@ export function checkCompatibleDevice(storageInfo) {
101101
}
102102

103103
/**
104-
* @template T
105-
* @callback ChangeCallback
106-
* @param {T} value
107-
* @returns {void}
104+
* @typedef {object} FlashStatus
105+
* @property {number} [step]
106+
* @property {string} [message]
107+
* @property {number} [progress]
108+
* @property {number} [error]
109+
* @property {boolean} [connected]
110+
* @property {string} [serial]
108111
*/
109112

110113
/**
111-
* @typedef {object} FlashManagerCallbacks
112-
* @property {ChangeCallback<number>} [onStepChange]
113-
* @property {ChangeCallback<string>} [onMessageChange]
114-
* @property {ChangeCallback<number>} [onProgressChange]
115-
* @property {ChangeCallback<number>} [onErrorChange]
116-
* @property {ChangeCallback<boolean>} [onConnectionChange]
117-
* @property {ChangeCallback<string>} [onSerialChange]
114+
* @callback UpdateCallback
115+
* @param {FlashStatus} status
116+
* @returns {void}
118117
*/
119118

120119
export class FlashManager {
121120
/** @type {string} */
122121
#userdataImage
123122

124123
/**
125-
* @param {string} manifestUrl
126124
* @param {ArrayBuffer} programmer
127-
* @param {FlashManagerCallbacks} callbacks
125+
* @param {UpdateCallback} onUpdate
128126
*/
129-
constructor(programmer, callbacks = {}) {
127+
constructor(programmer, onUpdate) {
130128
this.manifestUrl = null
131-
this.callbacks = callbacks
129+
this.onUpdate = onUpdate
132130
this.device = new qdlDevice(programmer)
133131
/** @type {import('./image').ImageManager|null} */
134132
this.imageManager = null
@@ -138,42 +136,45 @@ export class FlashManager {
138136
this.error = ErrorCode.NONE
139137
}
140138

139+
/** @param {FlashStatus} update */
140+
#update(update) {
141+
if (update.message) console.info('[Flash]', update.message)
142+
if (update.error !== undefined && update.error !== ErrorCode.NONE) {
143+
console.debug('[Flash] error', update.error)
144+
}
145+
this.onUpdate(update)
146+
}
147+
141148
/** @param {number} step */
142149
#setStep(step) {
143150
this.step = step
144-
this.callbacks.onStepChange?.(step)
151+
this.#update({ step })
145152
}
146153

147154
/** @param {string} message */
148155
#setMessage(message) {
149-
if (message) console.info('[Flash]', message)
150-
this.callbacks.onMessageChange?.(message)
156+
this.#update({ message })
151157
}
152158

153159
/** @param {number} progress */
154160
#setProgress(progress) {
155-
this.callbacks.onProgressChange?.(progress)
161+
this.#update({ progress })
156162
}
157163

158164
/** @param {number} error */
159165
#setError(error) {
160166
this.error = error
161-
this.callbacks.onErrorChange?.(error)
162-
this.#setProgress(-1)
163-
164-
if (error !== ErrorCode.NONE) {
165-
console.debug('[Flash] error', error)
166-
}
167+
this.#update({ error, progress: -1 })
167168
}
168169

169170
/** @param {boolean} connected */
170171
#setConnected(connected) {
171-
this.callbacks.onConnectionChange?.(connected)
172+
this.#update({ connected })
172173
}
173174

174175
/** @param {string} serial */
175176
#setSerial(serial) {
176-
this.callbacks.onSerialChange?.(serial)
177+
this.#update({ serial })
177178
}
178179

179180
/** @returns {boolean} */
@@ -199,8 +200,7 @@ export class FlashManager {
199200
/** @param {import('./image').ImageManager} imageManager */
200201
async initialize(imageManager) {
201202
this.imageManager = imageManager
202-
this.#setProgress(-1)
203-
this.#setMessage('')
203+
this.#update({ progress: -1, message: '' })
204204

205205
if (!this.#checkRequirements()) {
206206
return

src/utils/platform.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
// Force Windows mode for development - shows Zadig driver instructions
2-
// Enable with ?windows=1 in URL
1+
// Force Windows mode for development - Enable with ?windows=1 in URL
32
const FORCE_WINDOWS = new URLSearchParams(window.location.search).has('windows')
4-
if (FORCE_WINDOWS) {
5-
console.warn('[Platform] FORCE WINDOWS MODE ENABLED')
6-
}
73

84
const platform = (() => {
95
if ('userAgentData' in navigator && 'platform' in navigator.userAgentData && navigator.userAgentData.platform) {

0 commit comments

Comments
 (0)