Skip to content

Commit

Permalink
fix: Show tag suggestions in the share extension (#704)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbmorley authored Jul 1, 2023
1 parent 7b62dd9 commit f01755f
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 28 deletions.
25 changes: 18 additions & 7 deletions core/Sources/BookmarksCore/Common/ApplicationModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,31 @@ public class ApplicationModel: ObservableObject {
public var cache: NSCache = NSCache<NSString, SafeImage>()
public var database: Database

private var documentsUrl: URL
private var downloadManager: DownloadManager
private var updater: Updater
private var cancellables: Set<AnyCancellable> = []

public init() {
documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
try! FileManager.default.createDirectory(at: documentsUrl, withIntermediateDirectories: true, attributes: nil)

// Ensure the documents directory exists.
let fileManager = FileManager.default
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
try! fileManager.createDirectory(at: documentsURL, withIntermediateDirectories: true, attributes: nil)

// Clean up the legacy store if it exists.
let legacyStoreURL = documentsURL.appendingPathComponent("store.db")
if fileManager.fileExists(atPath: legacyStoreURL.path) {
print("Legacy store exists; cleaning up.")
try? fileManager.removeItem(at: legacyStoreURL)
}

// Create the database.
// TODO: Handle database initialisation errors #143
// https://github.com/inseven/bookmarks/issues/143
let storeURL = documentsUrl.appendingPathComponent("store.db")
print("Opening database at '\(storeURL.absoluteString)'...")
database = try! Database(path: storeURL)
imageCache = FileImageCache(path: documentsUrl.appendingPathComponent("thumbnails"))
print("Opening database at '\(Database.sharedStoreURL.absoluteString)'...")
database = try! Database(path: Database.sharedStoreURL)

imageCache = FileImageCache(path: documentsURL.appendingPathComponent("thumbnails"))
downloadManager = DownloadManager(limit: settings.maximumConcurrentThumbnailDownloads)
thumbnailManager = ThumbnailManager(imageCache: imageCache, downloadManager: downloadManager)
updater = Updater(database: database, settings: settings)
Expand Down
10 changes: 0 additions & 10 deletions core/Sources/BookmarksCore/Model/InfoContentViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,16 +105,6 @@ public class InfoContentViewModel: ObservableObject, Runnable {

}

@MainActor func suggestions(candidate: String, existing: [String], count: Int) -> [String] {
let existing = Set(existing)
return applicationModel.tagsModel.tags(prefix: candidate)
.sorted { $0.count > $1.count }
.prefix(count + existing.count)
.filter { !existing.contains($0.name) }
.prefix(count)
.map { $0.name }
}

@MainActor public func stop() {
cancellables.removeAll()
}
Expand Down
14 changes: 14 additions & 0 deletions core/Sources/BookmarksCore/Store/Database.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,20 @@ public class Database {

}

// Default store location.
// Unfortunately, when running unsigned under test, the group container creation fails so this code silently fails
// over to using the documents directory. This is pretty inelegant as we'd really want a hard failure so it's not
// possible to use the incorrect location in production but, absent a better solution, this will have to do.
public static let sharedStoreURL: URL = {
let fileManager = FileManager.default
let identifier = "group.uk.co.inseven.bookmarks"
let groupURL = fileManager.containerURL(forSecurityApplicationGroupIdentifier: identifier)
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
let directoryURL = groupURL ?? documentsURL
try? fileManager.createDirectory(atPath: directoryURL.path, withIntermediateDirectories: true)
return directoryURL.appendingPathComponent("store.db")
}()

static var migrations: [Int32:(Connection) throws -> Void] = [
1: { _ in },
2: { _ in },
Expand Down
19 changes: 11 additions & 8 deletions core/Sources/BookmarksCore/Store/TagsModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,17 @@ public class TagsModel: ObservableObject {
self.tags = []
}

@MainActor public func tags(prefix: String) -> [Database.Tag] {
@MainActor public func suggestions(candidate: String, existing: [String], count: Int) -> [String] {
let existing = Set(existing)
return tags(prefix: candidate)
.sorted { $0.count > $1.count }
.prefix(count + existing.count)
.filter { !existing.contains($0.name) }
.prefix(count)
.map { $0.name }
}

@MainActor private func tags(prefix: String) -> [Database.Tag] {
return trie.findWordsWithPrefix(prefix: prefix)
.compactMap { name in
guard let count = counts[name] else {
Expand All @@ -82,12 +92,5 @@ public class TagsModel: ObservableObject {
}
}

@MainActor public func suggestions(prefix: String, existing: [String]) -> [String] {
let currentTags = Set(existing)
let tags = Set(trie.findWordsWithPrefix(prefix: prefix))
let suggestions = Array(tags.subtracting(currentTags))
return suggestions.sorted()
}

}

7 changes: 6 additions & 1 deletion core/Sources/BookmarksCore/Views/InfoContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ import SwiftUI

public struct InfoContentView: View {

let applicationModel: ApplicationModel

@StateObject var model: InfoContentViewModel

public init(applicationModel: ApplicationModel, id: String) {
self.applicationModel = applicationModel
_model = StateObject(wrappedValue: InfoContentViewModel(applicationModel: applicationModel, id: id))
}

Expand All @@ -50,7 +53,9 @@ public struct InfoContentView: View {
}
Section {
TokenView("Add tags...", tokens: $model.tags) { candidate, existing, count in
model.suggestions(candidate: candidate, existing: existing, count: count)
applicationModel.tagsModel.suggestions(candidate: candidate,
existing: existing,
count: count)
}
}
Section {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ class ShareExtensionModel: ObservableObject, Runnable {

@MainActor private var cancellables: Set<AnyCancellable> = []

private static let database: Database = {
try! Database(path: Database.sharedStoreURL)
}()

let tagsModel: TagsModel

weak var dataSource: ShareExtensionDataSource? = nil

var pinboard: Pinboard? {
Expand All @@ -52,7 +58,8 @@ class ShareExtensionModel: ObservableObject, Runnable {
}

init() {

self.tagsModel = TagsModel(database: Self.database)
tagsModel.start()
}

@MainActor func load() {
Expand Down
4 changes: 3 additions & 1 deletion ios/Bookmarks Share Extension/Views/EditorView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import BookmarksCore

struct EditorView: View {

@EnvironmentObject var extensionModel: ShareExtensionModel

@Binding var post: Pinboard.Post

var body: some View {
Expand All @@ -34,7 +36,7 @@ struct EditorView: View {
}
Section {
TokenView("Add tags...", tokens: $post.tags) { candidate, existing, count in
return []
return extensionModel.tagsModel.suggestions(candidate: candidate, existing: existing, count: count)
}
}
if let url = post.href {
Expand Down

0 comments on commit f01755f

Please sign in to comment.