EmbeddedCameraViewer-aZnEbFDI.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,k as ee,l as te,w as a}from"./client-DSw2TdH4.js";import{n as ne}from"./QueryClientProvider-B5vEWYBq.js";import{t as re}from"./useQuery-DfiorXB9.js";import{t as ie}from"./useMutation-DLyYCmQ0.js";import{n as ae}from"./ToastContext-C3zxW_t3.js";import{t as oe}from"./external-link-BuJwWh2y.js";import{t as se}from"./grip-vertical-ClbE5NJh.js";import{t as ce}from"./maximize-2-CXARZr1r.js";import{t as le}from"./minimize-2-CObB7r6l.js";import{n as ue,t as de}from"./CameraDiagnoseModal-CZO_D5up.js";import{t as fe}from"./refresh-cw-D7pR-PbA.js";import{t as pe}from"./stethoscope-BNkaxpyE.js";import{t as me}from"./triangle-alert-Bb8T_5WO.js";import{t as he}from"./wifi-off-2Cy9fC-p.js";import{t as ge}from"./x-DIT5l0_1.js";import{n as _e,t as ve}from"./zoom-out-CV8N-4f5.js";import{n as ye}from"./AuthContext-XuzzSfKE.js";import{n as be}from"./camera-DVxLwUaj.js";import{t as xe}from"./useIsSidebarCompact-DWqh4K9S.js";import{n as Se,r as Ce,t as we}from"./SkipObjectsModal-CXP7UaJN.js";import{n as Te,t as Ee}from"./useCameraViewerId-D30-3MSQ.js";import{n as De,t as Oe}from"./useSidewaysBox-BYcZc_j5.js";var ke=t(`fullscreen`,[[`path`,{d:`M3 7V5a2 2 0 0 1 2-2h2`,key:`aa7l1z`}],[`path`,{d:`M17 3h2a2 2 0 0 1 2 2v2`,key:`4qcy5o`}],[`path`,{d:`M21 17v2a2 2 0 0 1-2 2h-2`,key:`6vwrx8`}],[`path`,{d:`M7 21H5a2 2 0 0 1-2-2v-2`,key:`ioqczr`}],[`rect`,{width:`10`,height:`8`,x:`7`,y:`8`,rx:`1`,key:`vys8me`}]]),o=e(ee(),1),s=a(),Ae=`embeddedCameraState_`,je=5,Me=2e3,Ne=3e4,Pe=5e3,Fe=56;function Ie(){let e=Math.min(400,Math.max(200,window.innerWidth-16));return{x:Math.max(0,window.innerWidth-e-20),y:64,width:e,height:300}}function c({printerId:e,printerName:t,viewerIndex:ee=0,onClose:a}){let{t:c}=r(),l=ne(),{showToast:Le}=ae(),{hasPermission:u}=ye(),d=`${Ae}${e}`,f=xe()?Fe:0,[p,m]=(0,o.useState)(()=>{try{let e=localStorage.getItem(d);if(e){let t=JSON.parse(e);return{x:Math.min(Math.max(0,t.x),window.innerWidth-100),y:Math.min(Math.max(0,t.y),window.innerHeight-100),width:Math.max(200,Math.min(t.width,window.innerWidth-20)),height:Math.max(150,Math.min(t.height,window.innerHeight-20))}}}catch{}let e=ee*30,t=Ie();return{...t,x:Math.max(0,t.x-e),y:Math.max(0,t.y+e)}});(0,o.useLayoutEffect)(()=>{m(e=>e.y<f?{...e,y:f}:e)},[f]);let[h,g]=(0,o.useState)(!1),[_,v]=(0,o.useState)(!1),[y,Re]=(0,o.useState)({x:0,y:0}),[b,ze]=(0,o.useState)(!1),[x,Be]=(0,o.useState)(!1),[S,C]=(0,o.useState)(1),[w,T]=(0,o.useState)({x:0,y:0}),[E,D]=(0,o.useState)(!1),[O,Ve]=(0,o.useState)({x:0,y:0}),[He,k]=(0,o.useState)(null),[A,Ue]=(0,o.useState)(null),[j,M]=(0,o.useState)(!1),[N,P]=(0,o.useState)(!0),[F,We]=(0,o.useState)(Date.now()),[I,L]=(0,o.useState)(0),[R,z]=(0,o.useState)(!1),[Ge,Ke]=(0,o.useState)(0),B=(0,o.useRef)(null),V=(0,o.useRef)(null),H=Ee(),qe=Te(V),U=(0,o.useRef)(null),W=(0,o.useRef)(null),G=(0,o.useRef)(null),[Je,Ye]=(0,o.useState)(!1),[Xe,K]=(0,o.useState)(!1),{data:q}=re({queryKey:[`printer`,e],queryFn:()=>i.getPrinter(e),enabled:e>0}),Ze=(0,o.useRef)(null),Qe=Oe(q?.camera_rotation),J=De(Ze,Qe&&!b),{data:Y}=re({queryKey:[`printerStatus`,e],queryFn:()=>i.getPrinterStatus(e),refetchInterval:3e4,enabled:e>0}),$e=ie({mutationFn:t=>i.setChamberLight(e,t),onMutate:async t=>{await l.cancelQueries({queryKey:[`printerStatus`,e]});let n=l.getQueryData([`printerStatus`,e]);return l.setQueryData([`printerStatus`,e],e=>({...e,chamber_light:t})),{previousStatus:n}},onSuccess:(e,t)=>{Le(`Chamber light ${t?`on`:`off`}`)},onError:(t,n,r)=>{r?.previousStatus&&l.setQueryData([`printerStatus`,e],r.previousStatus),Le(t.message||c(`printers.toast.failedToControlChamberLight`),`error`)}}),X=(Y?.state===`RUNNING`||Y?.state===`PAUSE`)&&(Y?.printable_objects_count??0)>=2;(0,o.useEffect)(()=>{let e=setTimeout(()=>{localStorage.setItem(d,JSON.stringify(p))},500);return()=>clearTimeout(e)},[p,d]);let Z=(0,o.useRef)(!1);(0,o.useEffect)(()=>{Z.current=!1;let t=`/api/v1/printers/${e}/camera/stop?viewer=${H}`,n=()=>{if(e>0&&!Z.current){Z.current=!0;let e={},n=te();n&&(e.Authorization=`Bearer ${n}`),fetch(t,{method:`POST`,keepalive:!0,headers:e}).catch(()=>{})}};return()=>{n(),U.current&&clearTimeout(U.current),W.current&&clearInterval(W.current),G.current&&clearInterval(G.current)}},[e,H]),(0,o.useEffect)(()=>{if(N){let e=setTimeout(()=>P(!1),3e3);return()=>clearTimeout(e)}},[N,F]);let Q=(0,o.useCallback)(()=>{if(I>=je){z(!1),M(!0);return}let e=Math.min(Me*2**I,Ne);z(!0),Ke(Math.ceil(e/1e3)),W.current=setInterval(()=>{Ke(e=>e<=1?(W.current&&clearInterval(W.current),0):e-1)},1e3),U.current=setTimeout(()=>{L(e=>e+1),z(!1),P(!0),M(!1),V.current&&(V.current.src=``),We(Date.now())},e)},[I]);(0,o.useEffect)(()=>{if(N||R||b){G.current&&=(clearInterval(G.current),null);return}return G.current=setInterval(async()=>{try{let t=await i.getCameraStatus(e);(t.stalled||!t.active&&!j)&&(G.current&&=(clearInterval(G.current),null),P(!1),Q())}catch{}},Pe),()=>{G.current&&=(clearInterval(G.current),null)}},[N,j,R,b,e,Q]),(0,o.useEffect)(()=>{let e=()=>{let e=!!document.fullscreenElement;Be(e),e||(C(1),T({x:0,y:0}))};return document.addEventListener(`fullscreenchange`,e),()=>document.removeEventListener(`fullscreenchange`,e)},[]);let et=()=>{B.current&&(document.fullscreenElement?document.exitFullscreen():B.current.requestFullscreen())},tt=()=>{C(e=>Math.min(e+.5,4))},nt=()=>{C(e=>{let t=Math.max(e-.5,1);return t===1&&T({x:0,y:0}),t})},rt=e=>{e.preventDefault(),e.deltaY<0?tt():nt()},it=e=>{S>1&&(e.preventDefault(),D(!0),Ve({x:e.clientX-w.x,y:e.clientY-w.y}))},$=(0,o.useCallback)(()=>{if(!B.current||!V.current)return{x:200,y:150};let e=B.current.getBoundingClientRect(),t=e.width*(S-1)/2,n=e.height*(S-1)/2;return{x:Math.max(50,t),y:Math.max(50,n)}},[S]),at=e=>{if(E&&S>1){let t=e.clientX-O.x,n=e.clientY-O.y,r=$();T({x:Math.max(-r.x,Math.min(r.x,t)),y:Math.max(-r.y,Math.min(r.y,n))})}},ot=()=>{D(!1)},st=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)},ct=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},lt=e=>{e.touches.length===2?(e.preventDefault(),k(st(e.touches)),Ue(ct(e.touches))):e.touches.length===1&&S>1&&(e.preventDefault(),D(!0),Ve({x:e.touches[0].clientX-w.x,y:e.touches[0].clientY-w.y}))},ut=e=>{if(e.touches.length===2&&He!==null){e.preventDefault();let t=st(e.touches),n=t/He;C(e=>{let t=Math.max(1,Math.min(4,e*n));return t===1&&T({x:0,y:0}),t}),k(t);let r=ct(e.touches);if(A){let e=$();T(t=>({x:Math.max(-e.x,Math.min(e.x,t.x+(r.x-A.x))),y:Math.max(-e.y,Math.min(e.y,t.y+(r.y-A.y)))}))}Ue(r)}else if(e.touches.length===1&&E&&S>1){e.preventDefault();let t=e.touches[0].clientX-O.x,n=e.touches[0].clientY-O.y,r=$();T({x:Math.max(-r.x,Math.min(r.x,t)),y:Math.max(-r.y,Math.min(r.y,n))})}},dt=e=>{e.touches.length<2&&(k(null),Ue(null)),e.touches.length===0&&D(!1)},ft=()=>{C(1),T({x:0,y:0})},pt=e=>{e.currentTarget.getAttribute(`src`)&&(P(!1),I<je?Q():M(!0))},mt=()=>{P(!1),M(!1),L(0),z(!1),U.current&&clearTimeout(U.current),W.current&&clearInterval(W.current)},ht=()=>{P(!0),M(!1),L(0),z(!1),U.current&&clearTimeout(U.current),W.current&&clearInterval(W.current);let t={},n=te();n&&(t.Authorization=`Bearer ${n}`),fetch(`/api/v1/printers/${e}/camera/stop?viewer=${H}`,{method:`POST`,headers:t}).catch(()=>{}),V.current&&(V.current.src=``),setTimeout(()=>We(Date.now()),100)},gt=e=>{e.target.closest(`.no-drag`)||(g(!0),Re({x:e.clientX-p.x,y:e.clientY-p.y}))},_t=e=>{if(e.target.closest(`.no-drag`))return;let t=e.touches[0];g(!0),Re({x:t.clientX-p.x,y:t.clientY-p.y})},vt=e=>{e.stopPropagation(),v(!0)},yt=e=>{e.stopPropagation(),v(!0)};(0,o.useEffect)(()=>{let e=e=>{if(h)m(t=>({...t,x:Math.max(0,Math.min(e.clientX-y.x,window.innerWidth-t.width)),y:Math.max(f,Math.min(e.clientY-y.y,window.innerHeight-t.height))}));else if(_&&B.current){let t=B.current.getBoundingClientRect();m(n=>({...n,width:Math.max(200,Math.min(e.clientX-t.left,window.innerWidth-n.x-10)),height:Math.max(150,Math.min(e.clientY-t.top,window.innerHeight-n.y-10))}))}},t=e=>{if(!h&&!_)return;e.preventDefault();let t=e.touches[0];if(h)m(e=>({...e,x:Math.max(0,Math.min(t.clientX-y.x,window.innerWidth-e.width)),y:Math.max(f,Math.min(t.clientY-y.y,window.innerHeight-e.height))}));else if(_&&B.current){let e=B.current.getBoundingClientRect();m(n=>({...n,width:Math.max(200,Math.min(t.clientX-e.left,window.innerWidth-n.x-10)),height:Math.max(150,Math.min(t.clientY-e.top,window.innerHeight-n.y-10))}))}},n=()=>{g(!1),v(!1)};if(h||_)return document.addEventListener(`mousemove`,e),document.addEventListener(`mouseup`,n),document.addEventListener(`touchmove`,t,{passive:!1}),document.addEventListener(`touchend`,n),document.addEventListener(`touchcancel`,n),()=>{document.removeEventListener(`mousemove`,e),document.removeEventListener(`mouseup`,n),document.removeEventListener(`touchmove`,t),document.removeEventListener(`touchend`,n),document.removeEventListener(`touchcancel`,n)}},[h,_,y,f]);let bt=n(`/api/v1/printers/${e}/camera/stream?fps=15&t=${F}&viewer=${H}`);return(0,s.jsxs)(`div`,{ref:B,className:`${x?`fixed inset-0 z-[100]`:`fixed z-40 rounded-lg shadow-2xl border border-bambu-dark-tertiary`} bg-bambu-dark-secondary overflow-hidden`,style:x?void 0:{left:p.x,top:p.y,width:b?200:p.width,height:b?40:p.height,cursor:h?`grabbing`:`default`},children:[(0,s.jsxs)(`div`,{className:`flex items-center justify-between px-3 py-2 bg-bambu-dark border-b border-bambu-dark-tertiary cursor-grab active:cursor-grabbing`,onMouseDown:gt,onTouchStart:_t,children:[(0,s.jsxs)(`div`,{className:`flex items-center gap-2 text-sm text-white truncate`,children:[(0,s.jsx)(se,{className:`w-4 h-4 text-bambu-gray flex-shrink-0`}),(0,s.jsx)(`span`,{className:`truncate`,children:q?.name||t})]}),(0,s.jsxs)(`div`,{className:`flex items-center gap-1 no-drag`,children:[(0,s.jsx)(`button`,{onClick:()=>$e.mutate(!Y?.chamber_light),disabled:!Y?.connected||$e.isPending||!u(`printers:control`),className:`p-1 rounded disabled:opacity-50 ${Y?.chamber_light?`bg-yellow-500/20 hover:bg-yellow-500/30`:`hover:bg-bambu-dark-tertiary`}`,title:u(`printers:control`)?c(`camera.chamberLight`):c(`printers.permission.noControl`),children:(0,s.jsx)(Ce,{on:Y?.chamber_light??!1,className:`w-3.5 h-3.5`})}),(0,s.jsx)(`button`,{onClick:()=>Ye(!0),disabled:!X||!u(`printers:control`),className:`p-1 rounded disabled:opacity-50 ${X&&u(`printers:control`)?`hover:bg-bambu-dark-tertiary`:``}`,title:u(`printers:control`)?c(X?`printers.skipObjects.tooltip`:`printers.skipObjects.onlyWhilePrinting`):c(`printers.permission.noControl`),children:(0,s.jsx)(we,{className:`w-3.5 h-3.5 text-bambu-gray`})}),(0,s.jsx)(`button`,{onClick:ht,disabled:N||R,className:`p-1 hover:bg-bambu-dark-tertiary rounded disabled:opacity-50`,title:`Refresh stream`,children:(0,s.jsx)(fe,{className:`w-3.5 h-3.5 text-bambu-gray ${N?`animate-spin`:``}`})}),(0,s.jsx)(`button`,{onClick:()=>K(!0),className:`p-1 hover:bg-bambu-dark-tertiary rounded`,title:c(`camera.diagnose.button`),children:(0,s.jsx)(pe,{className:`w-3.5 h-3.5 text-bambu-gray`})}),(0,s.jsx)(`button`,{onClick:et,className:`p-1 hover:bg-bambu-dark-tertiary rounded`,title:x?`Exit fullscreen`:`Fullscreen`,children:x?(0,s.jsx)(ue,{className:`w-3.5 h-3.5 text-bambu-gray`}):(0,s.jsx)(ke,{className:`w-3.5 h-3.5 text-bambu-gray`})}),(0,s.jsx)(`button`,{onClick:()=>{be(e)&&a()},className:`p-1 hover:bg-bambu-dark-tertiary rounded`,title:c(`camera.popOut`),"aria-label":c(`camera.popOut`),children:(0,s.jsx)(oe,{className:`w-3.5 h-3.5 text-bambu-gray`})}),(0,s.jsx)(`button`,{onClick:()=>ze(!b),className:`p-1 hover:bg-bambu-dark-tertiary rounded`,title:b?`Expand`:`Minimize`,children:b?(0,s.jsx)(ce,{className:`w-3.5 h-3.5 text-bambu-gray`}):(0,s.jsx)(le,{className:`w-3.5 h-3.5 text-bambu-gray`})}),(0,s.jsx)(`button`,{onClick:a,className:`p-1 hover:bg-red-500/20 rounded`,title:`Close`,children:(0,s.jsx)(ge,{className:`w-3.5 h-3.5 text-bambu-gray hover:text-red-600 dark:hover:text-red-400`})})]})]}),!b&&(0,s.jsxs)(`div`,{ref:Ze,className:`relative w-full bg-black flex items-center justify-center overflow-hidden h-[calc(100%-40px)]`,onWheel:rt,onMouseMove:at,onMouseUp:ot,onMouseLeave:ot,onTouchStart:lt,onTouchMove:ut,onTouchEnd:dt,style:{touchAction:`none`},children:[N&&!R&&(0,s.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center bg-black/50 z-10`,children:(0,s.jsx)(fe,{className:`w-6 h-6 text-bambu-gray animate-spin`})}),R&&(0,s.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center bg-black/80 z-10`,children:(0,s.jsxs)(`div`,{className:`text-center p-2`,children:[(0,s.jsx)(he,{className:`w-6 h-6 text-orange-400 mx-auto mb-2`}),(0,s.jsxs)(`p`,{className:`text-xs text-bambu-gray`,children:[`Reconnecting in `,Ge,`s...`]})]})}),j&&!R&&(0,s.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center bg-black z-10`,children:(0,s.jsxs)(`div`,{className:`text-center p-2`,children:[(0,s.jsx)(me,{className:`w-6 h-6 text-orange-400 mx-auto mb-2`}),(0,s.jsx)(`p`,{className:`text-xs text-bambu-gray mb-2`,children:c(`camera.unavailable`)}),(0,s.jsxs)(`div`,{className:`flex gap-2 justify-center`,children:[(0,s.jsx)(`button`,{onClick:ht,className:`px-2 py-1 text-xs bg-bambu-green text-white rounded hover:bg-bambu-green/80`,children:c(`camera.retry`)}),(0,s.jsx)(`button`,{onClick:()=>K(!0),className:`px-2 py-1 text-xs bg-bambu-dark border border-bambu-dark-tertiary text-bambu-gray hover:text-white rounded transition-colors`,children:c(`camera.diagnose.button`)})]})]})}),(0,s.jsx)(`img`,{ref:qe,src:bt,alt:`Camera stream`,className:`max-w-full max-h-full object-contain select-none`,style:{transform:`scale(${S}) translate(${w.x/S}px, ${w.y/S}px) rotate(${q?.camera_rotation||0}deg)`,...Qe?J?{maxWidth:J.height,maxHeight:J.width}:{maxWidth:`100%`,maxHeight:`100%`}:{},cursor:S>1?E?`grabbing`:`grab`:`default`},onError:pt,onLoad:mt,onMouseDown:it,draggable:!1},F),(0,s.jsxs)(`div`,{className:`absolute bottom-2 left-2 flex items-center gap-1 bg-black/60 rounded px-1.5 py-1 no-drag`,children:[(0,s.jsx)(`button`,{onClick:nt,disabled:S<=1,className:`p-1 hover:bg-white/10 rounded disabled:opacity-30`,title:`Zoom out`,children:(0,s.jsx)(ve,{className:`w-3.5 h-3.5 text-white`})}),(0,s.jsxs)(`button`,{onClick:ft,className:`px-1.5 py-0.5 text-xs text-white hover:bg-white/10 rounded min-w-[32px]`,title:`Reset zoom`,children:[Math.round(S*100),`%`]}),(0,s.jsx)(`button`,{onClick:tt,disabled:S>=4,className:`p-1 hover:bg-white/10 rounded disabled:opacity-30`,title:`Zoom in`,children:(0,s.jsx)(_e,{className:`w-3.5 h-3.5 text-white`})})]}),!x&&(0,s.jsx)(`div`,{className:`absolute bottom-0 right-0 w-6 h-6 cursor-se-resize no-drag hover:bg-white/10 rounded-tl transition-colors`,onMouseDown:vt,onTouchStart:yt,title:`Drag to resize`,children:(0,s.jsx)(`svg`,{className:`w-6 h-6 text-bambu-gray/70 hover:text-bambu-gray`,viewBox:`0 0 24 24`,fill:`currentColor`,children:(0,s.jsx)(`path`,{d:`M22 22H20V20H22V22ZM22 18H20V16H22V18ZM18 22H16V20H18V22ZM22 14H20V12H22V14ZM18 18H16V16H18V18ZM14 22H12V20H14V22ZM22 10H20V8H22V10ZM18 14H16V12H18V14ZM14 18H12V16H14V18ZM10 22H8V20H10V22Z`})})})]}),(0,s.jsx)(Se,{printerId:e,isOpen:Je,onClose:()=>Ye(!1)}),Xe&&(0,s.jsx)(de,{printerId:e,printerName:q?.name||null,onClose:()=>K(!1)})]})}export{c as EmbeddedCameraViewer};