Skip to content

Commit

Permalink
Change to autolink using the editor instead of the outline directly.
Browse files Browse the repository at this point in the history
  • Loading branch information
vincode-io committed Dec 2, 2023
1 parent 869080f commit 90797d4
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 27 deletions.
10 changes: 10 additions & 0 deletions Shared/AppDefaults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ final class AppDefaults {
static let ownerName = "ownerName"
static let ownerEmail = "ownerEmail"
static let ownerURL = "ownerURL"
static let autoLinkingEnabled = "autoLinking"
static let lastMainWindowWasClosed = "lastMainWindowWasClosed"
static let lastMainWindowState = "lastMainWindowState"
static let openQuicklyDocumentContainerID = "openQuicklyDocumentContainerID"
Expand Down Expand Up @@ -115,6 +116,15 @@ final class AppDefaults {
}
}

var autoLinkingEnabled: Bool {
get {
return Self.bool(for: Key.autoLinkingEnabled)
}
set {
Self.setBool(for: Key.autoLinkingEnabled, newValue)
}
}

var lastMainWindowState: [AnyHashable: Any]? {
get {
return AppDefaults.store.object(forKey: Key.lastMainWindowState) as? [AnyHashable : Any]
Expand Down
10 changes: 9 additions & 1 deletion VinOutlineKit/Sources/VinOutlineKit/Outline+CloudKit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ extension Outline: VCKModel {
struct Fields {
static let syncID = "syncID"
static let title = "title"
static let autoLinkingEnabled = "autoLinkingEnabled"
static let ownerName = "ownerName"
static let ownerEmail = "ownerEmail"
static let ownerURL = "ownerURL"
Expand Down Expand Up @@ -220,7 +221,10 @@ extension Outline: VCKModel {
let serverUpdated = record[Outline.CloudKitRecord.Fields.updated] as? Date
updated = merge(client: updated, ancestor: ancestorUpdated, server: serverUpdated)

let serverOwnerName = record[Outline.CloudKitRecord.Fields.ownerName] as? String
let serverAutolinkingEnabled = record[Outline.CloudKitRecord.Fields.autoLinkingEnabled] as? Bool
autoLinkingEnabled = merge(client: autoLinkingEnabled, ancestor: ancestorAutoLinkingEnabled, server: serverAutolinkingEnabled)

let serverOwnerName = record[Outline.CloudKitRecord.Fields.ownerName] as? String
ownerName = merge(client: ownerName, ancestor: ancestorOwnerName, server: serverOwnerName)

let serverOwnerEmail = record[Outline.CloudKitRecord.Fields.ownerEmail] as? String
Expand Down Expand Up @@ -251,6 +255,7 @@ extension Outline: VCKModel {
serverDisambiguator = record[Outline.CloudKitRecord.Fields.disambiguator] as? Int
serverCreated = record[Outline.CloudKitRecord.Fields.created] as? Date
serverUpdated = record[Outline.CloudKitRecord.Fields.updated] as? Date
serverAutolinkingEnabled = record[Outline.CloudKitRecord.Fields.autoLinkingEnabled] as? Bool
serverOwnerName = record[Outline.CloudKitRecord.Fields.ownerName] as? String
serverOwnerEmail = record[Outline.CloudKitRecord.Fields.ownerEmail] as? String
serverOwnerURL = record[Outline.CloudKitRecord.Fields.ownerURL] as? String
Expand Down Expand Up @@ -296,6 +301,9 @@ extension Outline: VCKModel {
let recordUpdated = merge(client: updated, ancestor: ancestorUpdated, server: serverUpdated)
record[Outline.CloudKitRecord.Fields.updated] = recordUpdated

let recordAutoLinkingEnabled = merge(client: autoLinkingEnabled, ancestor: ancestorAutoLinkingEnabled, server: serverAutolinkingEnabled)
record[Outline.CloudKitRecord.Fields.autoLinkingEnabled] = recordAutoLinkingEnabled

let recordOwnerName = merge(client: ownerName, ancestor: ancestorOwnerName, server: serverOwnerName)
record[Outline.CloudKitRecord.Fields.ownerName] = recordOwnerName

Expand Down
55 changes: 32 additions & 23 deletions VinOutlineKit/Sources/VinOutlineKit/Outline.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public extension Notification.Name {
static let OutlineSearchWillEnd = Notification.Name(rawValue: "OutlineSearchWillEnd")
static let OutlineAddedBacklinks = Notification.Name(rawValue: "OutlineAddedBacklinks")
static let OutlineRemovedBacklinks = Notification.Name(rawValue: "OutlineRemovedBacklinks")
static let OutlineFoundReplacableLinkTitle = Notification.Name(rawValue: "OutlineFoundReplacableLinkTitle")
}

public final class Outline: RowContainer, Identifiable, Equatable, Hashable, Codable {
Expand All @@ -41,7 +42,15 @@ public final class Outline: RowContainer, Identifiable, Equatable, Hashable, Cod
case notSearching
}

public struct ReplacableLinkTitle {
public var rowID: String
public var isInNotes: Bool
public var link: URL
public var title: String
}

public struct UserInfoKeys {
public static let replacableLinkTitle = "replacableLinkTitle"
public static let searchText = "searchText"
}

Expand Down Expand Up @@ -97,6 +106,16 @@ public final class Outline: RowContainer, Identifiable, Equatable, Hashable, Cod
}
}

var ancestorAutoLinkingEnabled: Bool?
var serverAutolinkingEnabled: Bool?
public internal(set) var autoLinkingEnabled: Bool? {
willSet {
if isCloudKit && ancestorAutoLinkingEnabled == nil {
ancestorAutoLinkingEnabled = autoLinkingEnabled
}
}
}

var ancestorOwnerName: String?
var serverOwnerName: String?
public internal(set) var ownerName: String? {
Expand Down Expand Up @@ -414,6 +433,8 @@ public final class Outline: RowContainer, Identifiable, Equatable, Hashable, Cod
case created
case ancestorUpdated
case updated
case ancestorAutoLinkingEnabled
case autoLinkingEnabled
case ancestorOwnerName
case ownerName
case ancestorOwnerEmail
Expand Down Expand Up @@ -2395,6 +2416,14 @@ private extension Outline {
NotificationCenter.default.post(name: .OutlineRemovedBacklinks, object: self, userInfo: nil)
}

func outlineFoundReplacableLinkTitle(rowID: String, isInNotes: Bool, link: URL, title: String) {
let replacableLinkTitle = ReplacableLinkTitle(rowID: rowID, isInNotes: isInNotes, link: link, title: title)

var userInfo = [AnyHashable: Any]()
userInfo[UserInfoKeys.replacableLinkTitle] = replacableLinkTitle
NotificationCenter.default.post(name: .OutlineFoundReplacableLinkTitle, object: self, userInfo: userInfo)
}

func changeSearchResult(_ changeToResult: Int) {
var reloads = Set<Int>()

Expand Down Expand Up @@ -2834,38 +2863,18 @@ private extension Outline {
}

func replaceLinkTitleIfPossible(row: Row, newText: NSAttributedString?, isInNotes: Bool) {
guard let newText else { return }
guard autoLinkingEnabled ?? false, let newText else { return }

let mutableText = NSMutableAttributedString(attributedString: newText)

mutableText.enumerateAttribute(.link, in: NSRange(location: 0, length: mutableText.length)) { [weak self] (value, range, match) in
guard let url = value as? URL, let self else { return }
guard mutableText.attributedSubstring(from: range).string == url.absoluteString else { return }

incrementBeingUsedCount()

WebPageTitle.find(forURL: url) { [weak self] webPageTitle in
guard let webPageTitle, let self else { return }

mutableText.removeAttribute(.link, range: range)
mutableText.replaceCharacters(in: range, with: webPageTitle)
mutableText.addAttribute(.link, value: url, range: NSRange(location: range.location, length: webPageTitle.count))

guard let row = self.findRow(id: row.id) else { return }

if !isInNotes {
row.topic = mutableText
} else {
row.note = mutableText
}

self.decrementBeingUsedCount()
self.unload()

guard self.isBeingUsed else { return }

if let shadowTableIndex = row.shadowTableIndex {
self.outlineElementsDidChange(OutlineElementChanges(section: self.adjustedRowsSection, reloads: Set([shadowTableIndex])))
DispatchQueue.main.async {
self.outlineFoundReplacableLinkTitle(rowID: row.id, isInNotes: isInNotes, link: url, title: webPageTitle)
}
}
}
Expand Down
33 changes: 31 additions & 2 deletions Zavala/Editor/EditorViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ class EditorViewController: UIViewController, DocumentsActivityItemsConfiguratio
NotificationCenter.default.addObserver(self, selector: #selector(outlineSearchWillEnd(_:)), name: .OutlineSearchWillEnd, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(outlineAddedBacklinks(_:)), name: .OutlineAddedBacklinks, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(outlineRemovedBacklinks(_:)), name: .OutlineRemovedBacklinks, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(outlineFoundReplacableLinkTitle(_:)), name: .OutlineFoundReplacableLinkTitle, object: nil)

NotificationCenter.default.addObserver(self, selector: #selector(didUndoChange(_:)), name: .NSUndoManagerDidUndoChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(didRedoChange(_:)), name: .NSUndoManagerDidRedoChange, object: nil)
Expand Down Expand Up @@ -719,6 +720,34 @@ class EditorViewController: UIViewController, DocumentsActivityItemsConfiguratio
collectionView.deleteSections([Outline.Section.backlinks.rawValue])
}

@objc func outlineFoundReplacableLinkTitle(_ note: Notification) {
guard note.object as? Outline == outline,
let replacableLinkTitle = note.userInfo?[Outline.UserInfoKeys.replacableLinkTitle] as? Outline.ReplacableLinkTitle,
let row = outline!.findRow(id: replacableLinkTitle.rowID),
let rowShadowTableIndex = row.shadowTableIndex,
let cell = collectionView.cellForItem(at: IndexPath(row: rowShadowTableIndex, section: adjustedRowsSection)) as? EditorRowViewCell else {
return
}

let mutableText: NSMutableAttributedString
if replacableLinkTitle.isInNotes, let note = row.note {
mutableText = NSMutableAttributedString(attributedString: note)
} else if let topic = row.topic {
mutableText = NSMutableAttributedString(attributedString: topic)
} else {
return
}

mutableText.enumerateAttribute(.link, in: NSRange(location: 0, length: mutableText.length)) { (value, range, match) in
guard mutableText.attributedSubstring(from: range).string == replacableLinkTitle.link.absoluteString else { return }
if replacableLinkTitle.isInNotes {
cell.noteTextView?.updateLink(text: replacableLinkTitle.title, link: replacableLinkTitle.link.absoluteString, range: range)
} else {
cell.topicTextView?.updateLink(text: replacableLinkTitle.title, link: replacableLinkTitle.link.absoluteString, range: range)
}
}
}

@objc func didUndoChange(_ note: Notification) {
updateUI()
}
Expand Down Expand Up @@ -1807,10 +1836,10 @@ extension EditorViewController: LinkViewControllerDelegate {

if cursorCoordinates.isInNotes {
rowCell.noteTextView?.becomeFirstResponder()
rowCell.noteTextView?.updateLinkForCurrentSelection(text: text, link: correctedLink, range: range)
rowCell.noteTextView?.updateLink(text: text, link: correctedLink, range: range)
} else {
rowCell.topicTextView?.becomeFirstResponder()
rowCell.topicTextView?.updateLinkForCurrentSelection(text: text, link: correctedLink, range: range)
rowCell.topicTextView?.updateLink(text: text, link: correctedLink, range: range)
}
}

Expand Down
2 changes: 1 addition & 1 deletion Zavala/Editor/Row/EditorRowTextView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ class EditorRowTextView: UITextView {
fatalError("scrollEditorToVisible has not been implemented")
}

func updateLinkForCurrentSelection(text: String, link: String?, range: NSRange) {
func updateLink(text: String, link: String?, range: NSRange) {
var attrs = typingAttributes
attrs.removeValue(forKey: .link)
let attrText = NSMutableAttributedString(string: text, attributes: attrs)
Expand Down

0 comments on commit 90797d4

Please sign in to comment.