Skip to content

Building macOS client with Swift - #1045

Merged
YunFy26 merged 73 commits into
DevXDojo:feature/macos-clientfrom
YunFy26:feature/macos-client
Aug 31, 2026
Merged

Building macOS client with Swift#1045
YunFy26 merged 73 commits into
DevXDojo:feature/macos-clientfrom
YunFy26:feature/macos-client

Conversation

@YunFy26

@YunFy26 YunFy26 commented Aug 30, 2026

Copy link
Copy Markdown

Description

Replaces the interface on this branch with a native macOS client. The Vue
frontend and the Wails shell are removed; frontend/ now holds a SwiftUI
application that talks to the Go backend over its existing HTTP API, and the Go
binary becomes a plain API server with no embedded web assets.

The client is built for feature parity with the interface it replaces: the same
translation catalogue, the same keyboard bindings, the same settings, and the
same wording throughout.

Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📝 Documentation update
  • ♻️ Code refactoring
  • ✅ Test addition/update

Related Issues

Addresses #303 — the request for a client written against SwiftUI. The other
half of that issue, Homebrew support, is not part of this change.

Changes Made

Client (frontend/, SwiftUI, macOS 14+, no third-party dependencies)

  • Sidebar built on NSOutlineView so dragging behaves the way source lists do,
    with folders, saved filters and per-activity badge counts
  • Article list with ordering, three row layouts, unread-only, mark all read,
    mark above/below, hide, read later, and the full context menu
  • Reading pane: rendered article or original page, reload, full-text fetch,
    translation, summary, image gallery, find in page, in-place audio and video,
    floating outline, and export to Obsidian, Notion and Zotero
  • Feed editor covering XPath scraping, IMAP newsletters with a connection test,
    per-feed proxy and refresh overrides, and tags; plus discovery, OPML import
    and export, tag management and a manage-feeds pane
  • AI chat, AI search and AI profile management
  • Settings window generated from internal/config/settings_schema.json, so all
    99 user-facing settings appear without a view being written for each
  • Keyboard shortcuts read from the stored shortcuts setting, window geometry
    remembered, statistics, update check and FreshRSS sync

Backend

  • main.go serves only /api; the server build tag and the embedded
    frontend/dist are gone, and the Wails dependency is dropped
  • The desktop OPML handler is folded into the single remaining one, so JSON
    import, XPath feeds, tags and FreshRSS-filtered export are preserved
  • HandleUpdateFeed no longer clears a stored IMAP password when the request
    carries an empty one — the feed listing strips the password before sending it,
    so every client was wiping credentials on save
  • /api/feeds/category is routed, and the free Google translation provider is
    made more reliable (both carried over from the earlier client branch)

Tooling and documentation

  • tools/settings-swift/generate.py generates the client's settings catalogue
  • Makefile, scripts, pre-commit hook and the three workflows rebuilt around the
    Swift package and the Go server; the Wails build system is removed
  • READMEs, contributor guide, agent guides and the architecture, build, testing,
    settings and code-pattern documents rewritten for what this branch builds

Screenshots

image

Testing

Test Configuration

  • OS: macOS 26.5.2 (25F84), Apple Silicon
  • MrRSS Version: 1.3.28
  • Go Version: 1.27.0
  • Swift Version: 6.2.3 (Xcode 26.2)
  • Node Version: N/A — this branch has no Node toolchain

Test Steps

  1. go test ./internal/... — 31 packages pass
  2. swift test --package-path frontend — 145 tests pass
  3. go vet ./... and gofmt — clean; swift build -c release — no warnings
  4. ./frontend/run.sh — backend starts, client connects, feeds and articles
    load, reading pane renders
  5. make build-app VERSION=1.3.28 — produces MrRSS.app and
    MrRSS-1.3.28-macos.dmg; the bundle launches, starts its own backend and
    reads ~/Library/Application Support/MrRSS/data/
  6. Every endpoint the client calls was exercised against a running backend to
    confirm its method and payload shape

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published

Additional Notes

Three defects were found by exercising the API against a running backend rather
than by reading it, and are fixed here: extracting an article's images is a GET
and was being sent as a POST, so the gallery always failed; reordering saved
filters takes the whole ordered list rather than one identifier; and paging under
the unread filter stopped early because it counted what survived the filter
rather than what the server returned.

frontend/ is deleted and recreated as the Swift package, so merging later
upstream changes to the old Vue files will report "deleted by us". Keeping them
deleted is the intended resolution, and this is noted in CLAUDE.md and
AGENTS.md.

Breaking Changes

