diff --git a/.maestro/features/03-compose-send.yaml b/.maestro/features/03-compose-send.yaml
index b115bd5a7..2b3ac3b38 100644
--- a/.maestro/features/03-compose-send.yaml
+++ b/.maestro/features/03-compose-send.yaml
@@ -9,7 +9,8 @@ tags:
- evalScript: ${output.subject = 'E2E compose ' + DEVICE + '-' + APPEARANCE + '-' + ORIENTATION + ' ' + Date.now()}
- tapOn: "Compose"
- extendedWaitUntil:
- visible: "New Message"
+ visible:
+ id: "compose-header"
timeout: 15000
- tapOn: "Recipient email addresses"
- inputText: "userb@example.org"
@@ -28,13 +29,13 @@ tags:
# The attach sheet offers its options one by one (it used to be a single
# accessibility element, and picking one opened no picker on iOS).
- tapOn: "Attach"
+# iOS keeps "Photos & Videos"; Android names the same row "Gallery".
- extendedWaitUntil:
visible: "Photos & Videos"
timeout: 10000
- assertVisible: "Camera"
-# A server with Files offers "Upload from this device" and "Attach from
-# Files" instead of a plain "Files".
-- assertVisible: "Upload from this device|Files"
+# The phone's own files; a server with Files adds "Bulwark Files" below.
+- assertVisible: "This device"
- takeScreenshot: compose-02-attach-sheet
- evalScript: ${output.pickPhoto = ORIENTATION != 'landscape'}
# The system photo picker runs in another process: XCTest sees none of its
@@ -52,7 +53,8 @@ tags:
commands:
- tapOn: "Photos & Videos"
- extendedWaitUntil:
- notVisible: "Draft saved|New Message"
+ notVisible:
+ id: "compose-header"
timeout: 10000
optional: true
- waitForAnimationToEnd:
@@ -79,7 +81,8 @@ tags:
- tapOn:
point: "90%,13%"
- extendedWaitUntil:
- visible: "New Message"
+ visible:
+ id: "compose-header"
timeout: 20000
- waitForAnimationToEnd:
timeout: 5000
diff --git a/.maestro/features/08-scheduled-send.yaml b/.maestro/features/08-scheduled-send.yaml
index 777b217ae..de40c2fc0 100644
--- a/.maestro/features/08-scheduled-send.yaml
+++ b/.maestro/features/08-scheduled-send.yaml
@@ -9,7 +9,8 @@ tags:
- evalScript: ${output.subject = 'E2E scheduled ' + DEVICE + '-' + APPEARANCE + '-' + ORIENTATION + ' ' + Date.now()}
- tapOn: "Compose"
- extendedWaitUntil:
- visible: "New Message"
+ visible:
+ id: "compose-header"
timeout: 15000
- tapOn: "Recipient email addresses"
- inputText: "userb@example.org"
diff --git a/.maestro/perf/3-compose.yaml b/.maestro/perf/3-compose.yaml
index 49651559d..0aa1f871e 100644
--- a/.maestro/perf/3-compose.yaml
+++ b/.maestro/perf/3-compose.yaml
@@ -9,7 +9,8 @@ name: Perf compose open
commands:
- tapOn: "Compose"
- extendedWaitUntil:
- visible: "New Message"
+ visible:
+ id: "compose-header"
timeout: 20000
- waitForAnimationToEnd:
timeout: 3000
diff --git a/locales/rn/ar.json b/locales/rn/ar.json
index 77ff076c4..ea271fd99 100644
--- a/locales/rn/ar.json
+++ b/locales/rn/ar.json
@@ -322,7 +322,10 @@
"signing_out": "جارٍ إزالة جهات الاتصال والتقويمات المتزامنة من هذا الجهاز…"
},
"email_composer": {
+ "attach_bulwark_files": "ملفات Bulwark",
"attach_camera": "الكاميرا",
+ "attach_gallery": "المعرض",
+ "attach_this_device": "هذا الجهاز",
"attachment_reminder_body": "تذكر رسالتك \"{keyword}\" لكن لم يتم إرفاق أي ملف. هل تريد الإرسال على أي حال؟",
"attachment_reminder_title": "هل نسيت إرفاق ملف؟",
"attachments_too_large_total": "ستتجاوز المرفقات الحد {max} الذي يسمح به هذا الخادم لكل رسالة.",
diff --git a/locales/rn/ca.json b/locales/rn/ca.json
index 838217699..0345ef70c 100644
--- a/locales/rn/ca.json
+++ b/locales/rn/ca.json
@@ -322,7 +322,10 @@
"signing_out": "S'estan eliminant d'aquest dispositiu els contactes i calendaris sincronitzats…"
},
"email_composer": {
+ "attach_bulwark_files": "Fitxers de Bulwark",
"attach_camera": "Càmera",
+ "attach_gallery": "Galeria",
+ "attach_this_device": "Aquest dispositiu",
"attachment_reminder_body": "El vostre missatge esmenta «{keyword}», però no hi ha cap fitxer adjunt. Voleu enviar-lo igualment?",
"attachment_reminder_title": "Us heu oblidat d'un fitxer adjunt?",
"attachments_too_large_total": "Els fitxers adjunts superarien els {max} que aquest servidor permet per missatge.",
diff --git a/locales/rn/cs.json b/locales/rn/cs.json
index 8438860a9..b7fb06c77 100644
--- a/locales/rn/cs.json
+++ b/locales/rn/cs.json
@@ -322,7 +322,10 @@
"signing_out": "Odebírání synchronizovaných kontaktů a kalendářů z tohoto zařízení…"
},
"email_composer": {
+ "attach_bulwark_files": "Soubory Bulwark",
"attach_camera": "Fotoaparát",
+ "attach_gallery": "Galerie",
+ "attach_this_device": "Toto zařízení",
"attachment_reminder_body": "Vaše zpráva obsahuje slovo „{keyword}“, ale není k ní připojen žádný soubor. Přesto odeslat?",
"attachment_reminder_title": "Nezapomněli jste přílohu?",
"attachments_too_large_total": "Přílohy by překročily limit {max}, který tento server povoluje na jednu zprávu.",
diff --git a/locales/rn/da.json b/locales/rn/da.json
index 32aab6412..78cd880b6 100644
--- a/locales/rn/da.json
+++ b/locales/rn/da.json
@@ -322,7 +322,10 @@
"signing_out": "Fjerner synkroniserede kontakter og kalendere fra denne enhed…"
},
"email_composer": {
+ "attach_bulwark_files": "Bulwark-filer",
"attach_camera": "Kamera",
+ "attach_gallery": "Galleri",
+ "attach_this_device": "Denne enhed",
"attachment_reminder_body": "Din besked nævner \"{keyword}\", men ingen fil er vedhæftet. Send alligevel?",
"attachment_reminder_title": "Glemt en vedhæftning?",
"attachments_too_large_total": "Vedhæftningerne ville overskride de {max}, som denne server tillader pr. besked.",
diff --git a/locales/rn/de.json b/locales/rn/de.json
index a8cf809f2..331b5fe4d 100644
--- a/locales/rn/de.json
+++ b/locales/rn/de.json
@@ -325,7 +325,10 @@
"signing_out": "Synchronisierte Kontakte und Kalender werden von diesem Gerät entfernt…"
},
"email_composer": {
+ "attach_bulwark_files": "Bulwark-Dateien",
"attach_camera": "Kamera",
+ "attach_gallery": "Galerie",
+ "attach_this_device": "Dieses Gerät",
"attachment_reminder_body": "Ihre Nachricht erwähnt \"{keyword}\", aber es ist keine Datei angehängt. Trotzdem senden?",
"attachment_reminder_title": "Anhang vergessen?",
"attachments_too_large_total": "Die Anhänge würden die {max} überschreiten, die dieser Server pro Nachricht erlaubt.",
diff --git a/locales/rn/en.json b/locales/rn/en.json
index 41171eb30..19d81d349 100644
--- a/locales/rn/en.json
+++ b/locales/rn/en.json
@@ -348,7 +348,10 @@
"signing_out": "Removing synced contacts and calendars from this device…"
},
"email_composer": {
+ "attach_bulwark_files": "Bulwark Files",
"attach_camera": "Camera",
+ "attach_gallery": "Gallery",
+ "attach_this_device": "This device",
"attachment_reminder_body": "Your message mentions \"{keyword}\" but no file is attached. Send anyway?",
"attachment_reminder_title": "Forgot an attachment?",
"attachments_too_large_total": "The attachments would exceed the {max} this server allows per message.",
diff --git a/locales/rn/es.json b/locales/rn/es.json
index 99a48255f..f2012348e 100644
--- a/locales/rn/es.json
+++ b/locales/rn/es.json
@@ -322,7 +322,10 @@
"signing_out": "Quitando de este dispositivo los contactos y calendarios sincronizados…"
},
"email_composer": {
+ "attach_bulwark_files": "Archivos de Bulwark",
"attach_camera": "Cámara",
+ "attach_gallery": "Galería",
+ "attach_this_device": "Este dispositivo",
"attachment_reminder_body": "Tu mensaje menciona \"{keyword}\" pero no hay ningún archivo adjunto. ¿Enviar de todos modos?",
"attachment_reminder_title": "¿Olvidaste un adjunto?",
"attachments_too_large_total": "Los adjuntos superarían los {max} que este servidor permite por mensaje.",
diff --git a/locales/rn/et.json b/locales/rn/et.json
index ff57ca097..74adaa627 100644
--- a/locales/rn/et.json
+++ b/locales/rn/et.json
@@ -1194,7 +1194,10 @@
"signing_out": "Sünkroonitud kontaktide ja kalendrite eemaldamine sellest seadmest…"
},
"email_composer": {
+ "attach_bulwark_files": "Bulwarki failid",
"attach_camera": "Kaamera",
+ "attach_gallery": "Galerii",
+ "attach_this_device": "See seade",
"attachment_reminder_body": "Sinu sõnumis mainitakse \"{keyword}\", kuid ühtegi faili pole lisatud. Kas saata ikkagi?",
"attachment_reminder_title": "Kas manus ununes?",
"attachments_too_large_total": "Manused ületaksid selle serveri lubatud piiri {max} kirja kohta.",
diff --git a/locales/rn/fa.json b/locales/rn/fa.json
index bdb944504..7c9281f31 100644
--- a/locales/rn/fa.json
+++ b/locales/rn/fa.json
@@ -322,7 +322,10 @@
"signing_out": "در حال حذف مخاطبین و تقویمهای همگامسازیشده از این دستگاه…"
},
"email_composer": {
+ "attach_bulwark_files": "فایلهای Bulwark",
"attach_camera": "دوربین",
+ "attach_gallery": "گالری",
+ "attach_this_device": "این دستگاه",
"attachment_reminder_body": "در پیام شما به «{keyword}» اشاره شده اما فایلی پیوست نشده است. با این حال ارسال شود؟",
"attachment_reminder_title": "پیوست را فراموش کردهاید؟",
"attachments_too_large_total": "پیوستها از سقف {max} که این سرور برای هر پیام مجاز میداند بیشتر میشوند.",
diff --git a/locales/rn/fr.json b/locales/rn/fr.json
index b56e1d874..92c605f08 100644
--- a/locales/rn/fr.json
+++ b/locales/rn/fr.json
@@ -322,7 +322,10 @@
"signing_out": "Suppression des contacts et calendriers synchronisés de cet appareil…"
},
"email_composer": {
+ "attach_bulwark_files": "Fichiers Bulwark",
"attach_camera": "Appareil photo",
+ "attach_gallery": "Galerie",
+ "attach_this_device": "Cet appareil",
"attachment_reminder_body": "Votre message mentionne « {keyword} » mais aucun fichier n'est joint. Envoyer quand même ?",
"attachment_reminder_title": "Pièce jointe oubliée ?",
"attachments_too_large_total": "Les pièces jointes dépasseraient les {max} autorisés par ce serveur pour un message.",
diff --git a/locales/rn/he.json b/locales/rn/he.json
index 0a78c29e6..7bacfd9ba 100644
--- a/locales/rn/he.json
+++ b/locales/rn/he.json
@@ -322,7 +322,10 @@
"signing_out": "מסיר מהמכשיר הזה את אנשי הקשר ולוחות השנה המסונכרנים…"
},
"email_composer": {
+ "attach_bulwark_files": "קבצי Bulwark",
"attach_camera": "מצלמה",
+ "attach_gallery": "גלריה",
+ "attach_this_device": "מכשיר זה",
"attachment_reminder_body": "ההודעה שלך מזכירה \"{keyword}\" אבל לא צורף קובץ. לשלוח בכל זאת?",
"attachment_reminder_title": "שכחת קובץ מצורף?",
"attachments_too_large_total": "הקבצים המצורפים יחרגו מהמגבלה של {max} להודעה שהשרת הזה מאפשר.",
diff --git a/locales/rn/hu.json b/locales/rn/hu.json
index 85ba2eab8..84cbe31ae 100644
--- a/locales/rn/hu.json
+++ b/locales/rn/hu.json
@@ -322,7 +322,10 @@
"signing_out": "A szinkronizált névjegyek és naptárak eltávolítása erről az eszközről…"
},
"email_composer": {
+ "attach_bulwark_files": "Bulwark-fájlok",
"attach_camera": "Kamera",
+ "attach_gallery": "Galéria",
+ "attach_this_device": "Ez az eszköz",
"attachment_reminder_body": "Az üzeneted említi a(z) „{keyword}” kifejezést, de nincs fájl csatolva. Elküldöd így is?",
"attachment_reminder_title": "Elfelejtetted a csatolmányt?",
"attachments_too_large_total": "A csatolmányok túllépnék a szerver által üzenetenként engedélyezett méretet ({max}).",
diff --git a/locales/rn/it.json b/locales/rn/it.json
index ced0f08ea..3943d77b4 100644
--- a/locales/rn/it.json
+++ b/locales/rn/it.json
@@ -322,7 +322,10 @@
"signing_out": "Rimozione dei contatti e dei calendari sincronizzati da questo dispositivo…"
},
"email_composer": {
+ "attach_bulwark_files": "File di Bulwark",
"attach_camera": "Fotocamera",
+ "attach_gallery": "Galleria",
+ "attach_this_device": "Questo dispositivo",
"attachment_reminder_body": "Il tuo messaggio menziona \"{keyword}\" ma nessun file è allegato. Inviare comunque?",
"attachment_reminder_title": "Hai dimenticato un allegato?",
"attachments_too_large_total": "Gli allegati supererebbero i {max} consentiti da questo server per messaggio.",
diff --git a/locales/rn/ja.json b/locales/rn/ja.json
index c707429fa..bdc7932de 100644
--- a/locales/rn/ja.json
+++ b/locales/rn/ja.json
@@ -322,7 +322,10 @@
"signing_out": "同期した連絡先とカレンダーをこのデバイスから削除しています…"
},
"email_composer": {
+ "attach_bulwark_files": "Bulwark ファイル",
"attach_camera": "カメラ",
+ "attach_gallery": "ギャラリー",
+ "attach_this_device": "このデバイス",
"attachment_reminder_body": "メッセージに「{keyword}」が含まれていますが、ファイルが添付されていません。このまま送信しますか?",
"attachment_reminder_title": "添付ファイルを忘れていませんか?",
"attachments_too_large_total": "添付ファイルがサーバーの上限(1 通あたり {max})を超えます。",
diff --git a/locales/rn/ko.json b/locales/rn/ko.json
index e339356ad..07bc4dc18 100644
--- a/locales/rn/ko.json
+++ b/locales/rn/ko.json
@@ -322,7 +322,10 @@
"signing_out": "동기화된 연락처와 캘린더를 이 기기에서 삭제하는 중…"
},
"email_composer": {
+ "attach_bulwark_files": "Bulwark 파일",
"attach_camera": "카메라",
+ "attach_gallery": "갤러리",
+ "attach_this_device": "이 기기",
"attachment_reminder_body": "메시지에 \"{keyword}\"이(가) 언급되어 있지만 첨부된 파일이 없어요. 그래도 보낼까요?",
"attachment_reminder_title": "첨부 파일을 잊으셨나요?",
"attachments_too_large_total": "첨부 파일이 이 서버의 메시지당 한도({max})를 넘어요.",
diff --git a/locales/rn/lv.json b/locales/rn/lv.json
index bfbab989b..6ff34c1b9 100644
--- a/locales/rn/lv.json
+++ b/locales/rn/lv.json
@@ -322,7 +322,10 @@
"signing_out": "Sinhronizētie kontakti un kalendāri tiek noņemti no šīs ierīces…"
},
"email_composer": {
+ "attach_bulwark_files": "Bulwark faili",
"attach_camera": "Kamera",
+ "attach_gallery": "Galerija",
+ "attach_this_device": "Šī ierīce",
"attachment_reminder_body": "Jūsu ziņojumā minēts \"{keyword}\", bet nav pievienots neviens fails. Vai tomēr sūtīt?",
"attachment_reminder_title": "Aizmirsāt pielikumu?",
"attachments_too_large_total": "Pielikumi pārsniegtu {max}, ko šis serveris atļauj vienam ziņojumam.",
diff --git a/locales/rn/mn.json b/locales/rn/mn.json
index 545763ec6..1de055967 100644
--- a/locales/rn/mn.json
+++ b/locales/rn/mn.json
@@ -322,7 +322,10 @@
"signing_out": "Синк хийсэн харилцагчид болон хуанлиудыг энэ төхөөрөмжөөс устгаж байна…"
},
"email_composer": {
+ "attach_bulwark_files": "Bulwark файл",
"attach_camera": "Камер",
+ "attach_gallery": "Галерей",
+ "attach_this_device": "Энэ төхөөрөмж",
"attachment_reminder_body": "Таны имэйлд \"{keyword}\" гэж дурдсан ч файл хавсаргаагүй байна. Ямар ч байсан илгээх үү?",
"attachment_reminder_title": "Хавсралтаа мартсан уу?",
"attachments_too_large_total": "Хавсралтууд энэ серверийн нэг имэйлд зөвшөөрөх {max} хэмжээнээс хэтэрнэ.",
diff --git a/locales/rn/nb.json b/locales/rn/nb.json
index f577863ec..d8ac49c35 100644
--- a/locales/rn/nb.json
+++ b/locales/rn/nb.json
@@ -322,7 +322,10 @@
"signing_out": "Fjerner synkroniserte kontakter og kalendere fra denne enheten…"
},
"email_composer": {
+ "attach_bulwark_files": "Bulwark-filer",
"attach_camera": "Kamera",
+ "attach_gallery": "Galleri",
+ "attach_this_device": "Denne enheten",
"attachment_reminder_body": "Meldingen din nevner «{keyword}», men ingen fil er vedlagt. Sende likevel?",
"attachment_reminder_title": "Glemt et vedlegg?",
"attachments_too_large_total": "Vedleggene ville overskride grensen på {max} per melding som denne serveren tillater.",
diff --git a/locales/rn/nl.json b/locales/rn/nl.json
index 0305eeb25..6feffbdbf 100644
--- a/locales/rn/nl.json
+++ b/locales/rn/nl.json
@@ -322,7 +322,10 @@
"signing_out": "Gesynchroniseerde contacten en agenda's worden van dit apparaat verwijderd…"
},
"email_composer": {
+ "attach_bulwark_files": "Bulwark-bestanden",
"attach_camera": "Camera",
+ "attach_gallery": "Galerij",
+ "attach_this_device": "Dit apparaat",
"attachment_reminder_body": "Uw bericht vermeldt \"{keyword}\" maar er is geen bestand bijgevoegd. Toch verzenden?",
"attachment_reminder_title": "Bijlage vergeten?",
"attachments_too_large_total": "De bijlagen zouden de {max} overschrijden die deze server per bericht toestaat.",
diff --git a/locales/rn/pl.json b/locales/rn/pl.json
index 16974c1b4..b87ceee0f 100644
--- a/locales/rn/pl.json
+++ b/locales/rn/pl.json
@@ -322,7 +322,10 @@
"signing_out": "Usuwanie zsynchronizowanych kontaktów i kalendarzy z tego urządzenia…"
},
"email_composer": {
+ "attach_bulwark_files": "Pliki Bulwark",
"attach_camera": "Aparat",
+ "attach_gallery": "Galeria",
+ "attach_this_device": "To urządzenie",
"attachment_reminder_body": "Twoja wiadomość wspomina o „{keyword}”, ale nie załączono żadnego pliku. Wysłać mimo to?",
"attachment_reminder_title": "Zapomniano o załączniku?",
"attachments_too_large_total": "Załączniki przekroczyłyby limit {max} na wiadomość obowiązujący na tym serwerze.",
diff --git a/locales/rn/pt.json b/locales/rn/pt.json
index a8ddcbfea..74decdc26 100644
--- a/locales/rn/pt.json
+++ b/locales/rn/pt.json
@@ -322,7 +322,10 @@
"signing_out": "Removendo contatos e calendários sincronizados deste dispositivo…"
},
"email_composer": {
+ "attach_bulwark_files": "Arquivos do Bulwark",
"attach_camera": "Câmera",
+ "attach_gallery": "Galeria",
+ "attach_this_device": "Este dispositivo",
"attachment_reminder_body": "Sua mensagem menciona \"{keyword}\", mas nenhum arquivo está anexado. Enviar mesmo assim?",
"attachment_reminder_title": "Esqueceu um anexo?",
"attachments_too_large_total": "Os anexos excederiam o limite de {max} por mensagem permitido por este servidor.",
diff --git a/locales/rn/ro.json b/locales/rn/ro.json
index b950ba299..c6ca1dda5 100644
--- a/locales/rn/ro.json
+++ b/locales/rn/ro.json
@@ -322,7 +322,10 @@
"signing_out": "Se elimină de pe acest dispozitiv contactele și calendarele sincronizate…"
},
"email_composer": {
+ "attach_bulwark_files": "Fișiere Bulwark",
"attach_camera": "Cameră",
+ "attach_gallery": "Galerie",
+ "attach_this_device": "Acest dispozitiv",
"attachment_reminder_body": "Mesajul dvs. menționează „{keyword}”, dar nu este atașat niciun fișier. Doriți să trimiteți oricum?",
"attachment_reminder_title": "Ați uitat un atașament?",
"attachments_too_large_total": "Atașamentele ar depăși limita de {max} per mesaj permisă de acest server.",
diff --git a/locales/rn/ru.json b/locales/rn/ru.json
index ef07729ba..e89bc7828 100644
--- a/locales/rn/ru.json
+++ b/locales/rn/ru.json
@@ -322,7 +322,10 @@
"signing_out": "Удаление синхронизированных контактов и календарей с этого устройства…"
},
"email_composer": {
+ "attach_bulwark_files": "Файлы Bulwark",
"attach_camera": "Камера",
+ "attach_gallery": "Галерея",
+ "attach_this_device": "Это устройство",
"attachment_reminder_body": "В письме упоминается «{keyword}», но файл не прикреплён. Всё равно отправить?",
"attachment_reminder_title": "Забыли вложение?",
"attachments_too_large_total": "Вложения превысят лимит {max} на одно письмо, установленный этим сервером.",
diff --git a/locales/rn/sk.json b/locales/rn/sk.json
index 0a28af946..5721d7821 100644
--- a/locales/rn/sk.json
+++ b/locales/rn/sk.json
@@ -322,7 +322,10 @@
"signing_out": "Odstraňujú sa synchronizované kontakty a kalendáre z tohto zariadenia…"
},
"email_composer": {
+ "attach_bulwark_files": "Súbory Bulwark",
"attach_camera": "Fotoaparát",
+ "attach_gallery": "Galéria",
+ "attach_this_device": "Toto zariadenie",
"attachment_reminder_body": "Vaša správa spomína „{keyword}“, ale nie je priložený žiadny súbor. Odoslať aj tak?",
"attachment_reminder_title": "Nezabudli ste prílohu?",
"attachments_too_large_total": "Prílohy by prekročili limit {max}, ktorý tento server povoľuje na jednu správu.",
diff --git a/locales/rn/th.json b/locales/rn/th.json
index 30edd6db5..740b82b16 100644
--- a/locales/rn/th.json
+++ b/locales/rn/th.json
@@ -324,7 +324,10 @@
"signing_out": "กำลังนำผู้ติดต่อและปฏิทินที่ซิงค์ไว้ออกจากอุปกรณ์นี้…"
},
"email_composer": {
+ "attach_bulwark_files": "ไฟล์ Bulwark",
"attach_camera": "กล้อง",
+ "attach_gallery": "แกลเลอรี",
+ "attach_this_device": "อุปกรณ์นี้",
"attachment_reminder_body": "ข้อความของคุณมีคำว่า “{keyword}” แต่ไม่มีไฟล์แนบ ต้องการส่งต่อไปหรือไม่?",
"attachment_reminder_title": "ลืมแนบไฟล์หรือไม่?",
"attachments_too_large_total": "ไฟล์แนบจะเกิน {max} ที่เซิร์ฟเวอร์นี้อนุญาตต่อข้อความ",
diff --git a/locales/rn/tr.json b/locales/rn/tr.json
index 9430954a6..d820da0ab 100644
--- a/locales/rn/tr.json
+++ b/locales/rn/tr.json
@@ -322,7 +322,10 @@
"signing_out": "Senkronize edilen kişiler ve takvimler bu cihazdan kaldırılıyor…"
},
"email_composer": {
+ "attach_bulwark_files": "Bulwark Dosyaları",
"attach_camera": "Kamera",
+ "attach_gallery": "Galeri",
+ "attach_this_device": "Bu cihaz",
"attachment_reminder_body": "İletinizde \"{keyword}\" geçiyor ancak hiçbir dosya eklenmemiş. Yine de gönderilsin mi?",
"attachment_reminder_title": "Ek eklemeyi mi unuttunuz?",
"attachments_too_large_total": "Ekler, bu sunucunun ileti başına izin verdiği {max} sınırını aşacak.",
diff --git a/locales/rn/uk.json b/locales/rn/uk.json
index 215ec54b1..d8000800d 100644
--- a/locales/rn/uk.json
+++ b/locales/rn/uk.json
@@ -322,7 +322,10 @@
"signing_out": "Видалення синхронізованих контактів і календарів із цього пристрою…"
},
"email_composer": {
+ "attach_bulwark_files": "Файли Bulwark",
"attach_camera": "Камера",
+ "attach_gallery": "Галерея",
+ "attach_this_device": "Цей пристрій",
"attachment_reminder_body": "У листі згадано «{keyword}», але файл не вкладено. Усе одно надіслати?",
"attachment_reminder_title": "Забули вкладення?",
"attachments_too_large_total": "Вкладення перевищать ліміт {max} на один лист, встановлений цим сервером.",
diff --git a/locales/rn/zh-TW.json b/locales/rn/zh-TW.json
index cb2cee9fc..d6eca7163 100644
--- a/locales/rn/zh-TW.json
+++ b/locales/rn/zh-TW.json
@@ -322,7 +322,10 @@
"signing_out": "正在從此裝置移除已同步的聯絡人和行事曆…"
},
"email_composer": {
+ "attach_bulwark_files": "Bulwark 檔案",
"attach_camera": "相機",
+ "attach_gallery": "圖庫",
+ "attach_this_device": "此裝置",
"attachment_reminder_body": "您的郵件提到「{keyword}」,但沒有附加檔案。仍要傳送嗎?",
"attachment_reminder_title": "忘記新增附件了嗎?",
"attachments_too_large_total": "附件將超過此伺服器每封郵件 {max} 的上限。",
diff --git a/locales/rn/zh.json b/locales/rn/zh.json
index cfa66f457..cd297db7e 100644
--- a/locales/rn/zh.json
+++ b/locales/rn/zh.json
@@ -322,7 +322,10 @@
"signing_out": "正在从此设备移除已同步的联系人和日历…"
},
"email_composer": {
+ "attach_bulwark_files": "Bulwark 文件",
"attach_camera": "相机",
+ "attach_gallery": "图库",
+ "attach_this_device": "此设备",
"attachment_reminder_body": "您的邮件中提到了“{keyword}”,但未附加任何文件。仍然发送吗?",
"attachment_reminder_title": "忘记添加附件了吗?",
"attachments_too_large_total": "附件将超过此服务器每封邮件 {max} 的上限。",
diff --git a/src/lib/__tests__/compose-send-queue-wiring.test.ts b/src/lib/__tests__/compose-send-queue-wiring.test.ts
index bf2f126e1..f9eeb8b57 100644
--- a/src/lib/__tests__/compose-send-queue-wiring.test.ts
+++ b/src/lib/__tests__/compose-send-queue-wiring.test.ts
@@ -8,7 +8,7 @@ const compose = fs.readFileSync(path.resolve(__dirname, '../../screens/ComposeSc
const banner = fs.readFileSync(path.resolve(__dirname, '../../components/OfflineBanner.tsx'), 'utf8');
describe('ComposeScreen offline send', () => {
- const send = compose.slice(compose.indexOf('const performSendInner'), compose.indexOf('const titleKey'));
+ const send = compose.slice(compose.indexOf('const performSendInner'), compose.indexOf('const headerTitle'));
it('queues the message instead of trying while offline', () => {
const offline = send.indexOf('if (!useNetworkStore.getState().online && queueForLater(outgoing, false)) return;');
diff --git a/src/screens/ComposeScreen.tsx b/src/screens/ComposeScreen.tsx
index bfd65d20b..995905cf3 100644
--- a/src/screens/ComposeScreen.tsx
+++ b/src/screens/ComposeScreen.tsx
@@ -11,7 +11,7 @@ import {
List, ListOrdered, Link2, Link2Off, Image as ImageIcon, Quote,
Heading1, Heading2, AlignLeft, AlignCenter, AlignRight, RemoveFormatting,
Undo2, Redo2, FileText, Clock, Check, Palette, Table, LayoutTemplate, MailCheck,
- Tag, Type, Highlighter, Trash2, Settings,
+ Tag, Type, Highlighter, Trash2, Settings, Camera, Smartphone, FolderOpen,
} from '../components/icons';
import DateTimePicker, { type DateTimePickerEvent } from '@react-native-community/datetimepicker';
import * as ImagePicker from 'expo-image-picker';
@@ -323,6 +323,7 @@ function ToolbarButton({
interface SheetOption {
label: string;
+ icon?: React.ReactNode;
destructive?: boolean;
onPress: () => void;
}
@@ -360,6 +361,7 @@ function OptionsSheet({
style={styles.scheduleRow}
onPress={() => { onClose(); afterDismiss.run(opt.onPress); }}
>
+ {opt.icon}
{opt.label}
))}
@@ -2149,17 +2151,21 @@ export default function ComposeScreen({ route, navigation }: Props) {
const [filesPickerOpen, setFilesPickerOpen] = React.useState(false);
const hasServerFiles = supportsFiles();
const attachOptions: SheetOption[] = [
- { label: t('email_composer.attach_photos', 'Photos & Videos'), onPress: () => { void pickPhotoAttachments(); } },
- { label: t('email_composer.attach_camera', 'Camera'), onPress: () => { void takePhotoAttachment(); } },
{
- // Next to "Attach from Files" a plain "Files" would read as the same.
- label: hasServerFiles
- ? t('email_composer.attach_from_device', 'Upload from this device')
- : t('email_composer.attach_files', 'Files'),
- onPress: () => { void pickFileAttachments(); },
+ // iOS calls its library Photos; "Gallery" is the Android word.
+ label: Platform.OS === 'ios'
+ ? t('email_composer.attach_photos', 'Photos & Videos')
+ : t('email_composer.attach_gallery', 'Gallery'),
+ icon: ,
+ onPress: () => { void pickPhotoAttachments(); },
},
+ { label: t('email_composer.attach_camera', 'Camera'), icon: , onPress: () => { void takePhotoAttachment(); } },
+ // "This device" and "Bulwark Files" keep the phone's files and the
+ // server's Files apart.
+ { label: t('email_composer.attach_this_device', 'This device'), icon: , onPress: () => { void pickFileAttachments(); } },
...(hasServerFiles ? [{
- label: t('email_composer.attach_from_files', 'Attach from Files'),
+ label: t('email_composer.attach_bulwark_files', 'Bulwark Files'),
+ icon: ,
onPress: () => { if (!refuseAttachAfterSwitch()) setFilesPickerOpen(true); },
}] : []),
];
@@ -2944,11 +2950,12 @@ export default function ComposeScreen({ route, navigation }: Props) {
}
};
- const titleKey =
- mode === 'forward' ? 'email_composer.forward'
- : mode === 'replyAll' ? 'email_composer.reply_all'
- : replyTo ? 'email_composer.reply'
- : 'email_composer.new_message';
+ // A new message has no title: the empty fields already say what it is.
+ const headerTitle =
+ mode === 'forward' ? t('email_composer.forward', 'Forward')
+ : mode === 'replyAll' ? t('email_composer.reply_all', 'Reply All')
+ : replyTo ? t('email_composer.reply', 'Reply')
+ : '';
const fromDisplay = React.useMemo(() => {
if (!primaryIdentity) return identityError ? t('email_composer.identity_unavailable', 'Identity unavailable') : t('common.loading', 'Loading...');
@@ -3118,7 +3125,8 @@ export default function ComposeScreen({ route, navigation }: Props) {
const composer = (
-
+ {/* The Maestro flows wait for this id: a new message has no title to wait for. */}
+
{savingDraft ? : }
-
-
- {t(titleKey, mode === 'forward' ? 'Forward' : mode === 'replyAll' ? 'Reply All' : replyTo ? 'Reply' : 'New Message')}
-
+
+ {!!headerTitle && {headerTitle}}
{!!draftStatusText && !typingInShortWindow && (
{draftStatusText}
)}
@@ -3959,6 +3975,7 @@ function makeStyles(c: ThemePalette) {
borderRadius: radius.full,
},
headerTitleWrap: { flex: 1, minWidth: 0 },
+ headerTitleWrapUntitled: { alignSelf: 'stretch', justifyContent: 'center' },
headerTitle: { ...typography.h3, color: c.text },
headerSubtitle: { ...typography.caption, color: c.textMuted, marginTop: -2 },
headerRight: { flexDirection: 'row', alignItems: 'center', gap: spacing.sm },