()
| 10 | import { toast } from "sonner"; |
| 11 | |
| 12 | export default function BackgroundManagerWindow() { |
| 13 | const [tab] = useAtom(activeTabAtom); |
| 14 | const project = tab instanceof Project ? tab : undefined; |
| 15 | const [backgroundImages, setBackgroundImages] = useState<ImageNode[]>([]); |
| 16 | const [urls, setUrls] = useState(new Map<string, string>()); |
| 17 | const [brokenUuids, setBrokenUuids] = useState(new Set<string>()); |
| 18 | |
| 19 | useEffect(() => { |
| 20 | if (project) { |
| 21 | // 获取所有背景化的图片 |
| 22 | const images = project.stageManager.getImageNodes().filter((imageNode) => imageNode.isBackground); |
| 23 | setBackgroundImages(images); |
| 24 | } |
| 25 | }, [project]); |
| 26 | |
| 27 | useEffect(() => { |
| 28 | if (!project) return; |
| 29 | const newUrls = new Map<string, string>(); |
| 30 | for (const imageNode of backgroundImages) { |
| 31 | const blob = project.attachments.get(imageNode.attachmentId); |
| 32 | if (!blob) continue; |
| 33 | newUrls.set(imageNode.uuid, URL.createObjectURL(blob)); |
| 34 | } |
| 35 | setUrls(newUrls); |
| 36 | setBrokenUuids((prev) => { |
| 37 | if (prev.size === 0) return prev; |
| 38 | const next = new Set<string>(); |
| 39 | for (const uuid of prev) { |
| 40 | if (backgroundImages.some((it) => it.uuid === uuid)) next.add(uuid); |
| 41 | } |
| 42 | return next; |
| 43 | }); |
| 44 | return () => { |
| 45 | newUrls.forEach((url) => { |
| 46 | URL.revokeObjectURL(url); |
| 47 | }); |
| 48 | }; |
| 49 | }, [project, backgroundImages]); |
| 50 | |
| 51 | const handleRemoveBackground = (imageNode: ImageNode) => { |
| 52 | if (project) { |
| 53 | imageNode.isBackground = false; |
| 54 | project.historyManager.recordStep(); |
| 55 | toast.success("已取消图片的背景化"); |
| 56 | // 刷新背景图片列表 |
| 57 | const images = project.stageManager.getImageNodes().filter((imageNode) => imageNode.isBackground); |
| 58 | setBackgroundImages(images); |
| 59 | } |
| 60 | }; |
| 61 | |
| 62 | return ( |
| 63 | <div className="flex flex-col gap-4 p-4"> |
| 64 | <h1 className="text-xl font-semibold">背景管理器</h1> |
| 65 | <div className="flex-1"> |
| 66 | {backgroundImages.length === 0 ? ( |
| 67 | <p className="text-muted-foreground text-center">当前舞台上没有背景化的图片</p> |
| 68 | ) : ( |
| 69 | <div className="space-y-4"> |
nothing calls this directly
no test coverage detected