This branch no longer builds the desktop application or the web interface.

  • frontend/ is the SwiftUI package; the Vue sources, the Wails entry point and
    the Wails build system are removed
  • The Go binary serves /api only. Anything relying on it serving the web
    interface must use the client, or a separately hosted frontend
  • The server build tag no longer exists: build with go build .
  • Releases from this branch carry MrRSS-{version}-macos.dmg alone. Windows and
    Linux builds continue to come from main
  • HandleUpdateFeed now treats an empty email_password as "leave unchanged"
    rather than "clear". A client that deliberately cleared a password this way
    must delete and recreate the feed instead

No data migration is required: the backend's storage format is unchanged.

dependabot Bot and others added 30 commits August 24, 2026 09:28
…pdates

Bumps the go-dependencies group with 3 updates: [github.com/mmcdole/gofeed](https://github.com/mmcdole/gofeed), [github.com/wailsapp/wails/v3](https://github.com/wailsapp/wails) and [modernc.org/sqlite](https://gitlab.com/cznic/sqlite).


Updates `github.com/mmcdole/gofeed` from 1.4.1 to 1.4.2
- [Release notes](https://github.com/mmcdole/gofeed/releases)
- [Commits](mmcdole/gofeed@v1.4.1...v1.4.2)

Updates `github.com/wailsapp/wails/v3` from 3.0.0-beta.8 to 3.0.0-beta.11
- [Release notes](https://github.com/wailsapp/wails/releases)
- [Commits](wailsapp/wails@v3.0.0-beta.8...v3.0.0-beta.11)

Updates `modernc.org/sqlite` from 1.56.0 to 1.57.0
- [Changelog](https://gitlab.com/cznic/sqlite/blob/master/CHANGELOG.md)
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.56.0...v1.57.0)

---
updated-dependencies:
- dependency-name: github.com/mmcdole/gofeed
  dependency-version: 1.4.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: go-dependencies
- dependency-name: github.com/wailsapp/wails/v3
  dependency-version: 3.0.0-beta.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: go-dependencies
- dependency-name: modernc.org/sqlite
  dependency-version: 1.57.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: go-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps the website-dependencies group in /website with 1 update: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).


Updates `vite` from 8.2.1 to 8.2.2
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.2.2/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 8.2.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: website-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps the frontend-dependencies group in /frontend with 4 updates: [@wailsio/runtime](https://github.com/wailsapp/wails/tree/HEAD/v3/internal/runtime/desktop/@wailsio/runtime), [cypress](https://github.com/cypress-io/cypress), [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) and [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest).


Updates `@wailsio/runtime` from 3.0.0-beta.8 to 3.0.0-beta.11
- [Release notes](https://github.com/wailsapp/wails/releases)
- [Commits](https://github.com/wailsapp/wails/commits/v3.0.0-beta.11/v3/internal/runtime/desktop/@wailsio/runtime)

Updates `cypress` from 15.20.1 to 15.21.0
- [Release notes](https://github.com/cypress-io/cypress/releases)
- [Changelog](https://github.com/cypress-io/cypress/blob/develop/CHANGELOG.md)
- [Commits](cypress-io/cypress@v15.20.1...v15.21.0)

Updates `vite` from 8.2.1 to 8.2.2
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.2.2/packages/vite)

Updates `vitest` from 4.1.10 to 4.1.11
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.11/packages/vitest)

---
updated-dependencies:
- dependency-name: "@wailsio/runtime"
  dependency-version: 3.0.0-beta.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: frontend-dependencies
- dependency-name: cypress
  dependency-version: 15.21.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: frontend-dependencies
- dependency-name: vite
  dependency-version: 8.2.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: frontend-dependencies
- dependency-name: vitest
  dependency-version: 4.1.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: frontend-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
…go-dependencies-b85dd3e563

chore(go-deps:backend)(deps): bump the go-dependencies group with 3 updates
…n/website/website-dependencies-788cdcced7

chore(npm-deps:website)(deps-dev): bump vite from 8.2.1 to 8.2.2 in /website in the website-dependencies group
…n/frontend/frontend-dependencies-74e7b409bc

chore(npm-deps:frontend)(deps-dev): bump the frontend-dependencies group in /frontend with 4 updates
…h-relevance-navigation

fix(search): explain AI results and open selected articles
…-limit-live-update

fix(settings): update AI usage limit display immediately
YunFy26 added 29 commits August 29, 2026 21:06
@YunFy26
YunFy26 merged commit 1af71ba into DevXDojo:feature/macos-client Aug 31, 2026
4 checks 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

Development

Successfully merging this pull request may close these issues.

3 participants