CameraPage-1HAKZHBD.js 15 KB

1
  1. import{i as e}from"./rolldown-runtime-aKtaBQYM.js";import{C as t,S as n,T as r,a as i,d as ee,k as a,l as te,w as o}from"./client-DSw2TdH4.js";import{d as ne,f as re}from"./chunk-62JRHF6Z-DiDTZQg1.js";import{n as ie}from"./QueryClientProvider-B5vEWYBq.js";import{t as s}from"./useQuery-DfiorXB9.js";import{t as ae}from"./useMutation-DLyYCmQ0.js";import{t as oe}from"./camera-Cx_MQ-FA.js";import{n as se}from"./ToastContext-C3zxW_t3.js";import{n as ce,t as le}from"./CameraDiagnoseModal-CZO_D5up.js";import{t as ue}from"./picture-in-picture-2-Cf3ZubNG.js";import{t as de}from"./refresh-cw-D7pR-PbA.js";import{t as fe}from"./stethoscope-BNkaxpyE.js";import{t as pe}from"./triangle-alert-Bb8T_5WO.js";import{t as me}from"./wifi-off-2Cy9fC-p.js";import{n as he,t as ge}from"./zoom-out-CV8N-4f5.js";import{n as _e}from"./AuthContext-XuzzSfKE.js";import{o as ve,r as ye}from"./camera-DVxLwUaj.js";import{r as be}from"./index-DpuTTQai.js";import{n as xe,r as Se,t as Ce}from"./SkipObjectsModal-CXP7UaJN.js";import{n as we,t as Te}from"./useCameraViewerId-D30-3MSQ.js";import{n as Ee,t as De}from"./useSidewaysBox-BYcZc_j5.js";var Oe=t(`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(a(),1),l=o(),u=5,ke=2e3,Ae=2e3,je=3e4,Me=5e3;function d(){let{t:e}=r(),[t,n]=(0,c.useState)(!1);return t?(0,l.jsx)(`div`,{className:`min-h-screen bg-black flex items-center justify-center p-4`,children:(0,l.jsx)(`p`,{className:`text-white text-center`,children:e(`camera.poppedIn`)})}):(0,l.jsx)(f,{onPoppedIn:()=>n(!0)})}function f({onPoppedIn:e}){let{t}=r(),a=ie(),{showToast:o}=se(),{hasPermission:d,authEnabled:f,user:Ne}=_e(),{printerId:Pe}=ne(),p=parseInt(Pe||`0`,10),[Fe]=re(),Ie=parseInt(Fe.get(`fps`)||`15`,10),Le=Math.min(Math.max(isNaN(Ie)?15:Ie,1),30);be();let{data:Re,isPending:ze}=s({queryKey:[`camera-stream-token`,Ne?.id??null],queryFn:()=>i.getCameraStreamToken(),enabled:!f||!!Ne,staleTime:3e3*1e3}),m=Re?.token??ee(),[h,Be]=(0,c.useState)(`stream`),[Ve,He]=(0,c.useState)(!1),[Ue,g]=(0,c.useState)(!1),[_,v]=(0,c.useState)(!1),[y,b]=(0,c.useState)(!0),[x,S]=(0,c.useState)(Date.now()),[C,w]=(0,c.useState)(!1),[We,Ge]=(0,c.useState)(!1),[T,E]=(0,c.useState)(0),[D,O]=(0,c.useState)(!1),[Ke,qe]=(0,c.useState)(0),[k,A]=(0,c.useState)(1),[j,M]=(0,c.useState)({x:0,y:0}),[N,P]=(0,c.useState)(!1),[F,Je]=(0,c.useState)({x:0,y:0}),[Ye,I]=(0,c.useState)(null),[L,R]=(0,c.useState)(null),z=(0,c.useRef)(null),B=Te(),Xe=we(z),V=(0,c.useRef)(null),H=(0,c.useRef)(null),U=(0,c.useRef)(null),W=(0,c.useRef)(null),G=(0,c.useRef)(0),K=(0,c.useRef)(!1),q=(0,c.useRef)(null),{data:J}=s({queryKey:[`printer`,p],queryFn:()=>i.getPrinter(p),enabled:p>0}),{data:Y}=s({queryKey:[`printerStatus`,p],queryFn:()=>i.getPrinterStatus(p),refetchInterval:3e4,enabled:p>0}),Ze=ae({mutationFn:e=>i.setChamberLight(p,e),onMutate:async e=>{await a.cancelQueries({queryKey:[`printerStatus`,p]});let t=a.getQueryData([`printerStatus`,p]);return a.setQueryData([`printerStatus`,p],t=>({...t,chamber_light:e})),{previousStatus:t}},onSuccess:(e,t)=>{o(`Chamber light ${t?`on`:`off`}`)},onError:(e,n,r)=>{r?.previousStatus&&a.setQueryData([`printerStatus`,p],r.previousStatus),o(e.message||t(`printers.toast.failedToControlChamberLight`),`error`)}}),X=(Y?.state===`RUNNING`||Y?.state===`PAUSE`)&&(Y?.printable_objects_count??0)>=2;(0,c.useEffect)(()=>(J&&(document.title=`${J.name} - Camera`),()=>{document.title=`Bambuddy`}),[J]);let Z=(0,c.useRef)(!1);(0,c.useEffect)(()=>{let e=`/api/v1/printers/${p}/camera/stop?viewer=${B}`;Z.current=!1;let t=()=>{if(p>0&&!Z.current){Z.current=!0;let t={},n=te();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()}},[p,B]),(0,c.useEffect)(()=>{if(y&&!C){let e=setTimeout(()=>{b(!1)},h===`stream`?3e3:2e4);return()=>clearTimeout(e)}},[h,y,x,C]),(0,c.useEffect)(()=>{let e=()=>{let e=!!document.fullscreenElement;Ge(e),A(1),M({x:0,y:0}),h===`stream`&&!C&&(z.current&&(z.current.src=``),setTimeout(()=>{b(!0),S(Date.now())},200))};return document.addEventListener(`fullscreenchange`,e),()=>document.removeEventListener(`fullscreenchange`,e)},[h,C]),(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)(()=>()=>{H.current&&clearTimeout(H.current),U.current&&clearInterval(U.current),W.current&&clearInterval(W.current),q.current&&clearTimeout(q.current)},[]);let Qe=(0,c.useCallback)(()=>{if(T>=u){O(!1),v(!0);return}let e=Math.min(Ae*2**T,je);O(!0),qe(Math.ceil(e/1e3)),U.current=setInterval(()=>{qe(e=>e<=1?(U.current&&clearInterval(U.current),0):e-1)},1e3),H.current=setTimeout(()=>{E(e=>e+1),O(!1),b(!0),v(!1),z.current&&(z.current.src=``),S(Date.now())},e)},[T]);(0,c.useEffect)(()=>{if(h!==`stream`||y||D||C){W.current&&=(clearInterval(W.current),null);return}return G.current=0,W.current=setInterval(async()=>{try{let e=await i.getCameraStatus(p);if(!(e.stalled||!e.active&&!_)){G.current=0;return}if(G.current+=1,G.current<2)return;G.current=0,console.log(`Stream issue detected: stalled=${e.stalled}, active=${e.active}, reconnecting...`),W.current&&=(clearInterval(W.current),null),b(!1),Qe()}catch{}},Me),()=>{W.current&&=(clearInterval(W.current),null)}},[h,y,_,D,C,p,Qe]);let $e=e=>{e.currentTarget.getAttribute(`src`)&&(b(!1),h===`stream`&&T<u?Qe():h===`snapshot`&&!K.current?(K.current=!0,q.current&&clearTimeout(q.current),q.current=setTimeout(()=>{q.current=null,S(Date.now())},ke)):v(!0))},et=()=>{if(K.current=!1,b(!1),v(!1),E(0),G.current=0,O(!1),H.current&&clearTimeout(H.current),U.current&&clearInterval(U.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,ee=n+45+16+r;try{window.resizeTo(i,ee)}catch{}}}},tt=()=>{if(p>0){let e={},t=te();t&&(e.Authorization=`Bearer ${t}`),fetch(`/api/v1/printers/${p}/camera/stop?viewer=${B}`,{method:`POST`,headers:e}).catch(()=>{})}},nt=e=>{h===e||C||(w(!0),b(!0),v(!1),E(0),K.current=!1,O(!1),A(1),M({x:0,y:0}),H.current&&clearTimeout(H.current),U.current&&clearInterval(U.current),z.current&&(z.current.src=``),h===`stream`&&tt(),setTimeout(()=>{Be(e),S(Date.now()),w(!1)},100))},rt=()=>{C||(K.current=!1,w(!0),b(!0),v(!1),E(0),O(!1),H.current&&clearTimeout(H.current),U.current&&clearInterval(U.current),z.current&&(z.current.src=``),h===`stream`&&tt(),setTimeout(()=>{S(Date.now()),w(!1)},100))},it=()=>{V.current&&(document.fullscreenElement?document.exitFullscreen():V.current.requestFullscreen())},at=()=>{A(e=>Math.min(e+.5,4))},ot=()=>{A(e=>{let t=Math.max(e-.5,1);return t===1&&M({x:0,y:0}),t})},st=e=>{e.preventDefault(),e.deltaY<0?at():ot()},ct=e=>{k>1&&(e.preventDefault(),P(!0),Je({x:e.clientX-j.x,y:e.clientY-j.y}))},lt=(0,c.useCallback)(()=>{if(!V.current)return{x:300,y:200};let e=V.current.getBoundingClientRect(),t=e.width*(k-1)/2,n=e.height*(k-1)/2;return{x:Math.max(50,t),y:Math.max(50,n)}},[k]),ut=e=>{if(N&&k>1){let t=e.clientX-F.x,n=e.clientY-F.y,r=lt();M({x:Math.max(-r.x,Math.min(r.x,t)),y:Math.max(-r.y,Math.min(r.y,n))})}},dt=()=>{P(!1)},ft=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)},pt=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},mt=e=>{e.touches.length===2?(e.preventDefault(),I(ft(e.touches)),R(pt(e.touches))):e.touches.length===1&&k>1&&(e.preventDefault(),P(!0),Je({x:e.touches[0].clientX-j.x,y:e.touches[0].clientY-j.y}))},ht=e=>{if(e.touches.length===2&&Ye!==null){e.preventDefault();let t=ft(e.touches),n=t/Ye;A(e=>{let t=Math.max(1,Math.min(4,e*n));return t===1&&M({x:0,y:0}),t}),I(t);let r=pt(e.touches);if(L){let e=lt();M(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&&N&&k>1){e.preventDefault();let t=e.touches[0].clientX-F.x,n=e.touches[0].clientY-F.y,r=lt();M({x:Math.max(-r.x,Math.min(r.x,t)),y:Math.max(-r.y,Math.min(r.y,n))})}},gt=e=>{e.touches.length<2&&(I(null),R(null)),e.touches.length===0&&P(!1)},_t=()=>{A(1),M({x:0,y:0})},vt=C||!m&&(f||ze)?``:(e=>m?`${e}&token=${encodeURIComponent(m)}`:n(e))(h===`stream`?`/api/v1/printers/${p}/camera/stream?fps=${Le}&t=${x}&viewer=${B}`:`/api/v1/printers/${p}/camera/snapshot?t=${x}`),Q=y||C||D,yt=(0,c.useRef)(null),bt=De(J?.camera_rotation),$=Ee(yt,bt&&p>0),[xt]=(0,c.useState)(ye),[St,Ct]=(0,c.useState)(!1);return p?(0,l.jsxs)(`div`,{ref:V,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)(oe,{className:`w-4 h-4`}),J?.name||`Printer ${p}`]}),(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:()=>nt(`stream`),disabled:Q,className:`px-3 py-1 text-xs rounded transition-colors ${h===`stream`?`bg-bambu-green text-white`:`text-bambu-gray hover:text-white disabled:opacity-50`}`,children:t(`camera.live`)}),(0,l.jsx)(`button`,{onClick:()=>nt(`snapshot`),disabled:Q,className:`px-3 py-1 text-xs rounded transition-colors ${h===`snapshot`?`bg-bambu-green text-white`:`text-bambu-gray hover:text-white disabled:opacity-50`}`,children:t(`camera.snapshot`)})]}),(0,l.jsx)(`button`,{onClick:()=>Ze.mutate(!Y?.chamber_light),disabled:!Y?.connected||Ze.isPending||!d(`printers:control`),className:`p-1.5 rounded disabled:opacity-50 ${Y?.chamber_light?`bg-yellow-500/20 hover:bg-yellow-500/30`:`hover:bg-bambu-dark-tertiary`}`,title:d(`printers:control`)?t(`camera.chamberLight`):t(`printers.permission.noControl`),children:(0,l.jsx)(Se,{on:Y?.chamber_light??!1,className:`w-4 h-4`})}),(0,l.jsx)(`button`,{onClick:()=>He(!0),disabled:!X||!d(`printers:control`),className:`p-1.5 rounded disabled:opacity-50 ${X&&d(`printers:control`)?`hover:bg-bambu-dark-tertiary`:``}`,title:d(`printers:control`)?t(X?`printers.skipObjects.tooltip`:`printers.skipObjects.onlyWhilePrinting`):t(`printers.permission.noControl`),children:(0,l.jsx)(Ce,{className:`w-4 h-4 text-bambu-gray`})}),(0,l.jsx)(`button`,{onClick:rt,disabled:Q,className:`p-1.5 hover:bg-bambu-dark-tertiary rounded disabled:opacity-50`,title:t(h===`stream`?`camera.restartStream`:`camera.refreshSnapshot`),children:(0,l.jsx)(de,{className:`w-4 h-4 text-bambu-gray ${Q?`animate-spin`:``}`})}),(0,l.jsx)(`button`,{onClick:()=>g(!0),className:`p-1.5 hover:bg-bambu-dark-tertiary rounded`,title:t(`camera.diagnose.button`),children:(0,l.jsx)(fe,{className:`w-4 h-4 text-bambu-gray`})}),(0,l.jsx)(`button`,{onClick:async()=>{Ct(!0);let n=await ve(p,J?.name??``,xt);if(Ct(!1),!n){o(t(`camera.popInNoTab`),`warning`);return}e(),window.close()},disabled:St,className:`p-1.5 hover:bg-bambu-dark-tertiary rounded disabled:opacity-50`,title:t(`camera.popIn`),"aria-label":t(`camera.popIn`),children:(0,l.jsx)(ue,{className:`w-4 h-4 text-bambu-gray`})}),(0,l.jsx)(`button`,{onClick:it,className:`p-1.5 hover:bg-bambu-dark-tertiary rounded`,title:t(We?`camera.exitFullscreen`:`camera.fullscreen`),children:We?(0,l.jsx)(ce,{className:`w-4 h-4 text-bambu-gray`}):(0,l.jsx)(Oe,{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:st,onMouseMove:ut,onMouseUp:dt,onMouseLeave:dt,onTouchStart:mt,onTouchMove:ht,onTouchEnd:gt,style:{touchAction:`none`},children:(0,l.jsxs)(`div`,{ref:yt,className:`relative w-full h-full flex items-center justify-center`,children:[(y||C)&&!D&&(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)(de,{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:t(h===`stream`?`camera.connectingToCamera`:`camera.capturingSnapshot`)})]})}),D&&(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)(me,{className:`w-10 h-10 text-orange-400 mx-auto mb-3`}),(0,l.jsx)(`p`,{className:`text-white mb-2`,children:t(`camera.connectionLost`)}),(0,l.jsx)(`p`,{className:`text-sm text-bambu-gray mb-3`,children:t(`camera.reconnecting`,{countdown:Ke,attempt:Math.min(T+1,u),max:u})}),(0,l.jsx)(`button`,{onClick:rt,className:`px-4 py-2 bg-bambu-green text-white text-sm rounded hover:bg-bambu-green/80 transition-colors`,children:t(`camera.reconnectNow`)})]})}),_&&!D&&(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)(pe,{className:`w-12 h-12 text-orange-400 mx-auto mb-3`}),(0,l.jsx)(`p`,{className:`text-white mb-2`,children:t(`camera.cameraUnavailable`)}),(0,l.jsx)(`p`,{className:`text-xs text-bambu-gray mb-4 max-w-md`,children:t(`camera.cameraUnavailableDesc`)}),(0,l.jsxs)(`div`,{className:`flex gap-2 justify-center`,children:[(0,l.jsx)(`button`,{onClick:rt,className:`px-4 py-2 bg-bambu-green text-white rounded hover:bg-bambu-green/80 transition-colors`,children:t(`camera.retry`)}),(0,l.jsx)(`button`,{onClick:()=>g(!0),className:`px-4 py-2 bg-bambu-dark border border-bambu-dark-tertiary text-bambu-gray hover:text-white rounded transition-colors`,children:t(`camera.diagnose.button`)})]})]})}),(0,l.jsx)(`img`,{ref:Xe,src:vt,alt:t(`camera.cameraStream`),className:`max-w-full max-h-full object-contain select-none`,style:{transform:`scale(${k}) translate(${j.x/k}px, ${j.y/k}px) rotate(${J?.camera_rotation||0}deg)`,...bt?$?{maxWidth:$.height,maxHeight:$.width}:{maxWidth:`100vh`,maxHeight:`100vw`}:{},cursor:k>1?N?`grabbing`:`grab`:`default`},onError:vt?$e:void 0,onLoad:vt?et:void 0,onMouseDown:ct,draggable:!1},x),(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:ot,disabled:k<=1,className:`p-1.5 hover:bg-white/10 rounded disabled:opacity-30`,title:t(`camera.zoomOut`),children:(0,l.jsx)(ge,{className:`w-4 h-4 text-white`})}),(0,l.jsxs)(`button`,{onClick:_t,className:`px-2 py-1 text-sm text-white hover:bg-white/10 rounded min-w-[48px]`,title:t(`camera.resetZoom`),children:[Math.round(k*100),`%`]}),(0,l.jsx)(`button`,{onClick:at,disabled:k>=4,className:`p-1.5 hover:bg-white/10 rounded disabled:opacity-30`,title:t(`camera.zoomIn`),children:(0,l.jsx)(he,{className:`w-4 h-4 text-white`})})]})]})}),(0,l.jsx)(xe,{printerId:p,isOpen:Ve,onClose:()=>He(!1)}),Ue&&(0,l.jsx)(le,{printerId:p,printerName:J?.name||null,onClose:()=>g(!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:t(`camera.invalidPrinterId`)})})}export{d as CameraPage};