diff --git a/src/hooks/useBrotherMachine.ts b/src/hooks/useBrotherMachine.ts index 1229b57..845e5d5 100644 --- a/src/hooks/useBrotherMachine.ts +++ b/src/hooks/useBrotherMachine.ts @@ -27,7 +27,7 @@ export function useBrotherMachine() { ); const [uploadProgress, setUploadProgress] = useState(0); const [error, setError] = useState(null); - const [isPolling, setIsPolling] = useState(false); + const [isCommunicating, setIsCommunicating] = useState(false); const [isUploading, setIsUploading] = useState(false); const [isDeleting, setIsDeleting] = useState(false); const [resumeAvailable, setResumeAvailable] = useState(false); @@ -36,6 +36,12 @@ export function useBrotherMachine() { null, ); + // Subscribe to service communication state + useEffect(() => { + const unsubscribe = service.onCommunicationChange(setIsCommunicating); + return unsubscribe; + }, [service]); + // Define checkResume first (before connect uses it) const checkResume = useCallback(async (): Promise => { try { @@ -133,14 +139,11 @@ export function useBrotherMachine() { if (!isConnected) return; try { - setIsPolling(true); const state = await service.getMachineState(); setMachineStatus(state.status); setMachineError(state.error); } catch (err) { setError(err instanceof Error ? err.message : "Failed to get status"); - } finally { - setIsPolling(false); } }, [service, isConnected]); @@ -168,6 +171,22 @@ export function useBrotherMachine() { } }, [service, isConnected]); + const refreshServiceCount = useCallback(async () => { + if (!isConnected || !machineInfo) return; + + try { + const counts = await service.getServiceCount(); + setMachineInfo({ + ...machineInfo, + serviceCount: counts.serviceCount, + totalCount: counts.totalCount, + }); + } catch (err) { + // Don't set error for service count failures - it's not critical + console.warn("Failed to get service count:", err); + } + }, [service, isConnected, machineInfo]); + const loadCachedPattern = useCallback(async (): Promise<{ pesData: PesPatternData; patternOffset?: { x: number; y: number } } | null> => { if (!resumeAvailable) return null; @@ -349,8 +368,16 @@ export function useBrotherMachine() { } }, pollInterval); - return () => clearInterval(interval); - }, [isConnected, machineStatus, refreshStatus, refreshProgress]); + // Separate interval for service count (slower update rate - every 10 seconds) + const serviceCountInterval = setInterval(async () => { + await refreshServiceCount(); + }, 10000); + + return () => { + clearInterval(interval); + clearInterval(serviceCountInterval); + }; + }, [isConnected, machineStatus, refreshStatus, refreshProgress, refreshServiceCount]); // Refresh pattern info when status changes to SEWING_WAIT // (indicates pattern was just uploaded or is ready) @@ -372,7 +399,7 @@ export function useBrotherMachine() { sewingProgress, uploadProgress, error, - isPolling, + isPolling: isCommunicating, isUploading, isDeleting, resumeAvailable, diff --git a/src/services/BrotherPP1Service.ts b/src/services/BrotherPP1Service.ts index f480ad5..d19618c 100644 --- a/src/services/BrotherPP1Service.ts +++ b/src/services/BrotherPP1Service.ts @@ -47,6 +47,29 @@ export class BrotherPP1Service { private readCharacteristic: BluetoothRemoteGATTCharacteristic | null = null; private commandQueue: Array<() => Promise> = []; private isProcessingQueue = false; + private isCommunicating = false; + private communicationCallbacks: Set<(isCommunicating: boolean) => void> = new Set(); + + /** + * Subscribe to communication state changes + * @param callback Function called when communication state changes + * @returns Unsubscribe function + */ + onCommunicationChange(callback: (isCommunicating: boolean) => void): () => void { + this.communicationCallbacks.add(callback); + // Immediately call with current state + callback(this.isCommunicating); + return () => { + this.communicationCallbacks.delete(callback); + }; + } + + private setCommunicating(value: boolean) { + if (this.isCommunicating !== value) { + this.isCommunicating = value; + this.communicationCallbacks.forEach(callback => callback(value)); + } + } async connect(): Promise { this.device = await navigator.bluetooth.requestDevice({ @@ -103,6 +126,7 @@ export class BrotherPP1Service { } this.isProcessingQueue = true; + this.setCommunicating(true); while (this.commandQueue.length > 0) { const command = this.commandQueue.shift(); @@ -117,6 +141,7 @@ export class BrotherPP1Service { } this.isProcessingQueue = false; + this.setCommunicating(false); } /**