Replace Flutter app with native SwiftUI rewrite (iOS 26)

Complete ground-up rewrite in SwiftUI targeting iOS 26. Drops the Flutter/Dart
codebase entirely in favour of a lean native app with no third-party dependencies.

Features shipped:
- Bookmark list with pagination, pull-to-refresh, swipe delete/archive
- Add bookmark form + iOS share extension (zero-tap save from any app)
- Tags tab — all tags sorted by count, tap to browse filtered bookmarks
- Native search tab (Tab role: .search) with instant client-side filtering
- AI enrichment via OpenRouter (google/gemini-2.0-flash-lite-001): auto-summary
  and tag generation, semantic search, smart collections
- Settings: linkding server config, OpenRouter API key
- App Groups for credential sharing between main app and share extension
- Swift 6 strict concurrency throughout (@Observable, @MainActor)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Krishna Kumar
2026-05-21 08:33:01 -05:00
parent cd85f9c67f
commit b7ef5c2215
306 changed files with 2337 additions and 17949 deletions

112
README.md
View File

@@ -1,61 +1,69 @@
<h1 align="center">
<img src="assets/other/banner.png" />
</h1>
# Marks
<p align="center">
<b>Linkdy</b> is a <a href="https://github.com/sissbruecker/linkding" target="_blank" rel="noopener noreferrer"><b>Linkding</b></a> client created with Flutter. <a href="https://github.com/sissbruecker/linkding" target="_blank" rel="noopener noreferrer">Linkding</a> is a self hosted bookmark manager. The objective of this project is to give all it's users an application to manage the bookmarks from a mobile device.
</p>
A native iOS client for [linkding](https://github.com/sissbruecker/linkding), the self-hosted bookmark manager.
<p align="center">
<a href="https://play.google.com/store/apps/details?id=com.jgeek00.linkdy" target="_blank" rel="noopener noreferrer">
<img src="/assets/other/get_google_play.png" width="300px">
</a>
<a href="https://apps.apple.com/us/app/linkdy/id6479930976" target="_blank" rel="noopener noreferrer">
<img src="/assets/other/get-appstore.png" width="300px">
</a>
</p>
Built from scratch in SwiftUI targeting iOS 26. Replaces the previous Flutter-based app.
### Main features
<ul>
<li>List your bookmarks.</li>
<li>Open the links on an internal browser.</li>
<li>Search bookmarks.</li>
<li>Create new bookmarks.</li>
<li>Create new tags.</li>
<li>List the bookmarks associated with each tag.</li>
<li>Material You interface with dynamic theming (only Android 12+).</li>
</ul>
## Features
## Privacy policy
Check the privacy policy [here](https://pastebin.com/raw/Yiw4h6KK).
- Browse and search your bookmarks
- Swipe to delete or archive
- Add bookmarks manually
- Share to Marks from any app (share extension)
- Tag browser — see all tags sorted by count, tap to filter
- Native search tab with instant client-side filtering
- AI enrichment via OpenRouter — auto-generates summaries and tags for each bookmark
- Semantic search — rank bookmarks by relevance using AI
- Smart Collections — AI groups your bookmarks into themed collections
- Pagination — loads more as you scroll
### Development
1. Clone this repository.
2. Run ``flutter pub get`` to install all the dependencies.
3. Run the application on the desired virtual or physical device.
## Requirements
<p>
<b>State manager</b>
<br>
Linkdy uses Riverpod as the state management system. Files ended on <code>.g.dart</code> are auto generated by Riverpod's code generator and shouldn't be edited manually.
The code generator can be started by running <code>dart run build_runner watch</code>. Then, the process will start on the terminal.
</p>
<p>
<b>Translations</b>
<br>
Linkdy uses <a href="https://pub.dev/packages/slang">slang</a> to manage the translations of the application. To add a new translation, create a new file on <code>lib/i18n</code>, with the structure <code>strings_[lang_code].i18n.json</code>. When adding a new string, make sure to add the translation on all <code>.i18n.json</code> files. Then, run <code>dart run slang</code> to generate the translations.
</p>
- iOS 26+
- A running [linkding](https://github.com/sissbruecker/linkding) instance with API access
- (Optional) An [OpenRouter](https://openrouter.ai) API key for AI features
### Android signing
1. Clone ``android/key.properties.sample`` and rename it to ``key.properties``.
2. Fill the variables with the values.
3. Put your ``keystore.jks`` file inside ``android/app/``.
4. Run ``flutter build apk --release`` or ``flutter build appbundle --release`` to compile and sign the production build.
## AI Features
<br>
<br>
<br>
<br>
<br>
All AI features are optional and powered by [OpenRouter](https://openrouter.ai) using `google/gemini-2.0-flash-lite-001` — one of the cheapest available models (~$0.075/M input tokens).
##### Created by JGeek00
| Feature | What it does |
|---|---|
| Auto-enrichment | Generates a one-sentence summary and 3-5 tags for each bookmark |
| Semantic search | Ranks your bookmarks by relevance to a natural language query |
| Smart Collections | Groups up to 150 bookmarks into 3-6 themed collections |
Add your OpenRouter API key in Settings to enable these features.
## Building
Requires [xcodegen](https://github.com/yonaskolb/XcodeGen).
```bash
brew install xcodegen
xcodegen generate
open Marks.xcodeproj
```
Then build and run in Xcode. The project uses automatic signing — set your development team in `project.yml` under `DEVELOPMENT_TEAM`.
## Architecture
- **SwiftUI** with `@Observable` and `@MainActor` throughout (Swift 6 strict concurrency)
- **LinkdingAPI** — thin wrapper around the linkding REST API
- **ClaudeService** — OpenRouter client for AI enrichment, semantic search, and collections
- **BookmarksViewModel** — central state: bookmarks list, pagination, search, enrichment progress
- **App Groups** — share extension and main app share credentials via `group.com.magicive.marks`
- **UserDefaults** — AI summaries and tags cached locally by bookmark ID
## Project structure
```
Marks/
Models/ Bookmark, ServerConfig, SmartCollection
Services/ LinkdingAPI, ClaudeService
Views/ BookmarksView, TagsView, SearchView, SettingsView, …
Assets.xcassets App icon and assets
ShareExtension/ iOS share extension (zero-tap bookmark saving)
project.yml xcodegen project spec
```