Started working on history tracking
This commit is contained in:
88
App/Backend/History/BrowserHistory.swift
Normal file
88
App/Backend/History/BrowserHistory.swift
Normal file
@@ -0,0 +1,88 @@
|
||||
//
|
||||
// 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)")
|
||||
}
|
||||
}
|
||||
|
||||
public func allHistory() -> [HistoryItem] {
|
||||
let dataContext = persistentContainer.viewContext
|
||||
|
||||
let fetchRequest: NSFetchRequest<HistoryItemEntity> = HistoryItemEntity.fetchRequest()
|
||||
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()
|
||||
fetchRequest.predicate = NSPredicate(format: "host CONTAINS %@ OR title contains %@", matching, matching)
|
||||
|
||||
let entities: [HistoryItemEntity] = (try? dataContext.fetch(fetchRequest)) ?? []
|
||||
let allItems: [HistoryItem] = entities.map { HistoryItem(entity: $0) }
|
||||
|
||||
var topLevelItems: [URL: (HistoryItem, Int)] = [:]
|
||||
allItems.forEach { item in
|
||||
let topLevelURL = item.url.topLevelURL()
|
||||
var topLevelItem = topLevelItems[topLevelURL] ?? (item, 0)
|
||||
topLevelItem.0.url = topLevelURL
|
||||
topLevelItems[topLevelURL] = topLevelItem
|
||||
}
|
||||
|
||||
return topLevelItems.values.map { return $0.0 }.sorted { (item1, item2) -> Bool in
|
||||
return topLevelItems[item1.url]!.1 < topLevelItems[item2.url]!.1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension URL
|
||||
{
|
||||
public func topLevelURL() -> URL {
|
||||
if var components = URLComponents(url: self, resolvingAgainstBaseURL: false) {
|
||||
components.path = ""
|
||||
components.query = ""
|
||||
components.queryItems = []
|
||||
if let url = components.url {
|
||||
return url
|
||||
}
|
||||
}
|
||||
|
||||
return self
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="17189" systemVersion="20A2348b" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||
<entity name="HistoryItemEntity" representedClassName="HistoryItemEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="host" optional="YES" attributeType="String"/>
|
||||
<attribute name="lastVisited" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="title" optional="YES" attributeType="String"/>
|
||||
<attribute name="url" optional="YES" attributeType="URI"/>
|
||||
<attribute name="visitCount" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="HistoryItemEntity" positionX="-63" positionY="-18" width="128" height="104"/>
|
||||
</elements>
|
||||
</model>
|
||||
21
App/Backend/History/HistoryItem.swift
Normal file
21
App/Backend/History/HistoryItem.swift
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// HistoryItem.swift
|
||||
// App
|
||||
//
|
||||
// Created by James Magahern on 8/14/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct HistoryItem: Hashable
|
||||
{
|
||||
var url: URL
|
||||
var title: String
|
||||
var lastVisited: Date
|
||||
|
||||
init(entity: HistoryItemEntity) {
|
||||
self.url = entity.url ?? URL(string: "about:blank")!
|
||||
self.lastVisited = entity.lastVisited ?? Date()
|
||||
self.title = entity.title ?? ""
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user