pressbox-darwin

Formerly pressbox-ios; it was renamed when it gained iPad and Mac support.

Source: github.com/red-oxide/pressbox-darwin

The iPhone, iPad and Mac app for pressbox, a self-hosted feed reader whose feeds and users are declared in NixOS. It reads from your pressbox server over its HTTP API (/api/v1) and shares read and starred state with the other clients, such as the pressbox terminal reader.

pressbox-darwin is in its early days. Expect rough edges, and features and behavior that may change between versions.

Requirements

  • iOS 18 or later on iPhone and iPad, or macOS 15 or later on a Mac.
  • A pressbox server reachable over HTTPS. iOS only allows plain HTTP to local network addresses (the same goes for macOS); tailscale serve --bg 8470 on the server is the least work, and a reverse proxy with ACME works too.
  • To build: a Mac with Xcode 26 or later and XcodeGen.

Building

The repo holds an XcodeGen spec (project.yml) and the SwiftUI sources (Pressbox/); the Xcode project is generated, not committed. One target builds for iPhone, iPad and Mac; platform differences are #if os(macOS) blocks.

nix develop    # provides xcodegen on macOS, or: brew install xcodegen
just open      # xcodegen, then open Pressbox.xcodeproj

Set your team under Signing & Capabilities (or DEVELOPMENT_TEAM in project.yml), pick an iOS device, a simulator or My Mac, and run it. CI builds the app for the iOS simulator and for macOS on every change (.github/workflows/apple.yml); just build does the same locally (just build-ios or just build-mac for one).

Using it

On first launch, enter the server address and tap "Pair this device". The app shows a code like K7W-4QX: approve it on the server with sudo pressboxctl approve K7W-4QX, or from a device that is already paired (pressbox approve K7W-4QX). See pressbox's docs on pairing and users.

Settings also has:

  • Approve a device, for pairing other clients from your phone. Admins can approve a device for another user.
  • Require Face ID (Touch ID on Mac), which locks the app whenever it goes to the background (on Mac: when it's hidden or its window is minimized).
  • Mark as read when scrolled past, off by default: items are marked read as they scroll off the top of the list while you scroll (not in search results).
  • Unread count on app icon, kept current by background refresh (on Mac, in the Dock, reloaded every 15 minutes while the app is open).

On Mac, Settings is in the app menu (⌘,), Reload is ⌘R and Refresh Feeds on Server is ⇧⌘R, and each column's buttons are in the window toolbar.

The Server section shows the address, the signed-in user and device, and the server's version.

Podcasts

Podcast episodes (items with audio or video) show a waveform in the list, a half-filled circle once started, and a speaker while playing. Their article has Play (or "Resume from 12:34"), Video when there is one, and buttons for the chapters and transcript. Opening an episode doesn't mark it read; playing it to the end (or stopping in its last 30 seconds) does.

While an episode plays, a bar sits above the controls of every screen; tap it for the full player: artwork (the chapter's, when it has one), a scrubber, back 10 / forward 30 seconds, previous and next chapter, the speed (1× to 2×, and 0.75×, keeping the pitch), AirPlay, the chapter list and the transcript, which follows along and jumps where you tap. Audio keeps playing in the background and shows on the Lock Screen and in Control Center, whose buttons and headphones work too (on Mac, in Control Center's Now Playing and on the media keys); video plays in the player, full screen or in picture in picture.

The position is saved on the server every 15 seconds and when you pause or stop, so playback resumes where you left off here or in any other pressbox client.

Search is in the item list. Opened articles, and the content of up to 30 unread items per refresh, are saved for offline reading. The token is kept in the keychain on this device only; it is readable after the first unlock (rather than behind Face ID) so the badge can update in the background.