Repository navigation
Bring Remotes to the app - #25
Merged
Merged
Conversation
Remotes takes Saved's place in the tab bar, and Saved opens from your own profile. The inbox and threads poll as the web's do, messages push staged and then pushed, and the Account screen gains the web's Remotes switch and Share pulls. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… turned up Each message is now a row of the thread's scroll view, not of one column inside it, so SwiftUI keeps a reader's place by the rows on screen. With NativePHP/mobile-ui#141 (combined/dev-null-app 6e92378), a message arriving no longer pulls someone reading back down to it, and still follows someone at the bottom. Bubbles get a set width, since a column that only hugged its bubble measured the text on one line and clipped it. HEAD only shows when something above it was read, as on the web. The thread's own path() clashed with OpensInTab's and silently stopped View profile and mention taps. And a devnull too old to send remotes on /me no longer reads as Remotes turned off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ipe to reply Remotes gets the web's two buttons at the top right, with its icons: New org (users-round) and New remote (square-pen). New remote finds a developer by name or handle and opens your conversation with them. New org takes an optional name and people, up to the web's 100 with you, and opens the new org. Someone you can't reach shows the web's reason and can't be picked. Both use the people search and org creation in nunomaduro/dev-null.sh#734. Open, Fetched and Stashed are now pages you swipe between, like the Log and Notifications. The pager's tabs are text only, so Fetched's request count goes in its label. Swiping a message sideways replies to it, as the web does on touch screens: someone else's to the right, your own to the left. The field takes focus. Any other swipe, such as a flick while scrolling, does nothing. The typing line now sits above the composer's border, as on the web, so the Push box is tighter. Stash and Pop in a thread's menu use the web's archive icons. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A long press on a message was unreliable, so it's gone. A tap now shows React and Reply beside the message, with the web's icons (smile-plus and reply), as the web shows them on hover. Reply sits nearest the bubble. The row keeps a gutter for them on every message, so they come and go without moving anything. React opens the reactions sheet, which no longer carries Reply. A double tap still toggles a heart, and a swipe still replies. Who's typing moves under the title in the nav bar. The empty typing line above the composer was part of the bar, so it hid messages before they reached the bar's border. The field has the same room above and below, so the bar sits evenly on the keyboard. The thread now pads its end for the bar alone. mobile-ui's bottom anchor adds the home indicator while the keyboard is down (NativePHP/mobile-ui#141, combined/dev-null-app b70ef42). With the keyboard up there's no longer a big gap above the bar, and a short thread no longer floats up the screen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The buttons sat in a gutter at the edge of the screen, away from short messages. Now the bubble and a slot for them share a row, so they sit right against the bubble, after someone else's and before yours. The slot keeps its width, so a long message wraps short of it either way, and nothing moves when they appear. An image-only message keeps them beside its images. Every message keeps its buttons, faded out and tucked 8 points toward the bubble. A tap fades them in and slides them into place over 180ms, and fades out the last message's. Faded out, they take no taps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brings the web's Remotes (direct messages) to the app. Remotes takes Saved's place in the tab bar, and Saved opens from your own profile.
What's in it
Remotes tab. The web's inbox: Open, Stashed, and Fetched while devnull takes requests. They're pages you swipe between, like the Log and Notifications. The pager's tabs are text only, so Fetched's request count goes in its label ("Fetched · 2"). Each row shows the partner's avatar ringed in their lane (or two of an org's people), the name and handle (or "org · N"), and the last message in the web's words ("you: …", "Ada: …" in an org, "sent an image", or the org event). On the right it shows "N ahead" in your lane, or the relative time. Your own last message wears the web's pushed or pulled glyph. Pull to refresh and paging work as on the web. The tab badge is the unread count the web's nav shows.
New remote and New org. The web's two buttons sit at the top right of the inbox, with its icons (users-round and square-pen). New remote finds a developer by name or handle and opens your conversation with them in the picker's place. New org takes an optional name and people, up to the web's 100 with you, shows them as chips you tap to take back out, and opens the new org. Someone you can't reach shows the web's reason ("doesn't follow you", "has remotes off", "the org is full (100)") and can't be picked. A term nobody matches gets the web's
fatal: nothing matches '…'.Thread. Opens on the latest message, at the bottom:
Composer. In the bottom bar, with the same room above and below the field so it sits evenly on the keyboard. "@ada is typing…" shows under the title in the nav bar rather than above the composer as on the web. A line in the bar hid messages before they reached its border.
Account. The web's Remotes switch, word for word, under Pastéis mode. Under it, Share pulls and, only while devnull offers it, who can push to you. Each saves optimistically and goes back with the web's error if devnull says no.
Profile. Someone else's profile gets the web's Remote button beside Follow when you could push to them: they follow you, or devnull takes requests. Your own profile gets a Saved button in the nav bar beside Account.
Remotes off. The tab shows the web's 404 for /remotes, word for word, with "Back to your log", since that's what the web shows.
How new messages arrive
Polling, like the web. There are no websockets yet.
#[Poll]ticks every 2 seconds and an idle thread skips every other tick.RefreshesInBackground) and are never cached. Only a thread's first page and the inbox are kept, so opening one is instant.The thread is a
scroll-anchor="bottom"scroll view with each message as its own row. This PR bumpsnativephp/mobile-uito combined/dev-null-app b70ef42 for NativePHP/mobile-ui#141. With that, a message arriving follows you if you're at the bottom and leaves you alone if you're reading back. Before, it yanked you down. The view also adds the home indicator at its end while the keyboard is down, so the thread pads its end for the composer bar alone and sits right above it with the keyboard up or down. Nothing else in the lock moved.API it needs
Each part has its own upstream PR. Until one lands, that part of the app just doesn't answer.
remoteson/meA devnull without #649 sends no
remoteson/me, and the app takes that as on, so the tab doesn't show the 404 just because the API is older.Not in this PR
Checked on a simulator
On an iPhone 17 Pro simulator (iOS 27), I ran this against a local devnull with all six API PRs merged. Two test users talked to each other: local_dev in the app, and dking on the web in a browser.
The simulator reached the local API at 127.0.0.1. A cloudflared tunnel was refused by this session's permission settings, so no tunnel was involved. UIMenu items (the thread's ⋯ menu) didn't take AXe taps, so View profile and Stash are covered by feature tests only.
Following at the bottom, then staying put while reading back:
The screenshots are on the orphan branch
remotes-screenshots, to delete after merge.Since then, against the same local API with #734 added, I checked on the simulator:
The same build is on Simon's iPhone against that API over the LAN. AXe's typing didn't reach the simulator this time, so search results, picking and swipe to reply are covered by feature tests only so far.
Known rough edges
Timezonereads the phone's, and once it lands,Display::clock()should use it the way the day labels will.Tests
Feature tests for the inbox and its pager, the thread, swipe to reply, New remote and New org, the Account section, the Profile button and the cache. All 920 pass, and Pint is clean.
🤖 Generated with Claude Code