Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add spotlight support for Simplenote #1140

Merged
merged 19 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
078f4c8
Added CSSearchable helpers to easily index notes from SN
charliescheer Apr 11, 2024
9132eec
Added indexing of notes when they are saved or updated by sync
charliescheer Apr 11, 2024
98affe9
Remove spot light index of notes when deleted
charliescheer Apr 11, 2024
db42b63
Open notes from spotlight search
charliescheer Apr 11, 2024
aabd303
One time Index all notes in simplenote on launch
charliescheer Apr 11, 2024
5dad3d3
Fixed warning of incompatible return type in app delegate
charliescheer Apr 11, 2024
2e6307c
Fixed issue with appstore build that was failing the CI
charliescheer Apr 11, 2024
3e9ef61
Updated release notes for PR1140 add spotlight support
charliescheer Apr 12, 2024
f144054
user searchable item activity type instead of inline constant
charliescheer Apr 15, 2024
6f7dbef
Added option to enable or disable spotlight indexing
charliescheer Apr 15, 2024
057c4b5
Put checks to user options about indexing notes in CSSearchableIndex
charliescheer Apr 15, 2024
e72f78e
Added setting to enable and disable indexing notes in spotlight
charliescheer Apr 15, 2024
e73e931
Fixed a linting error
charliescheer Apr 15, 2024
f7dacb3
PreferencesViewController: Fixes UI / Options Out o Sync Glitch
jleandroperez Apr 17, 2024
dad871a
Merge branch 'trunk' into charlie/1000/add-spotlight-support
charliescheer Apr 17, 2024
cddcbed
refactored CSSearchIndex helpers to use self instead of calling default
charliescheer Apr 17, 2024
d570f24
Refactored CSSearchable helpers to drop force unwrap
charliescheer Apr 17, 2024
2e2f0e8
Dropped indexing in spotlight migration because the option is switched
charliescheer Apr 17, 2024
fd0a4f6
Refactored handleUserActivity to unwrap the simperium key for index
charliescheer Apr 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
2.21
-----

- Added spotlight search support for notes

