GitHub - moliango/doer · GitHub
Skip to content

Repository files navigation

Doer App Icon

Doer

A native iOS client for Linux.do — UIKit + Swift, no SwiftUI in the main app.

English | 中文

GitHub iOS 15.0+ Swift 5 UIKit

Screenshots

Home Mini Program Me
Home Mini Program Me
Login Default Theme Eye-care Theme
Login Default Eye-care
Xiaohongshu Theme WeChat Theme Telegram Theme
Xiaohongshu WeChat Telegram
Default Topic Detail WeChat Topic Detail Telegram Topic Detail
Default Topic Detail WeChat Topic Detail Telegram Topic Detail

Features

  • Linux.do browsing — Latest, top, categories, tags, and search, all rendered with native UIKit.
  • Topic detail — Cooked HTML rendered as native text, images, quotes, code, polls, spoilers, oneboxes, tables, videos, and a timeline jumper.
  • Replies & reactions — Reply to topics or floors, like posts, and use Linux.do emoji / Boost.
  • Image viewer — Multi-image swipe, count, share, save, and close.
  • Account & Me — Profile, badges, bookmarks, drafts, browsing history, notifications, and private messages.
  • Auth — Web login, cookie reuse for native requests, and global Cloudflare challenge handling, plus silent session recovery for third-party platforms.
  • Appearance — Default, eye-care, Xiaohongshu, and Telegram themes, plus fonts, font size, and tab-bar layout.
  • Plugins — Mini programs, NewAPI check-in (with silent re-auth), toolbox, and a plugin dock.
  • Share & widget — Share a topic URL into Doer, plus a home-screen quick-launch widget.
  • Data management — Inspect and clear browsing data, image cache, cookies, and app storage.
  • Updates — In-app check against GitHub Releases.

Tech Stack

Component Detail
Language Swift 5
UI Framework UIKit (no SwiftUI in the main app)
Minimum Target iOS 15.0
Bundle ID com.naine.doer
Architecture MVVM-style view models + DoerObservableObject / observable view controllers
Build Tool Tuist via mise (pinned in .mise.toml)
Networking Alamofire, custom router, cookie-backed requests, DoH URLProtocol
Web Session WKWebView for login, Cloudflare verification, and session refresh
Database SQLite via GRDB
HTML Rendering Local CookedHTML package backed by SwiftSoup
Image Loading SDWebImage + SDWebImageSVGCoder
Image Viewer Lightbox plus custom multi-image preview
Persistence Keychain, cookies, local settings, and GRDB-backed models
Localization Localizable.xcstrings — en / zh-Hans / zh-Hant / zh-HK

Architecture Overview

Doer follows a thin ViewController / fat ViewModel pattern with iOS 15-compatible observation. Since the project sets SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor, all UI-adjacent code runs on the main actor by default.

ViewController (renders state)
      │  observes DoerObservableObject.didChangeNotification
      ▼
ViewModel  (owns state, calls notifyChanged())
      │
      ▼
DiscourseAPI / DiscourseRouter  (per-forum Alamofire instance)

Key layers:

  • Doer/Networking/DiscourseAPI (one instance per forum, Alamofire-based) + DiscourseRouter (all API routes as enum).
  • Doer/Core/Auth/ — Web login via WKWebView, cookie reuse for native requests, Keychain-backed credentials, and session refresh.
  • Doer/Core/Plugins/ — Plugin registry, runtime, and built-in plugins (mini programs, NewAPI check-in, toolbox).
  • Doer/Database/ — GRDB DatabasePool with versioned migrations, stores ForumInstance records.
  • Doer/Core/Settings/AppSettings (DoerObservableObject singleton) for user preferences.
  • Packages/CookedHTML/ — Local Swift package that parses Discourse-cooked HTML into BlockNode/InlineNode trees with NSAttributedString rendering support.

Topic rendering supports two paths: a WKWebView snapshot path (JS messaging extracts interactive regions) and native UIKit block renderers under Doer/Features/ForumDetail/TopicDetail/NativeContent/.

Getting Started

Prerequisites

  • Xcode 16+
  • mise for tool versions (Tuist version is pinned in .mise.toml)
  • A development team ID in .mise.local.toml (not committed) as TUIST_DEVELOPMENT_TEAM

Build

# Install tools, fetch dependencies, and generate the Xcode project
make setup

# Re-generate the project only
make generate

# Build an unsigned IPA via ci_scripts
make unsigned-ipa

# Clean generated artifacts
make clean

Then open Doer.xcworkspace (not the standalone .xcodeproj), select the Doer scheme and your development team, and run.

The generated workspace is not committed. Run make generate again after changing Project.swift.

Tests

# CookedHTML package tests
cd Packages/CookedHTML && swift test

# App unit tests: open Doer.xcworkspace and run the DoerTests scheme

Project Structure

.
├── Project.swift                 # Tuist project: Doer / DoerTests / DoerShare / DoerWidget
├── Tuist/                        # External Swift packages
├── Doer/                         # App source
│   ├── AppDelegate.swift
│   ├── SceneDelegate.swift
│   ├── Info.plist
│   ├── Localizable.xcstrings     # en / zh-Hans / zh-Hant / zh-HK
│   ├── Assets.xcassets/          # App icon, launch art, runtime images
│   ├── AppIcon.icon/             # Icon Composer asset
│   ├── Components/               # Shared feedback / empty-state views
│   ├── Resources/Fonts/          # Bundled icon font
│   ├── Core/
│   │   ├── Auth/                 # Web login, cookie store, Keychain, session refresh
│   │   ├── ImageLoading/         # Avatar and image helpers
│   │   ├── Observable/           # Observable base controllers
│   │   ├── Plugins/              # Plugin registry and built-ins
│   │   ├── Settings/             # Theme, language, fonts, tab bar, DoH
│   │   └── Update/               # GitHub release checker
│   ├── Database/                 # GRDB pool and ForumInstance records
│   ├── Features/
│   │   ├── ForumDetail/          # Home, topic, Me, notifications, search, chat
│   │   ├── ForumList/            # Multi-forum list
│   │   ├── Main/                 # Root tab container
│   │   ├── Settings/             # Appearance, reading, data, network, about
│   │   ├── Plugins/              # Mini programs, NewAPI check-in, toolbox
│   │   ├── Notion/               # Notion topic sync
│   │   └── AIModelService/       # In-app AI providers
│   └── Networking/               # DiscourseAPI + DiscourseRouter + DoH
├── Extensions/
│   ├── DoerShare/                # Share extension → doer://
│   └── DoerWidget/               # Home-screen widget
├── Packages/CookedHTML/          # Cooked HTML → native block/inline tree
├── DoerTests/                    # App unit tests
├── ci_scripts/                   # Unsigned IPA build
└── assets/                       # README icon and screenshots

Acknowledgements

Doer is a native iOS client for Linux.do. The UIKit architecture started from Dexo; several interaction details came from FluxDo. The product name and repository are independent.

Project Links

About

No description, website, or topics provided.

Resources

Stars

18 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages