Skip to content

Latest commit

 

History

164 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Less Paper

A native iOS client for paperless-ngx — built in SwiftUI, on top of The Composable Architecture.

Download on the App Store App Store version CI iOS 18.0+ Swift 6.3 Architecture: TCA Built with Tuist Tuist dashboard License: MIT TestFlight beta

The inbox, the document list, offline favorites, the search filters, and a document open for reading

Status

This is a complete rewrite of Less Paper, and it is the app on the App Store today: https://apps.apple.com/en/app/less-paper/id6464425056. It needs paperless-ngx 2.15.3 or newer — that is the release whose REST API first reached version 8, which is the oldest the app negotiates down to, and an older server is turned away with a message saying so.

Every push to main also ships a TestFlight build, and the beta is open to anyone who wants the next release early: https://testflight.apple.com/join/3CM21m1n

Features

  • Multiple servers — connect to as many paperless-ngx instances as you like and switch between them
  • Search and filter — the full filter set from the web UI, including custom-field filters, and a search field on every management list
  • Saved views — create, edit and reorder them from the app
  • Offline favorites — keep chosen documents on the device, PDF and all, and read them with no server in reach
  • Document editing — title, correspondent, document type, storage path, tags, notes and custom fields
  • Bulk edit — apply changes to a whole selection at once, including bulk delete and merge
  • Import — share sheet extension for getting documents in from anywhere on the device
  • Password-protected PDFs — unlock on import, with passwords remembered in the keychain
  • Trash — restore a document you deleted, or empty the trash for good
  • Permission-aware — controls your account has no permission to use stay hidden, and a restricted account can still add a server
  • iPad layout — the document opens in a second column beside the list, rather than pushing it aside
  • Single sign-on — sign in with an OIDC provider your server offers, through a system browser sheet
  • Advanced authentication — client certificates, custom HTTP headers, and reverse-proxy setups such as Authelia
  • Deep links — open a document straight from a lesspaper:// link
  • Diagnostics — a local error log, redacted of anything that could be a credential, that you can read and share when something goes wrong
  • Tip jar — an optional way to support the app, in Settings

Requirements

Single sign-on (OIDC)

If your server offers OpenID Connect sign-in, the app shows the same providers on its sign-in screen and runs the login through a system browser sheet. For that flow to complete, the OAuth client your paperless instance uses needs two things on the identity provider:

  • lesspaper://oidc-callback registered as a redirect URI — this is how the browser hands the login back to the app
  • a public (PKCE) code exchange allowed — like any native client, the app exchanges its authorization code with PKCE and no client secret; a strictly confidential client will reject that exchange

If the browser sheet ends on an error from the provider about the redirect URI, the callback URL above is the thing that's missing.

Building the app

Building requires Xcode 26.5; everything else is pinned with mise, which installs Tuist, SwiftLint, SwiftFormat and everything else at the exact versions CI uses.

mise install       # tools + `brew bundle` via the postinstall hook
tuist install      # resolve Swift package dependencies
tuist generate     # generate LessPaper.xcworkspace

No Tuist account is needed. The project is connected to the Tuist server for build insights and a shared binary cache, and optionalAuthentication in Tuist.swift means an unauthenticated clone simply goes without them rather than failing. Run tuist auth login to get them locally.

A local paperless-ngx to develop against

mise run docker:start   # bring up paperless-ngx
mise run docker:seed    # fill it with realistic fixture data
mise run docker:stop

Everyday tasks

mise run ci:test:unit    # run the unit tests
mise run ci:test:ui      # run the XCUITest journeys (slow)
mise run ci:lint         # SwiftLint + SwiftFormat
mise run format          # apply formatting
mise run snapshots:diff  # visual diff of changed snapshots
mise run screenshots:frame  # re-render the App Store screenshots

Architecture

The project is generated by Tuist from Project.swift, and split into modules declared in Tuist/ProjectDescriptionHelpers/Module.swift:

  • Interface / implementationApiInterface holds the models and use-case protocols; ApiImplementation holds the concrete networking. Features depend only on the interface, which is what keeps them testable.
  • Feature modules — one per domain (DocumentsFeature, TagsFeature, CustomFieldsFeature, …), each a TCA reducer plus its SwiftUI views.
  • App modulesShareApp alone, which stands in for the share extension so XCUITest can drive it without going through another app's share sheet. The per-feature harness apps this list once described are gone: UI tests drive the real app now — see Testing.
  • Support modulesComponents for shared UI and DesignTokens for the colour palette it draws from, Logging for the shareable error log, TestSupport / ApiTestSupport / UITestSupport / SnapshotSupport for the test helpers, and MarketingKit, which renders the App Store screenshots from committed captures.

Dependency injection runs through swift-dependencies, persistence through swift-sharing, and networking through Get.

Build and test runs are reported to the Tuist server, and the project's dashboard is public: https://tuist.dev/plu/less-paper. It is the quickest way to see how long CI is taking and which targets dominate a run, without digging through workflow logs.

Testing

Tests are written with Swift Testing and cover unit tests and snapshot tests, plus XCUITest journeys that drive the real app.

The API layer is tested against a live paperless-ngx container rather than mocks, so the tests catch real API drift.

UI tests live in AppUITests and drive the assembled app end to end — onboarding, server management, settings, the create/edit/delete lifecycle of each entity, custom fields, and document browsing and editing — rather than a harness app per feature. Each test creates its own paperless user, so what it makes is invisible to every other test and the lists it opens start empty. The journeys run serially and take several minutes; they are the slow part of the suite, so CI reserves them for main and for pull requests labelled UITests or TestFlight.

CI runs only the modules whose fingerprint changed, so most pull requests test a slice of the suite rather than all of it. A pull request labelled FullTests turns that off and runs everything the job covers — it does not pull in the UI tests, so pair it with UITests to run genuinely everything.

Every pull request also gets a comment reporting coverage for each module whose own tests ran, and for the files the pull request changed.

Contributing

Conventions for this codebase — comment style, TCA patterns, the confirmation-popup rule and more — live in AGENTS.md. Please read it before opening a pull request. Releasing to the App Store is a maintainer task, documented in docs/releasing.md.

License

MIT © Johannes Plunien

About

Less Paper - iOS client for Paperless-ngx

Resources

Stars

12 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Contributors

Languages