2.20
-----
Expand Down
12 changes: 12 additions & 0 deletions Simplenote.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -462,10 +462,14 @@
BA2C65CF26FE996A00FA84E1 /* NSButton+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA2C65CA26FE996100FA84E1 /* NSButton+Extensions.swift */; };
BA4C6D16264CA8C000B723A7 /* SignupRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4C6D15264CA8C000B723A7 /* SignupRemoteTests.swift */; };
BA4C6D18264CAAF800B723A7 /* URLRequest+Simplenote.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4C6D17264CAAF800B723A7 /* URLRequest+Simplenote.swift */; };
BA52005B2BC878F1003F1B75 /* CSSearchable+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA52005A2BC878F1003F1B75 /* CSSearchable+Helpers.swift */; };
BA52005D2BC88397003F1B75 /* NSManagedObjectContext+Simplenote.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA52005C2BC88397003F1B75 /* NSManagedObjectContext+Simplenote.swift */; };
BA553F0827065E20007737E9 /* FontSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA553F0727065E20007737E9 /* FontSettings.swift */; };
BA553F0927065E20007737E9 /* FontSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA553F0727065E20007737E9 /* FontSettings.swift */; };
BA5F020526BB57F000581E92 /* NSAlert+Simplenote.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA5F020426BB57F000581E92 /* NSAlert+Simplenote.swift */; };
BA5F020626BB57F000581E92 /* NSAlert+Simplenote.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA5F020426BB57F000581E92 /* NSAlert+Simplenote.swift */; };
BA71EC242BC88FD000F42CB1 /* CSSearchable+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA52005A2BC878F1003F1B75 /* CSSearchable+Helpers.swift */; };
BA71EC252BC88FFC00F42CB1 /* NSManagedObjectContext+Simplenote.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA52005C2BC88397003F1B75 /* NSManagedObjectContext+Simplenote.swift */; };
BA78AF6F2B5B2BBA00DCF896 /* AutomatticTracks in Frameworks */ = {isa = PBXBuildFile; productRef = BA78AF6E2B5B2BBA00DCF896 /* AutomatticTracks */; };
BA78AF712B5B2BC300DCF896 /* AutomatticTracks in Frameworks */ = {isa = PBXBuildFile; productRef = BA78AF702B5B2BC300DCF896 /* AutomatticTracks */; };
BA938CEC26ACFF4A00BE5A1D /* Remote.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA938CEB26ACFF4A00BE5A1D /* Remote.swift */; };
Expand Down Expand Up @@ -868,6 +872,8 @@
BA2C65CA26FE996100FA84E1 /* NSButton+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSButton+Extensions.swift"; sourceTree = "<group>"; };
BA4C6D15264CA8C000B723A7 /* SignupRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignupRemoteTests.swift; sourceTree = "<group>"; };
BA4C6D17264CAAF800B723A7 /* URLRequest+Simplenote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLRequest+Simplenote.swift"; sourceTree = "<group>"; };
BA52005A2BC878F1003F1B75 /* CSSearchable+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CSSearchable+Helpers.swift"; sourceTree = "<group>"; };
BA52005C2BC88397003F1B75 /* NSManagedObjectContext+Simplenote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+Simplenote.swift"; sourceTree = "<group>"; };
BA553F0727065E20007737E9 /* FontSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontSettings.swift; sourceTree = "<group>"; };
BA5F020426BB57F000581E92 /* NSAlert+Simplenote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAlert+Simplenote.swift"; sourceTree = "<group>"; };
BA938CEB26ACFF4A00BE5A1D /* Remote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Remote.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1251,6 +1257,7 @@
children = (
B5D21CB624881EF600D57A34 /* Array+Simplenote.swift */,
B57CB87D244DED2300BA7969 /* Bundle+Simplenote.swift */,
BA52005A2BC878F1003F1B75 /* CSSearchable+Helpers.swift */,
B53BF19B24ABDE7C00938C34 /* DateFormatter+Simplenote.swift */,
B5C620AA257ED4CF008359A9 /* NSAnimationContext+Simplenote.swift */,
B56FA79A2437D2E0002CB9FF /* NSAppearance+Simplenote.swift */,
Expand Down Expand Up @@ -1297,6 +1304,7 @@
BA5F020426BB57F000581E92 /* NSAlert+Simplenote.swift */,
BAFB544F26CCA7F1006E037C /* NSProgressIndicator+Simplenote.swift */,
BA2C65CA26FE996100FA84E1 /* NSButton+Extensions.swift */,
BA52005C2BC88397003F1B75 /* NSManagedObjectContext+Simplenote.swift */,
);
name = Extensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -2120,6 +2128,7 @@
BA2C65CB26FE996100FA84E1 /* NSButton+Extensions.swift in Sources */,
B58117E225B9E5D200927E0C /* AccountVerificationController.swift in Sources */,
B5009937242130F70037A431 /* UnicodeScalar+Simplenote.swift in Sources */,
BA52005B2BC878F1003F1B75 /* CSSearchable+Helpers.swift in Sources */,
B5985AD5242950B40044EDE9 /* NSColor+Simplenote.swift in Sources */,
B5C7DD3D243E1F1900BEE354 /* VersionsViewController.swift in Sources */,
B58BBD3D2523FF160025135F /* PopoverWindow.swift in Sources */,
Expand Down Expand Up @@ -2155,6 +2164,7 @@
B59EA98124AA5EFA008ABE4B /* NoteMetrics.swift in Sources */,
B5EDF338258A8F1B0066D91D /* TagListFilter.swift in Sources */,
375D293621E033D1007AB25A /* document.c in Sources */,
BA52005D2BC88397003F1B75 /* NSManagedObjectContext+Simplenote.swift in Sources */,
B5609AEC24EEE7200097777A /* SPBucket+Simplenote.swift in Sources */,
B56FA7902437C672002CB9FF /* ColorStudio.swift in Sources */,
B5177CD025EEEEFB00A8D834 /* NSWindow+Transitions.swift in Sources */,
Expand Down Expand Up @@ -2312,6 +2322,7 @@
BA2C65CF26FE996A00FA84E1 /* NSButton+Extensions.swift in Sources */,
375D294121E033D1007AB25A /* html_smartypants.c in Sources */,
B5E061782450AEDA0076111A /* ToolbarView.swift in Sources */,
BA71EC242BC88FD000F42CB1 /* CSSearchable+Helpers.swift in Sources */,
B502C1DE25BA2EB700145D6C /* AccountRemote.swift in Sources */,
F998F3EC22853C49008C2B59 /* CrashLogging.swift in Sources */,
B5919365245A7AD300A70C0C /* NSScreen+Simplenote.swift in Sources */,
Expand Down Expand Up @@ -2347,6 +2358,7 @@
B5F807CD2481982B0048CBD7 /* Note+Simplenote.swift in Sources */,
A6C1E21525E010140076ADF7 /* SPApplication.swift in Sources */,
466FFEB417CC10A800399652 /* DateTransformer.m in Sources */,
BA71EC252BC88FFC00F42CB1 /* NSManagedObjectContext+Simplenote.swift in Sources */,
B5132FA923C4B9760065DD80 /* NSTextStorage+Simplenote.swift in Sources */,
375D293721E033D1007AB25A /* document.c in Sources */,
376EE3EC202B748E00E3812E /* SPAboutTextField.swift in Sources */,
Expand Down
97 changes: 97 additions & 0 deletions Simplenote/CSSearchable+Helpers.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
//
// CSSearchableItem+Helpers.swift
// Simplenote
//
// Created by Michal Kosmowski on 25/11/2016.
// Copyright © 2016 Automattic. All rights reserved.
//

import Foundation
import CoreSpotlight
import UniformTypeIdentifiers

