Skip to content

Gmail inbox tabs and iOS chat list fixes - #14

Merged
IGN-Styly merged 14 commits into
t3/build-ios-appfrom
t3/fix-inbox-sync-ci
Oct 12, 2026
Merged

IGN-Styly merged 14 commits into
t3/build-ios-appfrom
t3/fix-inbox-sync-ci

Conversation

@IGN-Styly

@IGN-Styly IGN-Styly commented Oct 12, 2026 •

Copy link
Copy Markdown
Member

Stacked on #8. The protoc CI fix is already pushed to #7 and #8 directly.

Gmail Inbox matches Gmail

Gmail's IMAP INBOX holds every inbox tab, so Promotions mail (for example the World Athletics newsletters) appeared in qmsg's Inbox although Gmail's own Inbox hides it.

  • INBOX uses an explicit category:primary search. Primary can overlap Updates when Gmail disables that tab, so subtracting the other categories hid valid Primary mail. Promotions, Social, Updates and Forums are virtual mailboxes over INBOX, marked $GmailTab.
  • Tabs are found with UID SEARCH X-GM-RAW "category:…". go-imap can't send that, so a minimal IMAP exchange runs on a separate connection. It stays open and is searched again only when Inbox's state changes.
  • Mail can't be moved into a tab, or from a tab to Inbox. gmail_tabs = "false" restores the old behaviour.
  • iOS lists the tabs under Inbox and leaves them out of the Move menu.

iOS issues

Cleanup from the #7/#8 review

  • iOS marks a chat read once per message and never for the account's own. Bursts of arrivals become one mark. Each mark is a journaled action, and the server allows 5,000 per device per week.
  • Sends refused with RESOURCE_EXHAUSTED show as failed, not "maybe sent". An action result too large to journal now returns UNKNOWN, because it ran.
  • On Ctrl-C or SIGTERM the server asks providers to shut down and waits up to 5 s before killing them.
  • An account with a removed type, or a component that fails to start, is logged and skipped. Before, it kept the whole server from starting.
  • New Message falls back to the account's contacts when a server can't open chats, as on Discord.
  • Pasted HEIC images become JPEG or PNG.
  • send() reuses Attachment.kind.
  • Docs: iOS Gmail sign-in in the API guide; no personal path in the iOS README.

Testing

  • Both Go provider suites pass. Regression tests cover overlapping Gmail categories, the tab protocol, and groups with no other recipients.
  • Discord Wasm integration: 10 passed, 1 existing ignored. The fixture omits DMs and group recipients from READY and serves the full list over REST; the old code fails the new startup assertions.
  • Email Wasm integration: 3 passed. Rust fmt and clippy with warnings denied pass.
  • Live account checks: all 102 direct chats and all seven groups match Discord REST, including every member list. The newest Primary message matches Gmail's explicit Primary search.
  • Built and installed on the connected iPhone. Captured matching dark-mode startup screenshots: header/loading pixels were RGB (44,44,45)/(28,28,29), now both (28,28,29).

Startup screenshots

Before c66e3a8 / after 72a52c7, same iPhone and dark-mode loading state. Images use the owner’s file server and require Tailscale access.

Before After
Startup before Startup after

@coderabbitai

coderabbitai Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: fd5c65cd-a962-4e42-af97-66c006167f93
📥 Commits

Reviewing files that changed from the base of the PR and between 17237ba and 72a52c7.

