refactor(app): introduce attachment storage layer and draft lifecycle management

Replace inline data-URL image handling with a persistent attachment storage service, add draft lifecycle states (active/abandoned/sent) with generation tracking, and update fetchAgent to return project placement alongside agent snapshots.
This commit is contained in:
Mohamed Boudra
2026-02-22 16:22:21 +07:00
parent 2652bdda2e
commit 0c710b09f5
55 changed files with 2381 additions and 350 deletions
+20 -5
View File
@@ -75,6 +75,7 @@ import { openExternalUrl } from "@/utils/open-external-url";
export type { InlinePathTarget } from "@/utils/inline-path";
import { useToolCallSheet } from "./tool-call-sheet";
import { ToolCallDetailsContent } from "./tool-call-details";
import { useAttachmentPreviewUrl } from "@/attachments/use-attachment-preview-url";
interface UserMessageProps {
message: string;
@@ -306,6 +307,11 @@ const userMessageStylesheet = StyleSheet.create((theme) => ({
width: 48,
height: 48,
},
imageThumbnailPlaceholder: {
width: 48,
height: 48,
backgroundColor: theme.colors.surface1,
},
copyButton: {
alignSelf: "flex-end",
padding: theme.spacing[1],
@@ -319,6 +325,18 @@ const userMessageStylesheet = StyleSheet.create((theme) => ({
},
}));
function UserMessageAttachmentThumbnail({
image,
}: {
image: UserMessageImageAttachment;
}) {
const uri = useAttachmentPreviewUrl(image);
if (!uri) {
return <View style={userMessageStylesheet.imageThumbnailPlaceholder} />;
}
return <Image source={{ uri }} style={userMessageStylesheet.imageThumbnail} />;
}
export const UserMessage = memo(function UserMessage({
message,
images = [],
@@ -368,13 +386,10 @@ export const UserMessage = memo(function UserMessage({
>
{images.map((image, index) => (
<View
key={`${image.uri}-${index}`}
key={`${image.id}-${index}`}
style={userMessageStylesheet.imagePill}
>
<Image
source={{ uri: image.uri }}
style={userMessageStylesheet.imageThumbnail}
/>
<UserMessageAttachmentThumbnail image={image} />
</View>
))}
</View>