extension CSSearchableItemAttributeSet {

convenience init(note: Note) {
self.init(contentType: UTType.data)
note.ensurePreviewStringsAreAvailable()
title = note.titlePreview
contentDescription = note.bodyPreview
}

}

extension CSSearchableItem {

convenience init(note: Note) {
let attributeSet = CSSearchableItemAttributeSet(note: note)
self.init(uniqueIdentifier: note.simperiumKey, domainIdentifier: "notes", attributeSet: attributeSet)
}

}

extension CSSearchableIndex {
// MARK: - Index Notes
@objc
func indexSpotlightItems(in context: NSManagedObjectContext) {
guard Options.shared.indexNotesForSpotlight else {
return
}

context.perform {
if let deleted = try? context.fetchObjects(for: "Note", withPredicate: NSPredicate(format: "deleted == YES")) as? [Note] {
CSSearchableIndex.default().deleteSearchableNotes(deleted)
}

if let notes = try? context.fetchObjects(for: "Note", withPredicate: NSPredicate(format: "deleted == NO")) as? [Note] {
CSSearchableIndex.default().indexSearchableNotes(notes)
charliescheer marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

@objc func indexSearchableNote(_ note: Note) {
guard Options.shared.indexNotesForSpotlight else {
return
}

let item = CSSearchableItem(note: note)
indexSearchableItems([item]) { error in
if let error = error {
NSLog("Couldn't index note in spotlight: \(error.localizedDescription)")
}
}
}

@objc func indexSearchableNotes(_ notes: [Note]) {
guard Options.shared.indexNotesForSpotlight else {
return
}

let items = notes.map {
return CSSearchableItem(note: $0)
}

indexSearchableItems(items) { error in
if let error = error {
NSLog("Couldn't index notes in spotlight: \(error.localizedDescription)")
}
}
}

@objc func deleteSearchableNote(_ note: Note) {
deleteSearchableNotes([note])
}

@objc func deleteSearchableNotes(_ notes: [Note]) {
let ids = notes.map {
return $0.simperiumKey!
charliescheer marked this conversation as resolved.
Show resolved Hide resolved
}

deleteSearchableItems(withIdentifiers: ids) { error in
if let error = error {
NSLog("Couldn't delete notes from spotlight index: \(error.localizedDescription)")
}
}
}

}
22 changes: 22 additions & 0 deletions Simplenote/NSManagedObjectContext+Simplenote.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// NSManagedObjectContext+Simplenote.swift
// Simplenote
//
// Created by Charlie Scheer on 4/11/24.
// Copyright © 2024 Simperium. All rights reserved.
//

import Foundation
import CoreData

extension NSManagedObjectContext {
@objc(fetchObjectsForEntityName: withPredicate: error:)
func fetchObjects(for entityName: String, withPredicate predicate: NSPredicate) throws -> Array<NSFetchRequestResult> {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>()
let entityDescription = NSEntityDescription.entity(forEntityName: entityName, in: self)

fetchRequest.entity = entityDescription

return try fetch(fetchRequest)
}
}
3 changes: 3 additions & 0 deletions Simplenote/NoteEditorViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ - (void)save
[self.saveTimer invalidate];
self.saveTimer = nil;

[[CSSearchableIndex defaultSearchableIndex] indexSearchableNote:self.note];

if (editorHasFocus) {
[[NSApp keyWindow] makeFirstResponder:self.noteEditor];

Expand Down Expand Up @@ -404,6 +406,7 @@ - (IBAction)deleteAction:(id)sender
[SPTracker trackEditorNoteDeleted];
noteToDelete.deleted = YES;
[self.noteActionsDelegate editorController:self deletedNoteWithSimperiumKey:noteToDelete.simperiumKey];
[[CSSearchableIndex defaultSearchableIndex] deleteSearchableNote:noteToDelete];
}

[self save];
Expand Down
3 changes: 3 additions & 0 deletions Simplenote/NoteListViewController.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Foundation
import SimplenoteSearch
import CoreSpotlight

// MARK: - NotesControllerDelegate
//
Expand Down Expand Up @@ -811,6 +812,7 @@ extension NoteListViewController {
for note in selectedNotes {
SPTracker.trackListNoteDeleted()
note.deleted = true
CSSearchableIndex.default().deleteSearchableNote(note)
}

simperium.save()
Expand Down Expand Up @@ -865,6 +867,7 @@ extension NoteListViewController {
note.deleted = false
simperium.save()

CSSearchableIndex.default().indexSearchableNote(note)
SPTracker.trackListNoteRestored()
}
}
13 changes: 13 additions & 0 deletions Simplenote/Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,19 @@ extension Options {
NotificationCenter.default.post(name: .FontSizeDidChange, object: nil)
}
}

/// Index notes for spotlight
///
@objc
var indexNotesForSpotlight: Bool {
get {
defaults.bool(forKey: .indexNotesForSpotlight)
}

set {
defaults.set(newValue, forKey: .indexNotesForSpotlight)
}
}
}

// MARK: - Migrations
Expand Down
Loading