Files
linkding-ios/Marks/MarksApp.swift
Krishna Kumar b7ef5c2215 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>
2026-05-21 08:33:01 -05:00

53 lines
1.5 KiB
Swift

import SwiftUI
@main
struct MarksApp: App {
@State private var serverConfig: ServerConfig? = ServerConfig.load()
var body: some Scene {
WindowGroup {
if let config = serverConfig {
MainContainer(config: config) {
config.delete()
serverConfig = nil
}
} else {
OnboardingView { newConfig in
newConfig.save()
serverConfig = newConfig
}
}
}
}
}
// Holds the API + ViewModel so they survive re-renders
struct MainContainer: View {
let config: ServerConfig
let onDisconnect: () -> Void
@State private var viewModel: BookmarksViewModel
init(config: ServerConfig, onDisconnect: @escaping () -> Void) {
self.config = config
self.onDisconnect = onDisconnect
let api = LinkdingAPI(config: config)
let claude = ClaudeService.load()
_viewModel = State(wrappedValue: BookmarksViewModel(api: api, claude: claude))
}
var body: some View {
TabView {
Tab("Bookmarks", systemImage: "bookmark") {
BookmarksView(viewModel: viewModel, onDisconnect: onDisconnect)
}
Tab("Tags", systemImage: "tag") {
TagsView(viewModel: viewModel)
}
Tab(role: .search) {
SearchView(viewModel: viewModel)
}
}
}
}