Files
Attractor/App/Backend/History/BrowserHistory.swift

116 lines
3.9 KiB
Swift
Raw Normal View History

2020-08-14 20:05:36 -07:00
//
// BrowserHistory.swift
// App
//
// Created by James Magahern on 8/14/20.
//
import Foundation
import CoreData
class BrowserHistory
{
static public let shared = BrowserHistory()
lazy fileprivate var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "History")
container.loadPersistentStores { description, error in
assert(error == nil)
}
return container
}()
public func didNavigate(toURL url: URL, title: String) {
let dataContext = persistentContainer.viewContext
let entity = HistoryItemEntity(context: dataContext)
entity.url = url
entity.lastVisited = Date()
entity.title = title
entity.host = url.host
do { try dataContext.save() }
catch {
let nserror = error as NSError
fatalError("Failed saving persistent entity to store: \(nserror), \(nserror.userInfo)")
}
}
2023-01-20 17:28:15 -08:00
public func allHistory(limit: Int? = nil) -> [HistoryItem] {
2020-08-14 20:05:36 -07:00
let dataContext = persistentContainer.viewContext
let fetchRequest: NSFetchRequest<HistoryItemEntity> = HistoryItemEntity.fetchRequest()
2023-01-20 17:28:15 -08:00
fetchRequest.sortDescriptors = [
// Sort by date
NSSortDescriptor(keyPath: \HistoryItemEntity.lastVisited, ascending: false)
]
if let limit {
fetchRequest.fetchLimit = limit
}
2020-08-14 20:05:36 -07:00
let entities: [HistoryItemEntity] = (try? dataContext.fetch(fetchRequest)) ?? []
return entities.map { (entity) -> HistoryItem in
HistoryItem(entity: entity)
}
}
public func visitedToplevelHistoryItems(matching: String) -> [HistoryItem] {
let dataContext = persistentContainer.viewContext
let fetchRequest: NSFetchRequest<HistoryItemEntity> = HistoryItemEntity.fetchRequest()
2023-01-20 16:20:36 -08:00
fetchRequest.predicate = NSPredicate(format: """
host CONTAINS[cd] %@
OR title CONTAINS[cd] %@
OR url ENDSWITH[cd] %@
""", matching, matching, matching)
fetchRequest.fetchLimit = 200
fetchRequest.sortDescriptors = [ NSSortDescriptor(key: "visitCount", ascending: false) ]
2020-08-14 20:05:36 -07:00
let entities: [HistoryItemEntity] = (try? dataContext.fetch(fetchRequest)) ?? []
let allItems: [HistoryItem] = entities.map { HistoryItem(entity: $0) }
var topLevelItems: [URL: (HistoryItem, Int)] = [:]
for item in allItems {
if item.url.pathComponents.count <= 2 {
var score = 1
let topLevelURL = item.url.topLevelURL()
var topLevelItem = topLevelItems[topLevelURL] ?? (item, 0)
topLevelItem.0.url = topLevelURL
if item.url.path == "/" || item.url.path == "" {
score += 10
topLevelItem.0.title = item.title
}
topLevelItem.1 += score
topLevelItems[topLevelURL] = topLevelItem
if topLevelItems.count == 20 {
break
}
2020-09-21 17:56:22 -07:00
}
2020-08-14 20:05:36 -07:00
}
return topLevelItems.values.map { return $0.0 }.sorted { (item1, item2) -> Bool in
2020-09-21 17:56:22 -07:00
return topLevelItems[item1.url]!.1 > topLevelItems[item2.url]!.1
2020-08-14 20:05:36 -07:00
}
}
}
extension URL
{
public func topLevelURL() -> URL {
if var components = URLComponents(url: self, resolvingAgainstBaseURL: false) {
2020-09-21 17:56:22 -07:00
components.query = nil
components.queryItems = nil
components.fragment = nil
2020-08-14 20:05:36 -07:00
if let url = components.url {
return url
}
}
return self
}
}