📒 Files selected for processing (27)
  • apps/ios/Qmsg/ChannelsView.swift
  • apps/ios/Qmsg/ChatView.swift
  • apps/ios/Qmsg/Components.swift
  • apps/ios/Qmsg/ComposerTextView.swift
  • apps/ios/Qmsg/MailViews.swift
  • apps/ios/Qmsg/NewChatView.swift
  • apps/ios/Qmsg/QmsgApp.swift
  • apps/ios/QmsgKit/Sources/QmsgKit/Models/Mail.swift
  • apps/ios/QmsgKit/Sources/QmsgKit/Store/QmsgStore.swift
  • apps/ios/QmsgKit/Tests/QmsgKitTests/ModelTests.swift
  • apps/ios/README.md
  • crates/qmsg-orchestrator/APP_API.md
  • crates/qmsg-orchestrator/src/app/mod.rs
  • crates/qmsg-orchestrator/src/app/providers.rs
  • crates/qmsg-orchestrator/src/main.rs
  • crates/qmsg-orchestrator/tests/discord.rs
  • crates/qmsg-orchestrator/tests/email.rs
  • providers/discord/convert.go
  • providers/discord/fakediscord/main.go
  • providers/discord/provider.go
  • providers/discord/provider_test.go
  • providers/email/README.md
  • providers/email/mail.go
  • providers/email/net.go
  • providers/email/provider.go
  • providers/email/tabs.go
  • providers/email/tabs_test.go
 _________________________________________________________________________________________________________________
< Estimate the order of your algorithms. Get a feel for how long things are likely to take before you write code. >
 -----------------------------------------------------------------------------------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@IGN-Styly
IGN-Styly added this pull request to stack #9 October 12, 2026 23:07
IGN-Styly and others added 14 commits October 13, 2026 00:08
Gmail's IMAP INBOX holds every inbox tab, so Promotions mail such as
World Athletics newsletters showed in qmsg's Inbox although Gmail keeps
it out of its own. INBOX now lists Primary mail, and Promotions, Social,
Updates and Forums are virtual mailboxes over INBOX. go-imap can't send
X-GM-RAW, so the tab searches run on a small connection of their own,
kept open and repeated only when Inbox changes. gmail_tabs = "false"
turns this off for accounts without tabs.

The iOS app lists the tabs under Inbox and leaves them out of Move.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Plain lists pin section headers while scrolling, so Recent, Servers and
Direct Messages stuck under the title like subtitles. Show them as rows
that scroll away instead.

Fixes #12

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Direct messages came after every server and, without loaded activity,
in alphabetical order, so they were easy to miss. The Discord provider
now positions DMs by their last message, and Chats lists them before
servers in that order, with chats that have activity first.

Fixes #10

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Recent list lived only in memory, so it was empty after the app
closed. Save it in user defaults; pairing again still clears it.

Fixes #11

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
While connecting, the banner's regular material showed as a black box
over the gray canvas in dark mode.

Fixes #13

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Marking read is a journaled action, and the server keeps 5,000 per
device a week. The app marked read on every arrival while at the
bottom, after a function lookup each time. Now a message is marked once,
the account's own messages not at all, and arrivals during a mark
become one mark of the newest.

A send refused with RESOURCE_EXHAUSTED never ran, so it now shows as
failed rather than maybe sent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ctrl-C now asks managed providers to shut down and gives them five
seconds before killing them. An account whose type is gone or whose
component fails to start is logged and left stopped instead of keeping
the whole server from starting. An action result too large to journal
returns UNKNOWN, since it ran, not RESOURCE_EXHAUSTED. The API guide
also describes iOS Gmail sign-in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- New Message falls back to the account's contacts when a server can't
  open chats, as on Discord, instead of saying the account can't.
- Pasted HEIC and other uncommon images become JPEG or PNG, like
  photos from the library.
- Sending reuses Attachment.kind instead of its own MIME switch.
- The README no longer names one person's machine.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Service managers stop the server with SIGTERM, which skipped the
graceful provider shutdown that Ctrl-C gets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rows without their own background fell back to the default black in
dark mode: the account-starting row in Chats, which set nil and undid
the list's canvas, and error and Load more rows in mail folders. They
showed as black boxes while loading.

Fixes #13

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@IGN-Styly
IGN-Styly force-pushed the t3/fix-inbox-sync-ci branch from 72a52c7 to 5dcf9a6 Compare October 12, 2026 23:08
@IGN-Styly
IGN-Styly merged commit 5166cbe into main Oct 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant