README

Swift Paperless

Get it on the App Store!

iOS app for Paperless-ngx

Localization status on Crowdin
App preview

Swift Paperless native iOS app for the Paperless-ngx software. Paperless-ngx is a self-hosted document management system that helps you organize your documents digitally.

This application requires a self-hosted instance to function!

TestFlight

To get the latest development version of the app, grab it on TestFlight!

Building from source

The Xcode project is generated with XcodeGen from project.yml; build settings live in Config/ as .xcconfig files. swift-paperless.xcodeproj is not committed — generate it before opening or building:

brew install xcodegen   # once
just generate           # or: xcodegen generate
open swift-paperless.xcodeproj

just build / just test-xcode regenerate the project automatically. Edit project.yml (targets, sources, dependencies) and Config/*.xcconfig (build settings) rather than the generated project, then re-run just generate.

Contact

If you have any questions or need support create an issue on GitHub or send me a message.

Maintenance

Automation lives in the scripts/ package (swpngx). Run swpngx via uv run --project scripts swpngx … from the repo root (or install the package so swpngx is on your PATH).

Device ids, simulator names, bezel PNGs, and framing geometry are defined once in screenshot_devices.toml. screenshots.toml references those ids for capture; frames.toml references the same file for framing. iPhone screenshots use Pro Max only (App Store Connect scales for smaller phones). Check alignment with:

uv run --project scripts swpngx devices check

TestFlight betas

A beta is cut entirely on CI — no commit, no tag, no local build:

just beta                      # from origin/main
just beta --ref release/v1.12  # from a release branch
just beta --dry-run            # CI builds and exports, uploads nothing

This previews the notes the build will publish, then dispatches .github/workflows/beta.yml (which you can also start straight from the Actions tab). CI asks App Store Connect for the build number, writes it into Config/Shared/Version.xcconfig for that build only, archives, signs, uploads, and — after the upload succeeds — creates the builds/<version>/<build> tag and its GitHub prerelease at the built commit. The tag is the record of what shipped, not the trigger, so it can never name a build that failed to upload.

Notes come from current_changelog.txt, which accumulates the user-facing bullets for the current marketing version. Nothing clears it at build time:

  • a build’s notes are the bullets added since the previous build tag; they become the prerelease body, which is what the in-app What’s New screen shows (just beta-notes previews them)
  • TestFlight “What to Test” is one 1.11.0 (209) section per build of the current version, newest first — the same shape as changelog.txt, scoped to the version in flight. App Store Connect caps that field at 4000 characters and a version’s notes routinely run past it, so whole builds are dropped off the oldest end until it fits and a link to the releases takes their place. A build is either there in full or not at all; only a single build whose own notes exceed the budget falls back to trimming by line. No more clearing the changelog by hand to fit
  • when the version ships, empty the file in the same commit that bumps MARKETING_VERSION with just set-version

To fix notes after the fact, edit the release body on GitHub (the copy users read) and, for TestFlight, run just set-test-notes <build>. changelog.txt is an offline copy of the per-build notes, regenerated from the releases with just changelog-archive.

What’s New decks

The paged What’s New screen for a version is written as YAML front matter at the top of its release note, docs/release_notes/v<version>.md. The docs build turns each one into whats_new/<version>.json on the site, which the app fetches; a note without a whats_new key publishes nothing.

---
whats_new:
  pages:
    - title: What's new in 1.11
      subtitle: Tags          # optional
      blocks:
        - type: card          # card, tip (adds tip buttons) or telemetry
          icon: tag           # any SF Symbol name, e.g. ladybug for a fixes card
          tint: teal          # optional: blue, indigo, orange, pink, purple, red, teal
          title: Nested tags
          text: Support for hierarchical tags.
          detail: |           # optional Markdown for "Learn more"
            Tags can now have parents. ![Tag tree](../assets/tags.png)
---

Relative links and images in detail resolve against https://swift-paperless.app/release_notes/. Check a deck before pushing with:

uv run scripts/whats_new.py build docs/release_notes site/whats_new

If a deck has a mistake, this command and the docs build both stop and name the file and field. When copying a release note into its GitHub release, leave out the front matter block: it is only for the app.

App Store screenshots

1. Capture raw simulator PNGs (config: screenshots.toml):

uv run --project scripts swpngx capture setup
# Or pin the screenshot backend:
uv run --project scripts swpngx capture setup --pngx-tag 2.19.4
# Or add random tags for UI stress testing:
uv run --project scripts swpngx capture setup --random-tags 1000
# Or add multiple random metadata types:
uv run --project scripts swpngx capture setup --random-tags 1000 --random-correspondents 500 --random-document-types 250
uv run --project scripts swpngx capture capture

Writes files like store/screenshots/en-US/iPhone_17_Pro_Max-01_documents.png (the prefix is the device id from screenshot_devices.toml). Tear down the backend with uv run --project scripts swpngx capture teardown.

2. Install device bezels from Apple Design Resources (Product Bezels). Each [[device]] in screenshot_devices.toml names a bezel_pack from bezel_packs.toml and the PNG filename to install under store/screenshots/frames/:

# Use DMGs you already downloaded (e.g. from ~/Downloads):
uv run --project scripts swpngx frames download --dmg-dir ~/Downloads

# Or let swpngx download from Apple into ~/Library/Caches/swpngx/bezels:
uv run --project scripts swpngx frames download

# Only the iPhone 17 pack, with one DMG path:
uv run --project scripts swpngx frames download --pack iphone_17 \
  --dmg-path ~/Downloads/Bezel-iPhone-17.dmg

Requires macOS (hdiutil). Apple’s DMG license prompt is accepted automatically (Y); you must comply with the Apple Design Resources license.

3. Frame screenshots for the App Store (config: frames.toml):

uv run --project scripts swpngx frame

Reads store/screenshots/<locale>/, composites device bezels and localized titles (from store/screenshots/Screenshots.xcstrings), and writes store/screenshots/framed/<locale>/*-framed.png. Device names in filenames must match device id in screenshot_devices.toml.

The framing font (Open Sans) is not in git (store/.gitignore ignores *.ttf). swpngx frame downloads it automatically from Google Fonts via fonts.toml, or you can prefetch:

uv run --project scripts swpngx fonts download

Preview locally:

uv run --project scripts swpngx preview

4. Upload metadata and framed screenshots with asc (brew install asc):

just deliver-preview    # dry run
just deliver            # metadata + screenshots
just deliver-metadata   # metadata only (What's New, description, …)

just deliver runs swpngx deliver for MARKETING_VERSION from Config/Shared/Version.xcconfig, creating that App Store version if it does not exist yet. It reads metadata from store/metadata/, sets the copyright and categories, and replaces all screenshots of each device in screenshot_devices.toml that has framed PNGs. No IPA is uploaded; TestFlight builds go through just beta separately. just deliver-preview also validates locally, then shows the changes against App Store Connect once the version exists.

store/metadata/default/ applies to every locale, including en-US, unless the locale directory overrides a file.

What’s New is edited only in store/metadata/default/release_notes.txt and applies to every locale.

Authentication uses the asc auth login credentials, or the same App Store Connect API key as TestFlight (APP_STORE_CONNECT_API_KEY_ID, APP_STORE_CONNECT_ISSUER_ID, and APP_STORE_CONNECT_KEY_FILEPATH or APP_STORE_CONNECT_KEY_CONTENT).

PNG screenshots under store/screenshots/ are gitignored; generate them locally before upload.

Panorama montage

Concatenate framed screenshots (adjust the glob for your device name):

montage store/screenshots/framed/en-US/iPhone_17_Pro_Max-0*-framed.png \
    -tile 4x1 -geometry +20+0 panorama.png

If montage fails with unable to read font `', the ImageMagick install has no configured fonts; pass one explicitly, e.g. -font /System/Library/Fonts/Supplemental/Arial.ttf.

docs/panorama.png is a symlink to the top-level panorama.png, so regenerating it updates both the README and the docs site.

Release tooling

See building releases for the shared CI pipeline and the just beta / just release commands.

评论

暂无评论