| 1 | import type { ImagePack, PackImage } from './types'; |
| 2 | |
| 3 | export const MAX_ATTACHMENT_BYTES = 20 * 1024 * 1024; |
| 4 | |
| 5 | export interface StagedAttachment { |
| 6 | id: number; |
| 7 | file: File; |
| 8 | previewUrl: string | null; |
| 9 | } |
| 10 | |
| 11 | export interface StickerHandlers { |
| 12 | onSend: (pack: ImagePack, image: PackImage) => void; |
| 13 | onClone: (pack: ImagePack, image: PackImage, x: number, y: number) => void; |
| 14 | onClonePack: (pack: ImagePack, x: number, y: number) => void; |
| 15 | onManage: () => void; |
| 16 | roomName: (roomId: string) => string; |
| 17 | } |
| 18 | |
| 19 | let nextId = 1; |
| 20 | |
| 21 | /** Files outside the homeserver-friendly size range are reported through `reject` and skipped. */ |
| 22 | export function stageFiles(files: File[], reject: (message: string) => void): StagedAttachment[] { |
| 23 | const accepted: StagedAttachment[] = []; |
| 24 | for (const file of files) { |
| 25 | if (file.size === 0 || file.size > MAX_ATTACHMENT_BYTES) { |
| 26 | reject(`${file.name || 'File'} must be between 1 byte and 20 MiB.`); |
| 27 | continue; |
| 28 | } |
| 29 | accepted.push({ id: nextId++, file, previewUrl: file.type.startsWith('image/') ? URL.createObjectURL(file) : null }); |
| 30 | } |
| 31 | return accepted; |
| 32 | } |
| 33 | |
| 34 | export function releaseStaged(list: StagedAttachment[]): void { |
| 35 | for (const attachment of list) if (attachment.previewUrl) URL.revokeObjectURL(attachment.previewUrl); |
| 36 | } |