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:
73
Marks/Models/Bookmark.swift
Normal file
73
Marks/Models/Bookmark.swift
Normal file
@@ -0,0 +1,73 @@
|
||||
import Foundation
|
||||
|
||||
struct Bookmark: Codable, Identifiable, Sendable, Hashable {
|
||||
let id: Int
|
||||
var url: String
|
||||
var title: String
|
||||
var description: String
|
||||
var tagNames: [String]
|
||||
var dateAdded: Date
|
||||
var dateModified: Date
|
||||
var isArchived: Bool
|
||||
var unread: Bool
|
||||
var shared: Bool
|
||||
var websiteTitle: String?
|
||||
var websiteDescription: String?
|
||||
var faviconUrl: String?
|
||||
var previewImageUrl: String?
|
||||
|
||||
// AI-enriched fields stored locally
|
||||
var aiSummary: String?
|
||||
var aiTags: [String]?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id, url, title, description, unread, shared
|
||||
case tagNames = "tag_names"
|
||||
case dateAdded = "date_added"
|
||||
case dateModified = "date_modified"
|
||||
case isArchived = "is_archived"
|
||||
case websiteTitle = "website_title"
|
||||
case websiteDescription = "website_description"
|
||||
case faviconUrl = "favicon_url"
|
||||
case previewImageUrl = "preview_image_url"
|
||||
}
|
||||
|
||||
var displayTitle: String {
|
||||
if !title.isEmpty { return title }
|
||||
if let t = websiteTitle, !t.isEmpty { return t }
|
||||
return url
|
||||
}
|
||||
|
||||
var domain: String {
|
||||
URL(string: url)?.host ?? url
|
||||
}
|
||||
}
|
||||
|
||||
struct BookmarkResponse: Codable, Sendable {
|
||||
let count: Int
|
||||
let next: String?
|
||||
let previous: String?
|
||||
let results: [Bookmark]
|
||||
}
|
||||
|
||||
struct BookmarkCreate: Codable, Sendable {
|
||||
let url: String
|
||||
let title: String
|
||||
let tagNames: [String]
|
||||
let isArchived: Bool
|
||||
let unread: Bool
|
||||
let shared: Bool
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case url, title, unread, shared
|
||||
case tagNames = "tag_names"
|
||||
case isArchived = "is_archived"
|
||||
}
|
||||
}
|
||||
|
||||
struct SmartCollection: Identifiable, Sendable {
|
||||
let id = UUID()
|
||||
let name: String
|
||||
let description: String
|
||||
let bookmarkIds: [Int]
|
||||
}
|
||||
Reference in New Issue
Block a user