diff --git a/firebaseai/FirebaseAIExample/Features/Multimodal/Models/MultimodalAttachment.swift b/firebaseai/FirebaseAIExample/Features/Multimodal/Models/MultimodalAttachment.swift index d98d78f47..cdcf7e63b 100644 --- a/firebaseai/FirebaseAIExample/Features/Multimodal/Models/MultimodalAttachment.swift +++ b/firebaseai/FirebaseAIExample/Features/Multimodal/Models/MultimodalAttachment.swift @@ -72,17 +72,23 @@ public struct MultimodalAttachment: Attachment, Equatable { } } +extension MultimodalAttachment: View { + public var body: some View { + AttachmentPreviewCard(attachment: self) + } +} + // validate file type & mime type extension MultimodalAttachment { public static let supportedFileExtensions: Set = [ - // Documents / text - "pdf", "txt", "text", // Images - "jpg", "jpeg", "png", "webp", + "png", "jpeg", "webp", // Video - "flv", "mov", "qt", "mpeg", "mpg", "ps", "mp4", "webm", "wmv", "3gp", "3gpp", + "flv", "mov", "mpeg", "mpegps", "mpg", "mp4", "webm", "wmv", "3gpp", // Audio - "aac", "flac", "mp3", "m4a", "mpga", "mp4a", "opus", "pcm", "raw", "wav", "weba", + "aac", "flac", "mp3", "mpa", "mpeg", "mpga", "mp4", "opus", "pcm", "wav", "webm", + // Documents + "pdf", "txt", ] public static func validateFileType(url: URL) throws { @@ -209,38 +215,32 @@ extension MultimodalAttachment { let fileExtension = url.pathExtension.lowercased() switch fileExtension { - // Documents / text - case "pdf": - return "application/pdf" - case "txt", "text": - return "text/plain" - // Images - case "jpg", "jpeg": - return "image/jpeg" case "png": return "image/png" + case "jpeg": + return "image/jpeg" case "webp": return "image/webp" // Video case "flv": return "video/x-flv" - case "mov", "qt": + case "mov": return "video/quicktime" case "mpeg": return "video/mpeg" + case "mpegps": + return "video/mpegps" case "mpg": return "video/mpg" - case "ps": - return "video/mpegps" case "mp4": return "video/mp4" case "webm": return "video/webm" case "wmv": return "video/wmv" - case "3gp", "3gpp": + case "3gpp": return "video/3gpp" // Audio @@ -249,22 +249,28 @@ extension MultimodalAttachment { case "flac": return "audio/flac" case "mp3": - return "audio/mpeg" - case "m4a": + return "audio/mp3" + case "mpa": return "audio/m4a" + case "mpeg": + return "audio/mpeg" case "mpga": return "audio/mpga" - case "mp4a": + case "mp4": return "audio/mp4" case "opus": return "audio/opus" - case "pcm", "raw": - return "audio/pcm" case "wav": return "audio/wav" - case "weba": + case "webm": return "audio/webm" + // Documents / text + case "pdf": + return "application/pdf" + case "txt": + return "text/plain" + default: return "application/octet-stream" } diff --git a/firebaseai/FirebaseAIExample/Features/Multimodal/Views/AttachmentPreviewCard.swift b/firebaseai/FirebaseAIExample/Features/Multimodal/Views/AttachmentPreviewCard.swift index 2bb37e25a..d0215d012 100644 --- a/firebaseai/FirebaseAIExample/Features/Multimodal/Views/AttachmentPreviewCard.swift +++ b/firebaseai/FirebaseAIExample/Features/Multimodal/Views/AttachmentPreviewCard.swift @@ -59,7 +59,6 @@ private enum AttachmentType: String { struct AttachmentPreviewCard: View { let attachment: MultimodalAttachment - let onRemove: (() -> Void)? private var attachmentType: AttachmentType { AttachmentType(mimeType: attachment.mimeType) @@ -93,16 +92,8 @@ struct AttachmentPreviewCard: View { Spacer() } } - - if let onRemove = onRemove { - Button(action: onRemove) { - Image(systemName: "xmark.circle.fill") - .font(.system(size: 16)) - .foregroundColor(.gray) - } - .buttonStyle(PlainButtonStyle()) - } } + .frame(width: 180) .padding(12) .background(Color(.systemGray6)) .clipShape(RoundedRectangle(cornerRadius: 12)) @@ -127,23 +118,19 @@ struct AttachmentPreviewCard: View { struct AttachmentPreviewScrollView: View { let attachments: [MultimodalAttachment] - var onAttachmentRemove: ((MultimodalAttachment) -> Void)? = nil var body: some View { if !attachments.isEmpty { ScrollView(.horizontal, showsIndicators: false) { - LazyHStack(spacing: 8) { + HStack { ForEach(attachments) { attachment in AttachmentPreviewCard( attachment: attachment, - onRemove: onAttachmentRemove == nil ? nil : { onAttachmentRemove?(attachment) } ) - .frame(width: 180) } } - .padding(.horizontal, 16) + .padding(.horizontal, 8) } - .frame(height: 80) } else { EmptyView() } @@ -157,7 +144,6 @@ struct AttachmentPreviewScrollView: View { mimeType: "image/jpeg", data: Data() ), - onRemove: { print("Image removed") } ) AttachmentPreviewCard( @@ -165,7 +151,6 @@ struct AttachmentPreviewScrollView: View { mimeType: "application/pdf", data: Data() ), - onRemove: { print("PDF removed") } ) AttachmentPreviewCard( @@ -173,7 +158,6 @@ struct AttachmentPreviewScrollView: View { mimeType: "video/mp4", data: Data() ), - onRemove: { print("Video removed") } ) AttachmentPreviewCard( @@ -181,7 +165,6 @@ struct AttachmentPreviewScrollView: View { mimeType: "audio/mpeg", data: Data() ), - onRemove: { print("Audio removed") } ) } .padding()