2020-09-10 14:10:46 +00:00
|
|
|
import SwiftUI
|
2020-09-04 20:56:14 +00:00
|
|
|
import CoreData
|
2020-07-25 11:02:11 +00:00
|
|
|
|
2020-09-08 20:17:58 +00:00
|
|
|
class PostListModel: ObservableObject {
|
2020-09-17 14:34:48 +00:00
|
|
|
func remove(_ post: WFAPost) {
|
2020-11-25 19:41:53 +00:00
|
|
|
withAnimation {
|
2021-10-08 21:15:38 +00:00
|
|
|
LocalStorageManager.standard.container.viewContext.delete(post)
|
2021-10-08 21:07:06 +00:00
|
|
|
LocalStorageManager.standard.saveContext()
|
2020-11-25 19:41:53 +00:00
|
|
|
}
|
2020-09-17 14:34:48 +00:00
|
|
|
}
|
|
|
|
|
2022-07-27 13:56:32 +00:00
|
|
|
func purgePublishedPosts() throws {
|
2020-09-04 20:56:14 +00:00
|
|
|
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "WFAPost")
|
2020-10-22 16:40:07 +00:00
|
|
|
fetchRequest.predicate = NSPredicate(format: "status != %i", 0)
|
2020-09-04 20:56:14 +00:00
|
|
|
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
|
|
|
|
|
|
|
|
do {
|
2021-10-08 21:15:38 +00:00
|
|
|
try LocalStorageManager.standard.container.viewContext.executeAndMergeChanges(using: deleteRequest)
|
2020-09-04 20:56:14 +00:00
|
|
|
} catch {
|
2022-07-27 13:56:32 +00:00
|
|
|
throw LocalStoreError.couldNotPurgePosts("cached")
|
2020-09-04 20:56:14 +00:00
|
|
|
}
|
2020-08-25 18:44:28 +00:00
|
|
|
}
|
2020-11-05 21:49:08 +00:00
|
|
|
|
|
|
|
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.
|
2020-11-06 20:48:02 +00:00
|
|
|
elidedPostBody = extractLede(from: strippedPostBody)
|
2020-11-05 21:49:08 +00:00
|
|
|
|
|
|
|
return elidedPostBody
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private extension PostListModel {
|
|
|
|
|
|
|
|
func stripMarkdown(from string: String) -> String {
|
2020-11-06 15:20:33 +00:00
|
|
|
var strippedString = string
|
|
|
|
strippedString = stripHeadingOctothorpes(from: strippedString)
|
2020-11-06 19:01:33 +00:00
|
|
|
strippedString = stripImages(from: strippedString, keepAltText: true)
|
2020-11-06 15:20:33 +00:00
|
|
|
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
|
2020-11-05 21:49:08 +00:00
|
|
|
}
|
|
|
|
|
2020-11-06 19:01:33 +00:00
|
|
|
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")
|
|
|
|
}
|
|
|
|
|
2020-11-05 21:49:08 +00:00
|
|
|
func extractLede(from string: String) -> String {
|
2020-11-06 20:48:02 +00:00
|
|
|
let truncatedString = string.prefix(80)
|
2020-11-09 19:56:03 +00:00
|
|
|
let terminatingPunctuation = ".。?"
|
|
|
|
let terminatingCharacters = CharacterSet(charactersIn: terminatingPunctuation).union(.newlines)
|
2020-11-05 21:49:08 +00:00
|
|
|
|
2020-11-09 19:56:03 +00:00
|
|
|
var lede: String = ""
|
2020-11-06 20:48:02 +00:00
|
|
|
let sentences = truncatedString.components(separatedBy: terminatingCharacters)
|
2020-11-10 20:21:21 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
2020-11-05 21:49:08 +00:00
|
|
|
}
|
|
|
|
return lede
|
|
|
|
}
|
2020-08-27 21:41:13 +00:00
|
|
|
}
|