swiftui-multiplatform/Shared/PostList/PostListModel.swift

127 lines
4.7 KiB
Swift
Raw Permalink Normal View History

2020-09-10 14:10:46 +00:00
import SwiftUI
import CoreData
class PostListModel: ObservableObject {
2020-09-17 14:34:48 +00:00
func remove(_ post: WFAPost) {
withAnimation {
LocalStorageManager.standard.container.viewContext.delete(post)
LocalStorageManager.standard.saveContext()
}
2020-09-17 14:34:48 +00:00
}
func purgePublishedPosts() throws {
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "WFAPost")
fetchRequest.predicate = NSPredicate(format: "status != %i", 0)
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try LocalStorageManager.standard.container.viewContext.executeAndMergeChanges(using: deleteRequest)
} catch {
throw LocalStoreError.couldNotPurgePosts("cached")
}
}
func getBodyPreview(of post: WFAPost) -> String {
var elidedPostBody: String = ""
// Strip any markdown from the post body.
let strippedPostBody = stripMarkdown(from: post.body)
// Extract lede from post.
elidedPostBody = extractLede(from: strippedPostBody)
return elidedPostBody
}
}
private extension PostListModel {
func stripMarkdown(from string: String) -> String {
var strippedString = string
strippedString = stripHeadingOctothorpes(from: strippedString)
strippedString = stripImages(from: strippedString, keepAltText: true)
return strippedString
}
func stripHeadingOctothorpes(from string: String) -> String {
let newLines = CharacterSet.newlines
var processedComponents: [String] = []
let components = string.components(separatedBy: newLines)
for component in components {
if component.isEmpty {
continue
}
var newString = component
while newString.first == "#" {
newString.removeFirst()
}
if newString.hasPrefix(" ") {
newString.removeFirst()
}
processedComponents.append(newString)
}
let headinglessString = processedComponents.joined(separator: "\n\n")
return headinglessString
}
func stripImages(from string: String, keepAltText: Bool = false) -> String {
let pattern = #"!\[[\"]?(.*?)[\"|]?\]\(.*?\)"#
var processedComponents: [String] = []
let components = string.components(separatedBy: .newlines)
for component in components {
if component.isEmpty { continue }
var processedString: String = component
if keepAltText {
let regex = try? NSRegularExpression(pattern: pattern, options: [])
if let matches = regex?.matches(
in: component, options: [], range: NSRange(location: 0, length: component.utf16.count)
) {
for match in matches {
if let range = Range(match.range(at: 1), in: component) {
processedString = "\(component[range])"
}
}
}
} else {
let range = component.startIndex..<component.endIndex
processedString = component.replacingOccurrences(
of: pattern,
with: "",
options: .regularExpression,
range: range
)
}
if processedString.isEmpty { continue }
processedComponents.append(processedString)
}
return processedComponents.joined(separator: "\n\n")
}
func extractLede(from string: String) -> String {
let truncatedString = string.prefix(80)
2020-11-09 19:56:03 +00:00
let terminatingPunctuation = ".。?"
let terminatingCharacters = CharacterSet(charactersIn: terminatingPunctuation).union(.newlines)
2020-11-09 19:56:03 +00:00
var lede: String = ""
let sentences = truncatedString.components(separatedBy: terminatingCharacters)
if let firstSentence = (sentences.filter { !$0.isEmpty }).first {
if truncatedString.count > firstSentence.count {
if terminatingPunctuation.contains(truncatedString[firstSentence.endIndex]) {
lede = String(truncatedString[...firstSentence.endIndex])
} else {
lede = firstSentence
}
} else if truncatedString.count == firstSentence.count {
if string.count > 80 {
if let endOfStringIndex = truncatedString.lastIndex(of: " ") {
lede = truncatedString[..<endOfStringIndex] + ""
}
} else {
lede = firstSentence
2020-11-09 19:56:03 +00:00
}
}
}
return lede
}
}