PDF-Archiver/PDF-Archiver

View on GitHub
Shared/Archive/ArchiveView.swift

Summary

Maintainability
A
0 mins
Test Coverage
//
//  ArchiveView.swift
//
//
//  Created by Julian Kahnert on 14.03.24.
//

import SwiftUI
import SwiftData

struct ArchiveView: View {
    private static let formatter: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.usesGroupingSeparator = false
        return formatter
    }()

    #warning("TODO: should we exclude the pdf content to reduce memory size here?")
    @Query(sort: \Document.date, order: .reverse) private var documents: [Document]

    @Binding var selectedDocumentId: String?
    @State private var searchText = ""
    @State private var tokens: [SearchToken] = []
    @State private var suggestedTokens: [SearchToken] = [.year(2024), .year(2023), .year(2022)]

    @State private var shoudLoadAll = false

    var body: some View {
        content
            .searchable(text: $searchText, tokens: $tokens, suggestedTokens: $suggestedTokens, placement: .toolbar, prompt: "Search your documents", token: { token in
                switch token {
                case .term(let term):
                    Label("\(term)", systemImage: "text.magnifyingglass")
                case .tag(let tag):
                    Label("\(tag)", systemImage: "tag")
                case .year(let year):
                    Label(Self.formatter.string(from: year as NSNumber) ?? "", systemImage: "calendar")
                }
            })
            .onChange(of: documents) { _, newDocuments in
                Task.detached(priority: .background) {
                    let mostUsedTags = newDocuments.flatMap(\.tags).histogram
                        .sorted { $0.value < $1.value }
                        .reversed()
                        .prefix(5)
                        .map(\.key)
                        .map { SearchToken.tag($0) }

                    let possibleYears = Set(newDocuments.map { $0.filename.prefix(4) })
                    let foundYears: [SearchToken] = possibleYears
                        .compactMap { Int($0) }
                        .sorted()
                        .reversed()
                        .prefix(5)
                        .map { .year($0) }

                    guard !Task.isCancelled else { return }
                    await MainActor.run {
                        guard !Task.isCancelled else { return }
                        self.suggestedTokens = mostUsedTags + foundYears
                    }
                }
            }
            .navigationTitle("Archive")
    }

    @ViewBuilder
    private var content: some View {
        if documents.isEmpty {
            ContentUnavailableView("Empty Archive", systemImage: "archivebox", description: Text("Start scanning and tagging your first document."))
        } else {
            ArchiveListView(selectedDocumentId: $selectedDocumentId, searchString: searchText, tokens: tokens, shoudLoadAll: $shoudLoadAll)
        }
    }
}

 #if DEBUG
 #Preview {
     NavigationStack {
         ArchiveView(selectedDocumentId: .constant("debug-document-id"))
     }
     .modelContainer(previewContainer())
 }
 #endif