Unify attachment display and enable file uploads on all platforms (#1501)

Attachment pills were drawn by four separate style sets, so files,
images, GitHub items, and reviews rendered at different heights in the
same tray. Move the frame, the two-line label, and the image thumbnail
into shared components so every attachment lines up at one height,
across both the composer and sent messages.

Sent-message images now open the lightbox, and file uploads work on
iOS and Android via expo-document-picker instead of being gated to
desktop.
This commit is contained in:
Mohamed Boudra
2026-06-13 10:18:39 +08:00
committed by GitHub
parent a5c4ba4d89
commit ef750e0a85
15 changed files with 358 additions and 219 deletions
+4 -3
View File
@@ -575,10 +575,11 @@ describe("translation resources", () => {
});
it("includes remaining utility chrome keys for the Batch 4T migration", () => {
expect(en.message.attachments.reviewOne).toBe("Review · 1 comment");
expect(en.message.attachments.reviewMany).toBe("Review · {{count}} comments");
expect(en.message.attachments.review).toBe("Review");
expect(en.message.attachments.commentsOne).toBe("1 comment");
expect(en.message.attachments.commentsMany).toBe("{{count}} comments");
expect(en.message.attachments.textAttachment).toBe("Text attachment");
expect(en.composer.attachments.browserElement).toBe("Element · {{tag}}");
expect(en.composer.attachments.element).toBe("Element");
expect(en.workspace.hoverCard.scriptsAccessibility).toBe("Workspace scripts");
expect(en.branchSwitcher.restoreStashTitle).toBe("Restore stashed changes?");
expect(en.branchSwitcher.stashRestored).toBe("Stashed changes restored");
+6 -3
View File
@@ -110,7 +110,7 @@ export const ar: TranslationResources = {
removeFile: "Remove file attachment",
openGithub: "افتح{{kind}}#{{number}}",
removeGithub: "إزالة{{kind}}#{{number}}",
browserElement: "العنصر ·{{tag}}",
element: "عنصر",
openBrowserElement: "افتح مرفق عنصر المتصفح",
removeBrowserElement: "إزالة مرفق عنصر المتصفح",
openReview: "فتح مرفق المراجعة",
@@ -255,9 +255,12 @@ export const ar: TranslationResources = {
imageUnavailable: "الصورة غير متاحة",
imagePreviewUnavailable: "معاينة الصورة غير متاحة.",
imagePreviewLoadFailed: "غير قادر على تحميل معاينة الصورة.",
reviewOne: "مراجعة · تعليق واحد",
reviewMany: "مراجعة · تعليقات{{count}}",
review: "مراجعة",
commentsOne: "تعليق واحد",
commentsMany: "{{count}} تعليقات",
textAttachment: "مرفق النص",
text: "نص",
file: "ملف",
},
speak: {
header: "تكلم",
+6 -3
View File
@@ -108,7 +108,7 @@ export const en = {
removeFile: "Remove file attachment",
openGithub: "Open {{kind}} #{{number}}",
removeGithub: "Remove {{kind}} #{{number}}",
browserElement: "Element · {{tag}}",
element: "Element",
openBrowserElement: "Open browser element attachment",
removeBrowserElement: "Remove browser element attachment",
openReview: "Open review attachment",
@@ -254,9 +254,12 @@ export const en = {
imageUnavailable: "Image unavailable",
imagePreviewUnavailable: "Image preview unavailable.",
imagePreviewLoadFailed: "Unable to load image preview.",
reviewOne: "Review · 1 comment",
reviewMany: "Review · {{count}} comments",
review: "Review",
commentsOne: "1 comment",
commentsMany: "{{count}} comments",
textAttachment: "Text attachment",
text: "Text",
file: "File",
},
speak: {
header: "Spoke",
+6 -3
View File
@@ -110,7 +110,7 @@ export const es: TranslationResources = {
removeFile: "Remove file attachment",
openGithub: "Abrir{{kind}}#{{number}}",
removeGithub: "Quitar{{kind}}#{{number}}",
browserElement: "Elemento ·{{tag}}",
element: "Elemento",
openBrowserElement: "Abrir archivo adjunto de elemento del navegador",
removeBrowserElement: "Eliminar el archivo adjunto del elemento del navegador",
openReview: "Abrir archivo adjunto de reseña",
@@ -258,9 +258,12 @@ export const es: TranslationResources = {
imageUnavailable: "Imagen no disponible",
imagePreviewUnavailable: "Vista previa de la imagen no disponible.",
imagePreviewLoadFailed: "No se puede cargar la vista previa de la imagen.",
reviewOne: "Reseña · 1 comentario",
reviewMany: "Revisión · Comentarios{{count}}",
review: "Revisión",
commentsOne: "1 comentario",
commentsMany: "{{count}} comentarios",
textAttachment: "Adjunto de texto",
text: "Texto",
file: "Archivo",
},
speak: {
header: "Habló",
+6 -3
View File
@@ -111,7 +111,7 @@ export const fr: TranslationResources = {
removeFile: "Remove file attachment",
openGithub: "Ouvrir{{kind}}#{{number}}",
removeGithub: "Supprimer{{kind}}#{{number}}",
browserElement: "Élément ·{{tag}}",
element: "Élément",
openBrowserElement: "Ouvrir la pièce jointe de l'élément de navigateur",
removeBrowserElement: "Supprimer la pièce jointe d'un élément de navigateur",
openReview: "Ouvrir la pièce jointe de l'avis",
@@ -258,9 +258,12 @@ export const fr: TranslationResources = {
imageUnavailable: "Image indisponible",
imagePreviewUnavailable: "Aperçu de l'image indisponible.",
imagePreviewLoadFailed: "Impossible de charger l'aperçu de l'image.",
reviewOne: "Avis · 1 commentaire",
reviewMany: "Révision · Commentaires{{count}}",
review: "Revue",
commentsOne: "1 commentaire",
commentsMany: "{{count}} commentaires",
textAttachment: "Texte en pièce jointe",
text: "Texte",
file: "Fichier",
},
speak: {
header: "Rayon",
+6 -3
View File
@@ -110,7 +110,7 @@ export const ru: TranslationResources = {
removeFile: "Remove file attachment",
openGithub: "Открыть{{kind}}#{{number}}",
removeGithub: "Удалить{{kind}}#{{number}}",
browserElement: "Элемент ·{{tag}}",
element: "Элемент",
openBrowserElement: "Открыть вложение элемента браузера",
removeBrowserElement: "Удалить вложение элемента браузера",
openReview: "Открыть прикрепленный файл с отзывом",
@@ -257,9 +257,12 @@ export const ru: TranslationResources = {
imageUnavailable: "Изображение недоступно",
imagePreviewUnavailable: "Предварительный просмотр изображения недоступен.",
imagePreviewLoadFailed: "Невозможно загрузить предварительный просмотр изображения.",
reviewOne: "Отзыв · 1 комментарий",
reviewMany: "Обзор · Комментарии{{count}}",
review: "Ревью",
commentsOne: "1 комментарий",
commentsMany: "Комментарии: {{count}}",
textAttachment: "Текстовое вложение",
text: "Текст",
file: "Файл",
},
speak: {
header: "Говорил",
+6 -3
View File
@@ -110,7 +110,7 @@ export const zhCN: TranslationResources = {
removeFile: "Remove file attachment",
openGithub: "打开 {{kind}} #{{number}}",
removeGithub: "移除 {{kind}} #{{number}}",
browserElement: "元素 · {{tag}}",
element: "元素",
openBrowserElement: "打开浏览器元素附件",
removeBrowserElement: "移除浏览器元素附件",
openReview: "打开 review 附件",
@@ -255,9 +255,12 @@ export const zhCN: TranslationResources = {
imageUnavailable: "图片不可用",
imagePreviewUnavailable: "图片预览不可用。",
imagePreviewLoadFailed: "无法加载图片预览。",
reviewOne: "Review · 1 条评论",
reviewMany: "Review · {{count}} 条评论",
review: "审查",
commentsOne: "1 条评论",
commentsMany: "{{count}} 条评论",
textAttachment: "文本附件",
text: "文本",
file: "文件",
},
speak: {
header: "已朗读",