mirror of
https://github.com/bulwarkmail/native.git
synced 2026-11-01 00:07:01 +00:00
docs: tick the reader parity items
This commit is contained in:
@@ -7,7 +7,7 @@ RN has a solid single-message reader (WebView body with CSP, shrink-to-fit + pin
|
||||
|
||||
### Thread view / navigation
|
||||
|
||||
- [ ] **Thread messages other than the newest are unreachable** — `P1` — `missing`
|
||||
- [x] **Thread messages other than the newest are unreachable — fixed in d2ed27f** — `P1` — `missing`
|
||||
- What WEB does: opening a thread renders every message of the thread as expandable cards (newest + all unread auto-expanded), each with its own body, attachments, reply/forward and mark-read-on-expand (`components/email/thread-conversation-view.tsx:98-115`, `171-200`, store `fetchThreadEmails` via `Thread/get` + `Email/get` in `stores/email-store.ts:3574-3640`, `lib/jmap/client.ts:2763-2800`).
|
||||
- What RN does: the list collapses same-thread rows to the newest message with a count badge (`src/screens/EmailListScreen.tsx:224-238`, default `disableThreading: false` at `src/stores/settings-store.ts:266`), the row opens `EmailThreadScreen` with a single `emailId` (`App.tsx:145-151`), and the screen only ever shows that one message (`src/screens/EmailThreadScreen.tsx:113-120`, `685-840`). `getThread` exists in `src/api/email.ts:448` but is only used by a test. Older messages of a thread cannot be opened at all unless the user turns on "Disable Thread Grouping".
|
||||
- Fix hint: on open, call `getThread(threadId, ownerAccountId)` + `getFullEmails(ids)` and render a vertical list of collapsible message cards inside the pane (newest + unread expanded), reusing `EmailBodyView` per card; keep the horizontal pager for thread-to-thread navigation.
|
||||
@@ -17,12 +17,12 @@ RN has a solid single-message reader (WebView body with CSP, shrink-to-fit + pin
|
||||
- What RN does: the pager is a `FlatList` over `useEmailStore(s => s.emails)` and the initial index is `Math.max(0, emails.findIndex(id))` (`src/screens/EmailThreadScreen.tsx:128-133`, `535-572`). `UnifiedInboxScreen` keeps its own local list and never writes the store (`src/screens/UnifiedInboxScreen.tsx:35-50`, `61-84`), `ContactActivity` navigates with ids from a contact search (`src/components/contacts/ContactActivity.tsx:170-177`). In both cases the opened id is absent from `emails`, so the visible pane is `emails[0]` (a different mailbox's first message, or blank when the list is empty) while the toolbar/mark-read/delete act on `activeEmailId`.
|
||||
- Fix hint: when `route.params.emailId` is not in `emails`, render a single-item pager (`data=[{id: emailId}]`) and disable prev/next; or have the unified inbox / contact activity pass their own id list through route params.
|
||||
|
||||
- [ ] **Mark-as-read "Never" (-1) marks the message read instantly** — `P2` — `rn-only-bug`
|
||||
- [x] **Mark-as-read "Never" (-1) marks the message read instantly — fixed in d2ed27f** — `P2` — `rn-only-bug`
|
||||
- What WEB does: `-1` means never auto-mark, `0` instant, `>0` delayed (`components/email/email-viewer.tsx:1218-1238`).
|
||||
- What RN does: `ReadingSettings` offers `Never = -1` (`src/components/settings/ReadingSettings.tsx:167-173`) but the viewer does `if (markAsReadDelay > 0) {timer} else { markRead() }` (`src/screens/EmailThreadScreen.tsx:237-245`), so `-1` behaves like instant.
|
||||
- Fix hint: add `if (markAsReadDelay === -1) return;` before the branch.
|
||||
|
||||
- [ ] **Skeleton / loading parity** — `P3` — `verified` (see "Verified at parity"); no action.
|
||||
- [x] **Skeleton / loading parity — verified, no action** — `P3` — `verified` (see "Verified at parity"); no action.
|
||||
|
||||
### Body rendering & sanitisation
|
||||
|
||||
@@ -36,7 +36,7 @@ RN has a solid single-message reader (WebView body with CSP, shrink-to-fit + pin
|
||||
- What RN does: `FORBID_TAGS` includes `'style'` (and `svg`) so every stylesheet is removed before render (`src/lib/email-html.ts:16-28`, `50-68`). Class-based colours vanish: a newsletter with white text via `.hero { color:#fff }` on a `bgcolor` cell renders white-on-white (light) or, after the invert filter, black-on-black. Also `hasNativeDarkMode` is evaluated on the *stripped* HTML inside `wrapEmailHtml` (`src/lib/email-html.ts:226-229`) but on the raw HTML in the component (`src/components/EmailBodyView.tsx:612-613`), so for emails with `@media (prefers-color-scheme: dark)` the CSS inversion is applied but the DOM re-invert pass is skipped.
|
||||
- Fix hint: keep `<style>` (the WebView is an isolated document; CSP already has `style-src 'unsafe-inline'`), port `stripExternalStyleSheetCss` + `decodeCssEscapes` for the blocked case, and evaluate `hasNativeDarkMode` once on the same input.
|
||||
|
||||
- [ ] **Dark-mode inversion CSS is an older revision of WEB's** — `P2` — `bugfix-parity`
|
||||
- [x] **Dark-mode inversion CSS is an older revision of WEB's — fixed in d2ed27f** — `P2` — `bugfix-parity`
|
||||
- What WEB does (1.7.4 "Correct dark-mode background-image inversion and height clipping", 1.6.3 emoji/nested bgcolor, 1.7.7 `height:100%` wrappers): background-*image* containers are re-inverted unconditionally and their media get `filter:none`; only bgcolor/`background:` containers use the `:not(:has(media))` guard; nested guard is limited to colour containers; `[style*="height:100%"]` is neutralised; Word/Outlook HTML gets `line-height:1.15` + `MsoNormal` margins and a fallback gutter; `messageSpacing` auto/edge gutter (`components/email/email-viewer.tsx:2200-2253`, `2287-2305`, `2438-2461`).
|
||||
- What RN does: `DARK_INVERSION` applies the `:not(:has(...))` guard to background-image containers too and includes them in the nested `filter:none` rule (`src/lib/email-html.ts:167-185`), the DOM pass only re-inverts containers without media children (`src/components/EmailBodyView.tsx:72-88`); no Word/Outlook padding, no per-message light/dark toggle (WEB toolbar Sun/Moon, `email-viewer.tsx:3199-3212`, changelog 1.6.0), no `messageSpacing`.
|
||||
- Fix hint: copy the current `darkModeCSS` block and the DOM re-invert loop verbatim into `email-html.ts` / `DARK_REINVERT_SCRIPT`; add a "View in light/dark mode" entry to the More sheet that overrides `renderAsDark` for the current message.
|
||||
@@ -75,7 +75,7 @@ RN has a solid single-message reader (WebView body with CSP, shrink-to-fit + pin
|
||||
- What RN does: `wrapPlainTextEmail` hard-codes `ui-monospace, Menlo, …` (`src/lib/email-html.ts:290`); no setting (`src/stores/settings-store.ts` has no `plainTextFont`).
|
||||
- Fix hint: add the setting (Reading settings) and switch the font-family in `wrapPlainTextEmail`.
|
||||
|
||||
- [ ] **Plain-text linkifier only catches http(s)** — `P3` — `verified` (same as WEB `plainTextToSafeHtml`); no action.
|
||||
- [x] **Plain-text linkifier only catches http(s) — verified, no action** — `P3` — `verified` (same as WEB `plainTextToSafeHtml`); no action.
|
||||
|
||||
- [x] **cid images larger than 2 MB and non-image cid parts silently show a 1x1 placeholder; octet-stream cid parts (#543) unverified — fixed in 06742ef** — `P3` — `partial`
|
||||
- What WEB does: fetches every cid part as an authenticated `blob:` URL regardless of size/type; the browser sniffs `application/octet-stream` image bytes (`components/email/email-viewer.tsx:1509-1575`; changelog 1.8.1 #543).
|
||||
@@ -89,39 +89,39 @@ RN has a solid single-message reader (WebView body with CSP, shrink-to-fit + pin
|
||||
- What RN does: `EMAIL_FULL_PROPERTIES` stops at `bodyStructure, textBody, htmlBody, bodyValues, attachments, blobId, bcc, replyTo, sentAt` (`src/api/email.ts:11-15`); the `Email` type has no `headers`/`messageId` (`src/api/types.ts:65-87`).
|
||||
- Fix hint: add the four properties to `EMAIL_FULL_PROPERTIES`, extend the type, and port `parseAuthenticationResults`/`parseSpamScore`/`extractListHeaders` (`lib/email-headers.ts`) to `src/lib/email-headers.ts`.
|
||||
|
||||
- [ ] **No "Show details" panel: CC/BCC/Reply-To/sent vs received/size/MIME/Message-ID/thread id** — `P2` — `missing`
|
||||
- [x] **No "Show details" panel: CC/BCC/Reply-To/sent vs received/size/MIME/Message-ID/thread id — fixed in d2ed27f** — `P2` — `missing`
|
||||
- What WEB does: header shows To/CC/BCC (first 2 + "+N", "me" substitution), a "Show details" toggle with recipients & routing, delivery delta, identifiers/threading, message properties, mailing-list section (`components/email/email-viewer.tsx:3892-3944`, `4187-4542`).
|
||||
- What RN does: one line `to <names>` (`src/screens/EmailThreadScreen.tsx:806-809`); CC/BCC/Reply-To are fetched but never shown; date/size only (`811-817`).
|
||||
- Fix hint: add CC/BCC rows and a collapsible details block under the sender row; reuse `formatSize`.
|
||||
|
||||
- [ ] **SPF/DKIM/DMARC/spam-score chips and spoof-aware identity badge** — `P3` — `missing`
|
||||
- [x] **SPF/DKIM/DMARC/spam-score chips and spoof-aware identity badge — fixed in d2ed27f** — `P3` — `missing`
|
||||
- What WEB does: auth chips with severity-ranked SPF (HELO vs MAIL FROM, #650), DMARC policy, iprev, spam score/LLM verdict (`components/email/email-viewer.tsx:4353-4438`, `lib/email-headers.ts:13-115`); "via <identity>" / sub-address tag badge hidden when spoofed (`components/email/email-identity-badge.tsx:33-68`, changelog 1.7.3).
|
||||
- What RN does: none.
|
||||
- Fix hint: after the headers finding, render chips in the details block; port `isAuthenticationSpoofed` for the badge.
|
||||
|
||||
- [ ] **List-Unsubscribe (RFC 2369) banner** — `P2` — `missing`
|
||||
- [x] **List-Unsubscribe (RFC 2369) banner — fixed in d2ed27f** — `P2` — `missing`
|
||||
- What WEB does: parses `List-Unsubscribe` (http preferred, else mailto), confirm dialog, sends the mailto unsubscribe through the account itself, remembers dismissals per Message-ID (`components/email/unsubscribe-banner.tsx:64-106`, `components/email/email-viewer.tsx:753-773`, `2672-2680`; changelog 1.7.7).
|
||||
- What RN does: none.
|
||||
- Fix hint: port `parseUnsubscribeUrls`/`isValidUnsubscribeUrl` from `lib/validation.ts`; for mailto call `sendEmail` with the parsed fields; open http via `expo-web-browser`.
|
||||
|
||||
- [ ] **Read receipts (MDN, RFC 8098): request banner, send, "always/ask/never", `$mdnsent`** — `P2` — `missing`
|
||||
- [x] **Read receipts (MDN, RFC 8098): request banner, send, "always/ask/never", `$mdnsent` — fixed in d2ed27f** — `P2` — `missing`
|
||||
- What WEB does: detects `Disposition-Notification-To`, offers Send/Ignore (or auto-sends in "always" mode) only in received folders, builds the multipart/report with `lib/mdn.ts`, uploads → `Email/import` into Sent → `EmailSubmission/set` with explicit envelope, then sets `$mdnsent` (`components/email/email-viewer.tsx:2686-2784`, `lib/jmap/client.ts:4080-4130`, `components/email/read-receipt-banner.tsx`).
|
||||
- What RN does: none; no `readReceiptResponse` setting.
|
||||
- Fix hint: port `lib/mdn.ts` verbatim (pure string builder), reuse `uploadBytes` (`src/api/blob.ts:67`) + `importEmailBlob` (`src/api/email.ts:423`) + an `EmailSubmission/set` helper; add the setting.
|
||||
|
||||
- [x] **Reply-To shown / used — fixed in 7f956d6** — folded into the reply-recipients finding below.
|
||||
|
||||
- [ ] **Sender / recipient tap actions (popover, view/add contact, copy address)** — `P3` — `missing`
|
||||
- [x] **Sender / recipient tap actions (popover, view/add contact, copy address) — fixed in d2ed27f** — `P3` — `missing`
|
||||
- What WEB does: every address is a `RecipientPopover` (contact lookup, extra emails/phones, copy, email, view/add contact); tapping the avatar opens the contact sidebar or, on mobile, the contact page (`components/email/recipient-popover.tsx`, `components/email/email-viewer.tsx:1140-1170`, `3841-3866`).
|
||||
- What RN does: names are static `Text` (`src/screens/EmailThreadScreen.tsx:794-810`).
|
||||
- Fix hint: wrap sender/recipients in `Pressable` opening a small action sheet (copy, compose to, open `ContactDetail`/`ContactForm` prefilled).
|
||||
|
||||
- [ ] **Displayed date uses `receivedAt` and device locale, ignoring the app's time-format setting** — `P3` — `bugfix-parity`
|
||||
- [x] **Displayed date uses `receivedAt` and device locale, ignoring the app's time-format setting — fixed in d2ed27f** — `P3` — `bugfix-parity`
|
||||
- What WEB does: `emailDisplayDate` prefers `sentAt` (falls back when missing or >24 h in the future, #891) and formats with the user's `timeFormat`/locale (`lib/email-date.ts:33-45`, `components/email/email-viewer.tsx:3811`).
|
||||
- What RN does: `formatHeaderDate(email.receivedAt)` with `toLocaleDateString(undefined, …)` (`src/screens/EmailThreadScreen.tsx:39-50`, `812-816`), so imported/migrated mail shows the import date and 12/24 h ignores the setting.
|
||||
- Fix hint: port `emailDisplayDate` (already in `src/lib/date-format.ts`?—if not, 15 lines) and use `useSettingsStore(s => s.timeFormat)` + locale from `useLocaleStore`.
|
||||
|
||||
- [ ] **Tags, `$important` badge and answered/forwarded state in the header** — `P3` — `missing`
|
||||
- [x] **Tags, `$important` badge and answered/forwarded state in the header — fixed in d2ed27f** — `P3` — `missing`
|
||||
- What WEB does: tag badges (removable) under the subject, "Important" pill (`components/email/email-viewer.tsx:3789-3806`); `$answered`/`$forwarded` set after send (`components/mail/mail-app.tsx:1663-1667`).
|
||||
- What RN does: Tag sheet exists but no badges are rendered in the pane; `$answered`/`$forwarded` are never set after a reply/forward (no hit for `$answered` in `src/`).
|
||||
- Fix hint: render `keywordDefs` matches from `email.keywords` under the subject; after a successful send in `ComposeScreen` call `setEmailKeywords(originalId, {...keywords, $answered|$forwarded: true}, accountId)`.
|
||||
@@ -133,17 +133,17 @@ RN has a solid single-message reader (WebView body with CSP, shrink-to-fit + pin
|
||||
- What RN does: `parseCalendarBlob(attachment.blobId)` uses `jmapClient.accountId` (`src/components/email/CalendarInvitationBanner.tsx:54`, `src/api/calendar.ts:355-360`) even though `EmailPane` knows `jmapAccountId`; Stalwart answers `CalendarEvent/parse` with an error for a blob in another account, so invitations in group/shared mailboxes show nothing (state `error` → banner hidden).
|
||||
- Fix hint: pass `jmapAccountId` from `EmailPane` into the banner and through to `parseCalendarBlob(blobId, accountId)`.
|
||||
|
||||
- [ ] **iMIP method detection ignores the raw ICS `METHOD` and Content-Type params** — `P2` — `partial`
|
||||
- [x] **iMIP method detection ignores the raw ICS `METHOD` and Content-Type params — fixed in 8206893** — `P2` — `partial`
|
||||
- What WEB does: reads `method=` from the part/attachment/header Content-Type, then fetches the raw ICS and reads `METHOD:` (`lib/calendar-invitation.ts:319-339`, `components/email/calendar-invitation-banner.tsx:419-447`), falling back to participant heuristics; `CANCEL`, `REPLY`, `COUNTER`, `REFRESH`, `DECLINECOUNTER`, `PUBLISH`, `ADD` each get their own title/info/actions.
|
||||
- What RN does: `extractMethodFromRawIcs` exists (`src/lib/calendar-invitation.ts:103-106`) but is never called; only `inferInvitationMethod` heuristics are used (`CalendarInvitationBanner.tsx:62`), so a cancellation whose event status is not `cancelled`, or a REPLY from a single attendee, is shown as a plain invitation with RSVP buttons.
|
||||
- Fix hint: fetch the blob text (`getDownloadUrl` + `secureFetch`, as `fetchRawEmail` does) in parallel with parse and prefer `extractMethodFromRawIcs`.
|
||||
|
||||
- [ ] **Banner lacks WEB's trust assessment, actor summary, existing-event / "already in calendar" state, calendar picker, "View in calendar", collapse, sequence badge, counter-proposal review** — `P3` — `partial`
|
||||
- [ ] **Banner lacks WEB's trust assessment, actor summary, existing-event / "already in calendar" state, calendar picker, "View in calendar", collapse, sequence badge, counter-proposal review** — `P3` — `partial` — deferred: trust assessment, iTIP method and calendar picker landed in 8206893 (calendar agent); existing-event state, "View in calendar", collapse, sequence badge and counter-proposal review remain open in the calendar area
|
||||
- What WEB does: `getInvitationTrustAssessment` (sender vs organizer + auth results) warning, actor line ("X accepted"), `queryCalendarEvents({uid})` to show "already in calendar" and current RSVP, picker when >1 calendar, "View in calendar" navigation, collapsible card, `sequence` "updated" pill, apply counter proposal for organizers (`components/email/calendar-invitation-banner.tsx:392-474`, `502-553`, `657-672`, `721-752`, `802-1140`).
|
||||
- What RN does: title/date/location/video/organizer rows, Yes/Maybe/No, Add to first writable calendar (`src/components/email/CalendarInvitationBanner.tsx:83-207`); no dedupe check before offering "Add", no picker, no trust warning, no navigation to the event.
|
||||
- Fix hint: port `getInvitationTrustAssessment` (needs the headers finding for auth), look up `useCalendarStore.events` by `uid` to switch to "already in calendar"/current response, add a calendar picker sheet when `calendars.length > 1`, and a "View in calendar" button that navigates to `CalendarScreen` with the start date.
|
||||
|
||||
- [ ] **The `.ics` part stays in the attachment list while the banner is shown** — `P3` — `bugfix-parity`
|
||||
- [x] **The `.ics` part stays in the attachment list while the banner is shown — fixed in d2ed27f** — `P3` — `bugfix-parity`
|
||||
- What WEB does: hides calendar MIME parts when the banner renders (`components/email/email-viewer.tsx:1591-1600`; changelog 1.4.14).
|
||||
- What RN does: `renderAttachments` filters only inline images (`src/screens/EmailThreadScreen.tsx:713-722`).
|
||||
- Fix hint: filter `isCalendarType(att.type) || name.endsWith('.ics')` when `calendarInvitationParsingEnabled && findCalendarAttachment(email)`.
|
||||
@@ -155,32 +155,32 @@ RN has a solid single-message reader (WebView body with CSP, shrink-to-fit + pin
|
||||
- What RN does: `navigateCompose('forward')` passes only from/to/cc/subject/plain body (`src/screens/EmailThreadScreen.tsx:366-382`); the `Compose.replyTo` param has no `attachments` field (`src/navigation/types.ts:7-19`) and `ComposeScreen` never seeds `attachments` from the original (`src/screens/ComposeScreen.tsx:354`). A forwarded invoice arrives without the PDF.
|
||||
- Fix hint: add `attachments?: Attachment[]` to the route param, and in `ComposeScreen` initialise `attachments` with `{blobId,name,type,size}` entries (blobs are account-scoped so no re-upload is needed; for shared-folder messages the blob belongs to the owner account — either re-upload via `getDownloadUrl(..., ownerAccountId)` + `uploadBytes`, or block forward there).
|
||||
|
||||
- [ ] **message/rfc822 attachments: no inline unwrap, no `.eml` preview** — `P2` — `missing`
|
||||
- [x] **message/rfc822 attachments: no inline unwrap, no `.eml` preview — fixed in d2ed27f** — `P2` — `missing`
|
||||
- What WEB does: when the outer body is empty (Outlook "forward as attachment") it parses the embedded message with postal-mime and renders its body + attachments, keeping the `.eml` chip; `.eml` attachments preview like an email (`components/email/email-viewer.tsx:1433-1507`, `1625-1636`; changelog 1.7.3, 1.8.1).
|
||||
- What RN does: the message renders "(empty message)" and the `.eml` chip can only be shared.
|
||||
- Fix hint: add `postal-mime` (pure JS, works in RN with a `TextDecoder` polyfill) and mirror the unwrap effect; render the parsed HTML through `EmailBodyView`.
|
||||
|
||||
- [ ] **TNEF `winmail.dat` is not decoded** — `P3` — `missing`
|
||||
- [x] **TNEF `winmail.dat` is not decoded — fixed in d2ed27f** — `P3` — `missing`
|
||||
- What WEB does: parses winmail.dat (body + embedded attachments) and hides the container (`lib/tnef.ts`, `components/email/email-viewer.tsx:1344-1431`).
|
||||
- What RN does: shows `winmail.dat` as an opaque attachment; the real files inside are unreachable.
|
||||
- Fix hint: `lib/tnef.ts` is pure `Uint8Array` code; copy it and feed `jmapClient.fetchBlobArrayBuffer`.
|
||||
|
||||
- [ ] **Attachment chip list: no MIME-based fallback names, MDN/DSN report parts and non-inline cid images mishandled** — `P3` — `partial`
|
||||
- [x] **Attachment chip list: no MIME-based fallback names, MDN/DSN report parts and non-inline cid images mishandled — fixed in d2ed27f** — `P3` — `partial`
|
||||
- What WEB does: unnamed parts get `Document.pdf`/`Email.eml`/`Attachment.<sub>` (`components/email/email-viewer.tsx:191-225`); `message/disposition-notification` and `message/delivery-status` parts are hidden (`1604-1606`); inline hiding requires `disposition === 'inline'` (`1601-1603`).
|
||||
- What RN does: unnamed → `'attachment'` (`src/screens/EmailThreadScreen.tsx:745`); report parts are listed; any `cid` image is hidden regardless of disposition (`719-721`), so an image attached with a Content-ID but `disposition: attachment` (common from some clients) disappears from the list even when the body does not reference it.
|
||||
- Fix hint: port `getAttachmentDisplayName`, add the two report-type filters, and check `disposition === 'inline'` (or that the body actually references the cid via `extractCidRefs`).
|
||||
|
||||
- [ ] **No image thumbnails on chips, no "Download all" zip, no per-chip Preview vs Download choice** — `P3` — `missing`
|
||||
- [x] **No image thumbnails on chips, no "Download all" zip, no per-chip Preview vs Download choice — fixed in d2ed27f** — `P3` — `missing`
|
||||
- What WEB does: image chips show the actual image (≤10 MB), a "Download all" bundles into a zip named by template, hover reveals separate Download/Preview buttons (`components/email/email-viewer.tsx:2024-2102`, `2104-2161`, `3949-4085`; changelog 1.6.0, 1.7.5).
|
||||
- What RN does: single tap follows the global `mailAttachmentAction`; `jszip` is already a dependency (`package.json:36`) but unused for mail.
|
||||
- Fix hint: long-press sheet with "Open / Save / Share"; a "Download all" entry building the zip with `jszip` into `Paths.cache` then sharing.
|
||||
|
||||
- [ ] **In-app attachment preview (images, PDF, text, audio/video) is absent; iOS "Preview" is just the share sheet** — `P3` — `partial`
|
||||
- [x] **In-app attachment preview (images, PDF, text, audio/video) is absent; iOS "Preview" is just the share sheet — fixed in d2ed27f** — `P3` — `partial`
|
||||
- What WEB does: `FilePreviewModal` for images/PDF (bytes handed to pdf.js, #871)/text/markdown/audio/video/eml, script-bearing types forced to download (`components/mail/mail-app.tsx:2887-2935`, `lib/file-preview.ts:29-92`).
|
||||
- What RN does: Android hands the file to an external viewer via `ACTION_VIEW`, iOS opens the share sheet (`src/lib/email-export.ts:64-79`, `115-141`); nothing is previewed inside the app.
|
||||
- Fix hint: for images/PDF/text open a modal `WebView` on the cached `file://` (or use `expo-file-system`'s `File.uri` with a QuickLook bridge on iOS); keep the external-viewer path as fallback.
|
||||
|
||||
- [ ] **Post-export action (archive/trash after "Export .eml") missing** — `P3` — `missing`
|
||||
- [x] **Post-export action (archive/trash after "Export .eml") missing — fixed in d2ed27f** — `P3` — `missing`
|
||||
- What WEB does: `postExportAction` setting runs archive/trash after export (`components/email/email-viewer.tsx:2559-2571`).
|
||||
- What RN does: export only (`src/screens/EmailThreadScreen.tsx:632-640`).
|
||||
- Fix hint: add the setting and call `onArchive`/`onDelete` after `shareEmailEml` resolves.
|
||||
@@ -202,7 +202,7 @@ RN has a solid single-message reader (WebView body with CSP, shrink-to-fit + pin
|
||||
- What RN does: `buildInitialHtml` supports `htmlBody` (`src/lib/compose-html.ts:79-83`) but the viewer only passes `body: plainTextBody(email)` (`src/screens/EmailThreadScreen.tsx:377`), and the header uses display name only (`compose-html.ts:31-35`) rather than WEB's `Name <email>` (#482).
|
||||
- Fix hint: pass `htmlBody` (sanitized via `stripDangerousTags`, cid refs rewritten to fetched data URIs or re-attached with the same `cid`) and switch `senderName` to the `Name <email>` form.
|
||||
|
||||
- [ ] **Forward as attachment (.eml) missing** — `P3` — `missing`
|
||||
- [x] **Forward as attachment (.eml) missing — fixed in d2ed27f** — `P3` — `missing`
|
||||
- What WEB does: More menu "Forward as attachment" builds a `message/rfc822` attachment referencing the original blobId with a `{date}-{subject}.eml` name (`lib/forward-as-attachment.ts:38-58`, `components/mail/mail-app.tsx:2022-2060`; changelog 1.8.1).
|
||||
- What RN does: none.
|
||||
- Fix hint: add a More-sheet entry that opens `Compose` with `attachments: [{blobId: email.blobId, name, type: 'message/rfc822', size: email.size}]` (depends on the forward-attachments fix).
|
||||
@@ -212,17 +212,17 @@ RN has a solid single-message reader (WebView body with CSP, shrink-to-fit + pin
|
||||
- What RN does: `identities.find(i => i.email === candidate.email)` (`src/screens/ComposeScreen.tsx:431-437`).
|
||||
- Fix hint: port `resolveReplyFrom`; the override needs a From override in `sendEmail`.
|
||||
|
||||
- [ ] **Quick reply box under the message** — `P3` — `missing`
|
||||
- [x] **Quick reply box under the message — fixed in d2ed27f** — `P3` — `missing`
|
||||
- What WEB does: inline textarea with Send / "More options" (opens composer prefilled), Ctrl+Enter (`components/email/email-viewer.tsx:5066-5154`).
|
||||
- What RN does: none.
|
||||
- Fix hint: optional; a bottom input that calls `sendEmail` with `buildReplyRecipients` output and the plain-text quote.
|
||||
|
||||
- [ ] **View source: no copy-to-clipboard; whole raw message loaded into a `<Text>`** — `P3` — `partial`
|
||||
- [x] **View source: no copy-to-clipboard; whole raw message loaded into a `<Text>` — fixed in d2ed27f** — `P3` — `partial`
|
||||
- What WEB does: synthetic source from the JMAP object with a Copy button (`components/email/email-viewer.tsx:5159-5208`, `lib/email-source.ts`). RN's raw RFC 822 view is actually more faithful.
|
||||
- What RN does: fetches the full blob as text and renders it in one selectable `Text` (`src/screens/EmailSourceScreen.tsx:24-35`, `68-70`); a 30 MB message will stall the JS thread.
|
||||
- Fix hint: add `Clipboard.setStringAsync`; cap display at e.g. 1 MB with a "Share full source" fallback.
|
||||
|
||||
- [ ] **Add sender to contacts / edit contact from the viewer** — `P3` — `missing`
|
||||
- [x] **Add sender to contacts / edit contact from the viewer — fixed in d2ed27f** — `P3` — `missing`
|
||||
- What WEB does: contact sidebar with "Add to contacts"/"Edit" (`components/email/email-viewer.tsx:552-568`, `5336-5368`; changelog 1.7.4).
|
||||
- What RN does: none (see popover finding).
|
||||
- Fix hint: sheet entry navigating to `ContactForm` with prefilled name/email.
|
||||
@@ -234,7 +234,7 @@ RN has a solid single-message reader (WebView body with CSP, shrink-to-fit + pin
|
||||
- What RN does: always does both (`src/components/EmailBodyView.tsx:644-653`), and `addToTrustedSendersBook` creates the book on first add (`src/stores/contacts-store.ts:308-321`), so a user who left the setting off (default `false`, `src/stores/settings-store.ts:239`) still gets a server-side "Trusted Senders" address book; the settings modal then lists only the local entries (`src/components/settings/ContentSendersSettings.tsx:19-21`, `123-144`), so book-trusted senders are invisible/unremovable there.
|
||||
- Fix hint: gate the book write on the setting (or, matching WEB 1.9.0, default the setting to on for contacts-capable accounts) and show `trustedSenderEmails` in the settings modal with remove support.
|
||||
|
||||
- [ ] **S/MIME settings screen is a dead stub** — `P3` — `rn-only-bug`
|
||||
- [x] **S/MIME settings screen is a dead stub — fixed in 3d0d440** — `P3` — `rn-only-bug`
|
||||
- What WEB does: built-in S/MIME was removed from core in 1.7.6 and lives in a privileged plugin; the viewer has no S/MIME state (`components/email/email-viewer.tsx:923-937`).
|
||||
- What RN does: `SmimeSettings` renders empty mock arrays and buttons with no handlers (`src/components/settings/SmimeSettings.tsx:32-33`, `118-121`, `163-166`); there is no verification/decryption in the viewer.
|
||||
- Fix hint: hide the screen (or show a "not available in the mobile app" note) until a crypto path exists; treat viewer-side S/MIME as N/A.
|
||||
|
||||
Reference in New Issue
Block a user