CameraPage-BaQjdvRN.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-C5b1pVUf.js";import{n as ne}from"./QueryClientProvider-BqikUEEO.js";import{t as o}from"./useQuery-DOr0golm.js";import{t as re}from"./useMutation-BAyvCE1t.js";import{t as s}from"./createLucideIcon-Br1j9igo.js";import{n as ie}from"./ToastContext-CypVB8nG.js";import{a as ae,i as oe,n as se,r as ce,t as le}from"./CameraDiagnoseModal-CXdDEg4k.js";import{t as ue}from"./triangle-alert-BAqbkTqR.js";import{n as de,t as fe}from"./zoom-out-BhJDvXo0.js";import{n as pe}from"./AuthContext-DS-dpwJp.js";import{Fn as me,Gn as he,It as ge,Wn as _e,n as ve,qt as ye,wt as be}from"./index-CG6Y41X9.js";import{n as xe,t as Se}from"./useCameraViewerId-Q5wZ7BAZ.js";var Ce=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,we=2e3,Te=3e4,Ee=5e3;function d(){let{t:e}=te(),t=ne(),{showToast:n}=ie(),{hasPermission:s,authEnabled:d,user:De}=pe(),{printerId:Oe}=_e(),f=parseInt(Oe||`0`,10),[ke]=he(),Ae=parseInt(ke.get(`fps`)||`15`,10),je=Math.min(Math.max(isNaN(Ae)?15:Ae,1),30);ve();let{data:Me,isPending:Ne}=o({queryKey:[`camera-stream-token`,De?.id??null],queryFn:()=>i.getCameraStreamToken(),enabled:d?!!De:!0,staleTime:3e3*1e3}),p=Me?.token??a(),[m,Pe]=(0,c.useState)(`stream`),[Fe,Ie]=(0,c.useState)(!1),[Le,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),[Re,ze]=(0,c.useState)(!1),[w,T]=(0,c.useState)(0),[E,D]=(0,c.useState)(!1),[Be,Ve]=(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,He]=(0,c.useState)({x:0,y:0}),[Ue,F]=(0,c.useState)(null),[I,L]=(0,c.useState)(null),R=(0,c.useRef)(null),z=Se(),We=xe(R),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}),Ge=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?viewer=${z}`;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,z]),(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=()=>{ze(!!document.fullscreenElement),k(1),j({x:0,y:0}),m===`stream`&&!S&&(R.current&&(R.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(we*2**w,Te);D(!0),Ve(Math.ceil(e/1e3)),H.current=setInterval(()=>{Ve(e=>e<=1?(H.current&&clearInterval(H.current),0):e-1)},1e3),V.current=setTimeout(()=>{T(e=>e+1),D(!1),y(!0),_(!1),R.current&&(R.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{}},Ee),()=>{U.current&&=(clearInterval(U.current),null)}},[m,v,g,E,S,f,Y]);let Ke=e=>{e.currentTarget.getAttribute(`src`)&&(y(!1),m===`stream`&&w<u?Y():_(!0))},qe=()=>{if(y(!1),_(!1),T(0),W.current=0,D(!1),V.current&&clearTimeout(V.current),H.current&&clearInterval(H.current),R.current&&!localStorage.getItem(`cameraWindowState`)){let e=R.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{}}}},Je=()=>{if(f>0){let e={},t=ee();t&&(e.Authorization=`Bearer ${t}`),fetch(`/api/v1/printers/${f}/camera/stop?viewer=${z}`,{method:`POST`,headers:e}).catch(()=>{})}},Ye=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),R.current&&(R.current.src=``),m===`stream`&&Je(),setTimeout(()=>{Pe(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),R.current&&(R.current.src=``),m===`stream`&&Je(),setTimeout(()=>{x(Date.now()),C(!1)},100))},Xe=()=>{B.current&&(document.fullscreenElement?document.exitFullscreen():B.current.requestFullscreen())},Ze=()=>{k(e=>Math.min(e+.5,4))},Qe=()=>{k(e=>{let t=Math.max(e-.5,1);return t===1&&j({x:0,y:0}),t})},$e=e=>{e.preventDefault(),e.deltaY<0?Ze():Qe()},et=e=>{O>1&&(e.preventDefault(),N(!0),He({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]),tt=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))})}},nt=()=>{N(!1)},rt=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)},it=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},at=e=>{e.touches.length===2?(e.preventDefault(),F(rt(e.touches)),L(it(e.touches))):e.touches.length===1&&O>1&&(e.preventDefault(),N(!0),He({x:e.touches[0].clientX-A.x,y:e.touches[0].clientY-A.y}))},ot=e=>{if(e.touches.length===2&&Ue!==null){e.preventDefault();let t=rt(e.touches),n=t/Ue;k(e=>{let t=Math.max(1,Math.min(4,e*n));return t===1&&j({x:0,y:0}),t}),F(t);let r=it(e.touches);if(I){let e=Z();j(t=>({x:Math.max(-e.x,Math.min(e.x,t.x+(r.x-I.x))),y:Math.max(-e.y,Math.min(e.y,t.y+(r.y-I.y)))}))}L(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))})}},st=e=>{e.touches.length<2&&(F(null),L(null)),e.touches.length===0&&N(!1)},ct=()=>{k(1),j({x:0,y:0})},Q=S||!p&&(d||Ne)?``:(e=>p?`${e}&token=${encodeURIComponent(p)}`:r(e))(m===`stream`?`/api/v1/printers/${f}/camera/stream?fps=${je}&t=${b}&viewer=${z}`:`/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)(me,{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:()=>Ye(`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:()=>Ye(`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:()=>Ge.mutate(!K?.chamber_light),disabled:!K?.connected||Ge.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:()=>Ie(!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)(ye,{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)(ge,{className:`w-4 h-4 text-bambu-gray`})}),(0,l.jsx)(`button`,{onClick:Xe,className:`p-1.5 hover:bg-bambu-dark-tertiary rounded`,title:e(Re?`camera.exitFullscreen`:`camera.fullscreen`),children:Re?(0,l.jsx)(ae,{className:`w-4 h-4 text-bambu-gray`}):(0,l.jsx)(Ce,{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:$e,onMouseMove:tt,onMouseUp:nt,onMouseLeave:nt,onTouchStart:at,onTouchMove:ot,onTouchEnd:st,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)(ye,{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)(be,{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:Be,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:We,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?Ke:void 0,onLoad:Q?qe:void 0,onMouseDown:et,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:Qe,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:ct,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:Ze,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:Fe,onClose:()=>Ie(!1)}),Le&&(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};