CameraPage-DvMFfXde.js 14 KB

1
  1. import{i as e}from"./chunk-aKtaBQYM.js";import{C as t,D as n,S as r,a as i,d as a,l as ee,w as te}from"./client-DnySrlFv.js";import{n as ne}from"./QueryClientProvider-Ce8_sN3w.js";import{t as o}from"./useQuery-BBCjCezC.js";import{t as re}from"./useMutation-B-Tr2hIP.js";import{t as s}from"./createLucideIcon-DvBYJlWL.js";import{n as ie}from"./ToastContext-BRX0SW3C.js";import{a as ae,i as oe,n as se,r as ce,t as le}from"./CameraDiagnoseModal-B8tzQ5r7.js";import{t as ue}from"./triangle-alert-Dt_1FcBy.js";import{n as de,t as fe}from"./zoom-out-DNNe6DMN.js";import{Ct as pe,Ft as me,Kt as he,Pn as ge,Un as _e,Wn as ve,n as ye,yt as be}from"./index-B-1xu8EB.js";import{t as xe}from"./useStreamImgRef-CRYQNmK0.js";var Se=s(`maximize`,[[`path`,{d:`M8 3H5a2 2 0 0 0-2 2v3`,key:`1dcmit`}],[`path`,{d:`M21 8V5a2 2 0 0 0-2-2h-3`,key:`1e4gt3`}],[`path`,{d:`M3 16v3a2 2 0 0 0 2 2h3`,key:`wsl5sc`}],[`path`,{d:`M16 21h3a2 2 0 0 0 2-2v-3`,key:`18trek`}]]),c=e(n(),1),l=t(),u=5,Ce=2e3,we=3e4,Te=5e3;function d(){let{t:e}=te(),t=ne(),{showToast:n}=ie(),{hasPermission:s,authEnabled:d,user:Ee}=be(),{printerId:De}=_e(),f=parseInt(De||`0`,10),[Oe]=ve(),ke=parseInt(Oe.get(`fps`)||`15`,10),Ae=Math.min(Math.max(isNaN(ke)?15:ke,1),30);ye();let{data:je,isPending:Me}=o({queryKey:[`camera-stream-token`,Ee?.id??null],queryFn:()=>i.getCameraStreamToken(),enabled:d?!!Ee:!0,staleTime:3e3*1e3}),p=je?.token??a(),[m,Ne]=(0,c.useState)(`stream`),[Pe,Fe]=(0,c.useState)(!1),[Ie,h]=(0,c.useState)(!1),[g,_]=(0,c.useState)(!1),[v,y]=(0,c.useState)(!0),[b,x]=(0,c.useState)(Date.now()),[S,C]=(0,c.useState)(!1),[Le,Re]=(0,c.useState)(!1),[w,T]=(0,c.useState)(0),[E,D]=(0,c.useState)(!1),[ze,Be]=(0,c.useState)(0),[O,k]=(0,c.useState)(1),[A,j]=(0,c.useState)({x:0,y:0}),[M,N]=(0,c.useState)(!1),[P,Ve]=(0,c.useState)({x:0,y:0}),[F,I]=(0,c.useState)(null),[L,R]=(0,c.useState)(null),z=(0,c.useRef)(null),He=xe(z),B=(0,c.useRef)(null),V=(0,c.useRef)(null),H=(0,c.useRef)(null),U=(0,c.useRef)(null),W=(0,c.useRef)(0),{data:G}=o({queryKey:[`printer`,f],queryFn:()=>i.getPrinter(f),enabled:f>0}),{data:K}=o({queryKey:[`printerStatus`,f],queryFn:()=>i.getPrinterStatus(f),refetchInterval:3e4,enabled:f>0}),Ue=re({mutationFn:e=>i.setChamberLight(f,e),onMutate:async e=>{await t.cancelQueries({queryKey:[`printerStatus`,f]});let n=t.getQueryData([`printerStatus`,f]);return t.setQueryData([`printerStatus`,f],t=>({...t,chamber_light:e})),{previousStatus:n}},onSuccess:(e,t)=>{n(`Chamber light ${t?`on`:`off`}`)},onError:(r,i,a)=>{a?.previousStatus&&t.setQueryData([`printerStatus`,f],a.previousStatus),n(r.message||e(`printers.toast.failedToControlChamberLight`),`error`)}}),q=(K?.state===`RUNNING`||K?.state===`PAUSE`)&&(K?.printable_objects_count??0)>=2;(0,c.useEffect)(()=>(G&&(document.title=`${G.name} - Camera`),()=>{document.title=`Bambuddy`}),[G]);let J=(0,c.useRef)(!1);(0,c.useEffect)(()=>{let e=`/api/v1/printers/${f}/camera/stop`;J.current=!1;let t=()=>{if(f>0&&!J.current){J.current=!0;let t={},n=ee();n&&(t.Authorization=`Bearer ${n}`),fetch(e,{method:`POST`,keepalive:!0,headers:t}).catch(()=>{})}},n=()=>{t()};return window.addEventListener(`beforeunload`,n),()=>{window.removeEventListener(`beforeunload`,n),t()}},[f]),(0,c.useEffect)(()=>{if(v&&!S){let e=setTimeout(()=>{y(!1)},m===`stream`?3e3:2e4);return()=>clearTimeout(e)}},[m,v,b,S]),(0,c.useEffect)(()=>{let e=()=>{Re(!!document.fullscreenElement),k(1),j({x:0,y:0}),m===`stream`&&!S&&(z.current&&(z.current.src=``),setTimeout(()=>{y(!0),x(Date.now())},200))};return document.addEventListener(`fullscreenchange`,e),()=>document.removeEventListener(`fullscreenchange`,e)},[m,S]),(0,c.useEffect)(()=>{let e,t=()=>{clearTimeout(e),e=setTimeout(()=>{localStorage.setItem(`cameraWindowState`,JSON.stringify({width:window.outerWidth,height:window.outerHeight,left:window.screenX,top:window.screenY}))},500)};return window.addEventListener(`resize`,t),()=>{clearTimeout(e),window.removeEventListener(`resize`,t)}},[]),(0,c.useEffect)(()=>()=>{V.current&&clearTimeout(V.current),H.current&&clearInterval(H.current),U.current&&clearInterval(U.current)},[]);let Y=(0,c.useCallback)(()=>{if(w>=u){D(!1),_(!0);return}let e=Math.min(Ce*2**w,we);D(!0),Be(Math.ceil(e/1e3)),H.current=setInterval(()=>{Be(e=>e<=1?(H.current&&clearInterval(H.current),0):e-1)},1e3),V.current=setTimeout(()=>{T(e=>e+1),D(!1),y(!0),_(!1),z.current&&(z.current.src=``),x(Date.now())},e)},[w]);(0,c.useEffect)(()=>{if(m!==`stream`||v||E||S){U.current&&=(clearInterval(U.current),null);return}return W.current=0,U.current=setInterval(async()=>{try{let e=await i.getCameraStatus(f);if(!(e.stalled||!e.active&&!g)){W.current=0;return}if(W.current+=1,W.current<2)return;W.current=0,console.log(`Stream issue detected: stalled=${e.stalled}, active=${e.active}, reconnecting...`),U.current&&=(clearInterval(U.current),null),y(!1),Y()}catch{}},Te),()=>{U.current&&=(clearInterval(U.current),null)}},[m,v,g,E,S,f,Y]);let We=e=>{e.currentTarget.getAttribute(`src`)&&(y(!1),m===`stream`&&w<u?Y():_(!0))},Ge=()=>{if(y(!1),_(!1),T(0),W.current=0,D(!1),V.current&&clearTimeout(V.current),H.current&&clearInterval(H.current),z.current&&!localStorage.getItem(`cameraWindowState`)){let e=z.current,t=e.naturalWidth,n=e.naturalHeight;if(t>0&&n>0){let e=window.outerWidth-window.innerWidth,r=window.outerHeight-window.innerHeight,i=t+16+e,a=n+45+16+r;try{window.resizeTo(i,a)}catch{}}}},Ke=()=>{if(f>0){let e={},t=ee();t&&(e.Authorization=`Bearer ${t}`),fetch(`/api/v1/printers/${f}/camera/stop`,{method:`POST`,headers:e}).catch(()=>{})}},qe=e=>{m===e||S||(C(!0),y(!0),_(!1),T(0),D(!1),k(1),j({x:0,y:0}),V.current&&clearTimeout(V.current),H.current&&clearInterval(H.current),z.current&&(z.current.src=``),m===`stream`&&Ke(),setTimeout(()=>{Ne(e),x(Date.now()),C(!1)},100))},X=()=>{S||(C(!0),y(!0),_(!1),T(0),D(!1),V.current&&clearTimeout(V.current),H.current&&clearInterval(H.current),z.current&&(z.current.src=``),m===`stream`&&Ke(),setTimeout(()=>{x(Date.now()),C(!1)},100))},Je=()=>{B.current&&(document.fullscreenElement?document.exitFullscreen():B.current.requestFullscreen())},Ye=()=>{k(e=>Math.min(e+.5,4))},Xe=()=>{k(e=>{let t=Math.max(e-.5,1);return t===1&&j({x:0,y:0}),t})},Ze=e=>{e.preventDefault(),e.deltaY<0?Ye():Xe()},Qe=e=>{O>1&&(e.preventDefault(),N(!0),Ve({x:e.clientX-A.x,y:e.clientY-A.y}))},Z=(0,c.useCallback)(()=>{if(!B.current)return{x:300,y:200};let e=B.current.getBoundingClientRect(),t=e.width*(O-1)/2,n=e.height*(O-1)/2;return{x:Math.max(50,t),y:Math.max(50,n)}},[O]),$e=e=>{if(M&&O>1){let t=e.clientX-P.x,n=e.clientY-P.y,r=Z();j({x:Math.max(-r.x,Math.min(r.x,t)),y:Math.max(-r.y,Math.min(r.y,n))})}},et=()=>{N(!1)},tt=e=>{if(e.length<2)return 0;let t=e[0].clientX-e[1].clientX,n=e[0].clientY-e[1].clientY;return Math.sqrt(t*t+n*n)},nt=e=>e.length<2?{x:e[0].clientX,y:e[0].clientY}:{x:(e[0].clientX+e[1].clientX)/2,y:(e[0].clientY+e[1].clientY)/2},rt=e=>{e.touches.length===2?(e.preventDefault(),I(tt(e.touches)),R(nt(e.touches))):e.touches.length===1&&O>1&&(e.preventDefault(),N(!0),Ve({x:e.touches[0].clientX-A.x,y:e.touches[0].clientY-A.y}))},it=e=>{if(e.touches.length===2&&F!==null){e.preventDefault();let t=tt(e.touches),n=t/F;k(e=>{let t=Math.max(1,Math.min(4,e*n));return t===1&&j({x:0,y:0}),t}),I(t);let r=nt(e.touches);if(L){let e=Z();j(t=>({x:Math.max(-e.x,Math.min(e.x,t.x+(r.x-L.x))),y:Math.max(-e.y,Math.min(e.y,t.y+(r.y-L.y)))}))}R(r)}else if(e.touches.length===1&&M&&O>1){e.preventDefault();let t=e.touches[0].clientX-P.x,n=e.touches[0].clientY-P.y,r=Z();j({x:Math.max(-r.x,Math.min(r.x,t)),y:Math.max(-r.y,Math.min(r.y,n))})}},at=e=>{e.touches.length<2&&(I(null),R(null)),e.touches.length===0&&N(!1)},ot=()=>{k(1),j({x:0,y:0})},Q=S||!p&&(d||Me)?``:(e=>p?`${e}&token=${encodeURIComponent(p)}`:r(e))(m===`stream`?`/api/v1/printers/${f}/camera/stream?fps=${Ae}&t=${b}`:`/api/v1/printers/${f}/camera/snapshot?t=${b}`),$=v||S||E;return f?(0,l.jsxs)(`div`,{ref:B,className:`min-h-screen bg-black flex flex-col`,children:[(0,l.jsxs)(`div`,{className:`flex items-center justify-between px-4 py-2 bg-bambu-dark-secondary border-b border-bambu-dark-tertiary`,children:[(0,l.jsxs)(`h1`,{className:`text-sm font-medium text-white flex items-center gap-2`,children:[(0,l.jsx)(ge,{className:`w-4 h-4`}),G?.name||`Printer ${f}`]}),(0,l.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,l.jsxs)(`div`,{className:`flex bg-bambu-dark rounded p-0.5`,children:[(0,l.jsx)(`button`,{onClick:()=>qe(`stream`),disabled:$,className:`px-3 py-1 text-xs rounded transition-colors ${m===`stream`?`bg-bambu-green text-white`:`text-bambu-gray hover:text-white disabled:opacity-50`}`,children:e(`camera.live`)}),(0,l.jsx)(`button`,{onClick:()=>qe(`snapshot`),disabled:$,className:`px-3 py-1 text-xs rounded transition-colors ${m===`snapshot`?`bg-bambu-green text-white`:`text-bambu-gray hover:text-white disabled:opacity-50`}`,children:e(`camera.snapshot`)})]}),(0,l.jsx)(`button`,{onClick:()=>Ue.mutate(!K?.chamber_light),disabled:!K?.connected||Ue.isPending||!s(`printers:control`),className:`p-1.5 rounded disabled:opacity-50 ${K?.chamber_light?`bg-yellow-500/20 hover:bg-yellow-500/30`:`hover:bg-bambu-dark-tertiary`}`,title:s(`printers:control`)?e(`camera.chamberLight`):e(`printers.permission.noControl`),children:(0,l.jsx)(oe,{on:K?.chamber_light??!1,className:`w-4 h-4`})}),(0,l.jsx)(`button`,{onClick:()=>Fe(!0),disabled:!q||!s(`printers:control`),className:`p-1.5 rounded disabled:opacity-50 ${q&&s(`printers:control`)?`hover:bg-bambu-dark-tertiary`:``}`,title:s(`printers:control`)?e(q?`printers.skipObjects.tooltip`:`printers.skipObjects.onlyWhilePrinting`):e(`printers.permission.noControl`),children:(0,l.jsx)(se,{className:`w-4 h-4 text-bambu-gray`})}),(0,l.jsx)(`button`,{onClick:X,disabled:$,className:`p-1.5 hover:bg-bambu-dark-tertiary rounded disabled:opacity-50`,title:e(m===`stream`?`camera.restartStream`:`camera.refreshSnapshot`),children:(0,l.jsx)(he,{className:`w-4 h-4 text-bambu-gray ${$?`animate-spin`:``}`})}),(0,l.jsx)(`button`,{onClick:()=>h(!0),className:`p-1.5 hover:bg-bambu-dark-tertiary rounded`,title:e(`camera.diagnose.button`),children:(0,l.jsx)(me,{className:`w-4 h-4 text-bambu-gray`})}),(0,l.jsx)(`button`,{onClick:Je,className:`p-1.5 hover:bg-bambu-dark-tertiary rounded`,title:e(Le?`camera.exitFullscreen`:`camera.fullscreen`),children:Le?(0,l.jsx)(ae,{className:`w-4 h-4 text-bambu-gray`}):(0,l.jsx)(Se,{className:`w-4 h-4 text-bambu-gray`})})]})]}),(0,l.jsx)(`div`,{className:`flex-1 flex items-center justify-center p-2 overflow-hidden`,onWheel:Ze,onMouseMove:$e,onMouseUp:et,onMouseLeave:et,onTouchStart:rt,onTouchMove:it,onTouchEnd:at,style:{touchAction:`none`},children:(0,l.jsxs)(`div`,{className:`relative w-full h-full flex items-center justify-center`,children:[(v||S)&&!E&&(0,l.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center bg-black/50 z-10`,children:(0,l.jsxs)(`div`,{className:`text-center`,children:[(0,l.jsx)(he,{className:`w-8 h-8 text-bambu-gray animate-spin mx-auto mb-2`}),(0,l.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:e(m===`stream`?`camera.connectingToCamera`:`camera.capturingSnapshot`)})]})}),E&&(0,l.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center bg-black/80 z-10`,children:(0,l.jsxs)(`div`,{className:`text-center p-4`,children:[(0,l.jsx)(pe,{className:`w-10 h-10 text-orange-400 mx-auto mb-3`}),(0,l.jsx)(`p`,{className:`text-white mb-2`,children:e(`camera.connectionLost`)}),(0,l.jsx)(`p`,{className:`text-sm text-bambu-gray mb-3`,children:e(`camera.reconnecting`,{countdown:ze,attempt:Math.min(w+1,u),max:u})}),(0,l.jsx)(`button`,{onClick:X,className:`px-4 py-2 bg-bambu-green text-white text-sm rounded hover:bg-bambu-green/80 transition-colors`,children:e(`camera.reconnectNow`)})]})}),g&&!E&&(0,l.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center bg-black z-10`,children:(0,l.jsxs)(`div`,{className:`text-center p-4`,children:[(0,l.jsx)(ue,{className:`w-12 h-12 text-orange-400 mx-auto mb-3`}),(0,l.jsx)(`p`,{className:`text-white mb-2`,children:e(`camera.cameraUnavailable`)}),(0,l.jsx)(`p`,{className:`text-xs text-bambu-gray mb-4 max-w-md`,children:e(`camera.cameraUnavailableDesc`)}),(0,l.jsxs)(`div`,{className:`flex gap-2 justify-center`,children:[(0,l.jsx)(`button`,{onClick:X,className:`px-4 py-2 bg-bambu-green text-white rounded hover:bg-bambu-green/80 transition-colors`,children:e(`camera.retry`)}),(0,l.jsx)(`button`,{onClick:()=>h(!0),className:`px-4 py-2 bg-bambu-dark border border-bambu-dark-tertiary text-bambu-gray hover:text-white rounded transition-colors`,children:e(`camera.diagnose.button`)})]})]})}),(0,l.jsx)(`img`,{ref:He,src:Q,alt:e(`camera.cameraStream`),className:`max-w-full max-h-full object-contain select-none`,style:{transform:`scale(${O}) translate(${A.x/O}px, ${A.y/O}px) rotate(${G?.camera_rotation||0}deg)`,...G?.camera_rotation===90||G?.camera_rotation===270?{maxWidth:`100vh`,maxHeight:`100vw`}:{},cursor:O>1?M?`grabbing`:`grab`:`default`},onError:Q?We:void 0,onLoad:Q?Ge:void 0,onMouseDown:Qe,draggable:!1},b),(0,l.jsxs)(`div`,{className:`absolute bottom-4 left-4 flex items-center gap-1.5 bg-black/60 rounded-lg px-2 py-1.5`,children:[(0,l.jsx)(`button`,{onClick:Xe,disabled:O<=1,className:`p-1.5 hover:bg-white/10 rounded disabled:opacity-30`,title:e(`camera.zoomOut`),children:(0,l.jsx)(fe,{className:`w-4 h-4 text-white`})}),(0,l.jsxs)(`button`,{onClick:ot,className:`px-2 py-1 text-sm text-white hover:bg-white/10 rounded min-w-[48px]`,title:e(`camera.resetZoom`),children:[Math.round(O*100),`%`]}),(0,l.jsx)(`button`,{onClick:Ye,disabled:O>=4,className:`p-1.5 hover:bg-white/10 rounded disabled:opacity-30`,title:e(`camera.zoomIn`),children:(0,l.jsx)(de,{className:`w-4 h-4 text-white`})})]})]})}),(0,l.jsx)(ce,{printerId:f,isOpen:Pe,onClose:()=>Fe(!1)}),Ie&&(0,l.jsx)(le,{printerId:f,printerName:G?.name||null,onClose:()=>h(!1)})]}):(0,l.jsx)(`div`,{className:`min-h-screen bg-black flex items-center justify-center`,children:(0,l.jsx)(`p`,{className:`text-white`,children:e(`camera.invalidPrinterId`)})})}export{d as CameraPage};