- {attachments.map((file, idx) => (
+ {attachments.map((a, idx) => (
setAttachments((prev) => prev.filter((_, i) => i !== idx))}
- {...(file.type.startsWith('image/')
- ? { onEdit: () => setAnnotatingIndex(idx) }
+ {...(a.file.type.startsWith('image/')
+ ? {
+ onEdit: () => setAnnotatingIndex(idx),
+ onToggleViewOnce: () =>
+ setAttachments((prev) =>
+ prev.map((x, i) =>
+ i === idx ? { ...x, viewOnce: !x.viewOnce } : x,
+ ),
+ ),
+ }
: {})}
/>
))}
@@ -1451,10 +1475,17 @@ export function ConversationPage() {
{annotatingIndex !== null && attachments[annotatingIndex] && (
setAnnotatingIndex(null)}
onSave={(next) => {
- setAttachments((prev) => prev.map((f, i) => (i === annotatingIndex ? next : f)));
+ // Preserve the per-attachment viewOnce flag across annotation —
+ // the user's burn-after-viewing intent shouldn't reset just
+ // because they redrew the image.
+ setAttachments((prev) =>
+ prev.map((a, i) =>
+ i === annotatingIndex ? { file: next, viewOnce: a.viewOnce } : a,
+ ),
+ );
setAnnotatingIndex(null);
}}
/>
@@ -1811,13 +1842,18 @@ function Banner({ children }: { children: React.ReactNode }) {
function AttachmentPreview({
file,
+ viewOnce,
onRemove,
onEdit,
+ onToggleViewOnce,
}: {
file: File;
+ viewOnce: boolean;
onRemove: () => void;
onEdit?: () => void;
+ onToggleViewOnce?: () => void;
}) {
+ const { t } = useTranslation(['app']);
const isImage = file.type.startsWith('image/');
const [url, setUrl] = useState(null);
useEffect(() => {
@@ -1850,6 +1886,42 @@ function AttachmentPreview({
)}
+ {isImage && onToggleViewOnce && (
+
+ )}
+ {/* When viewOnce is on, overlay a persistent "1×" badge so the user
+ has visual confirmation independent of the small toggle button. */}
+ {isImage && viewOnce && (
+
+ 1×
+
+ )}