Page Menu
Home
Musing Studio
Search
Configure Global Search
Log In
Files
F10455689
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
8 KB
Subscribers
None
View Options
diff --git a/Shared/PostList/PostCellView.swift b/Shared/PostList/PostCellView.swift
index 14fa2fc..1522141 100644
--- a/Shared/PostList/PostCellView.swift
+++ b/Shared/PostList/PostCellView.swift
@@ -1,64 +1,86 @@
import SwiftUI
struct PostCellView: View {
+ @EnvironmentObject var model: WriteFreelyModel
@ObservedObject var post: WFAPost
var collectionName: String?
static let createdDateFormat: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale.current
formatter.dateStyle = .long
formatter.timeStyle = .short
return formatter
}()
+ var titleText: String {
+ if post.title.isEmpty {
+ return model.posts.getBodyPreview(of: post)
+ }
+ return post.title
+ }
+
var body: some View {
HStack {
VStack(alignment: .leading) {
if let collectionName = collectionName {
Text(collectionName)
.font(.caption)
.foregroundColor(.secondary)
.padding(EdgeInsets(top: 3, leading: 4, bottom: 3, trailing: 4))
.overlay(RoundedRectangle(cornerRadius: 2).stroke(Color.secondary, lineWidth: 1))
}
- Text(post.title)
+ Text(titleText)
.font(.headline)
Text(post.createdDate ?? Date(), formatter: Self.createdDateFormat)
.font(.caption)
.foregroundColor(.secondary)
.padding(.top, -3)
}
Spacer()
PostStatusBadgeView(post: post)
}
.padding(5)
}
}
struct PostCell_AllPostsPreviews: PreviewProvider {
static var previews: some View {
let context = LocalStorageManager.persistentContainer.viewContext
let testPost = WFAPost(context: context)
testPost.title = "Test Post Title"
testPost.body = "Here's some cool sample body text."
testPost.createdDate = Date()
return PostCellView(post: testPost, collectionName: "My Cool Blog")
.environment(\.managedObjectContext, context)
}
}
struct PostCell_NormalPreviews: PreviewProvider {
static var previews: some View {
let context = LocalStorageManager.persistentContainer.viewContext
let testPost = WFAPost(context: context)
testPost.title = "Test Post Title"
testPost.body = "Here's some cool sample body text."
testPost.collectionAlias = "My Cool Blog"
testPost.createdDate = Date()
return PostCellView(post: testPost)
.environment(\.managedObjectContext, context)
}
}
+
+struct PostCell_NoTitlePreviews: PreviewProvider {
+ static var previews: some View {
+ let context = LocalStorageManager.persistentContainer.viewContext
+ let testPost = WFAPost(context: context)
+ testPost.title = ""
+ testPost.body = "Here's some cool sample body text."
+ testPost.collectionAlias = "My Cool Blog"
+ testPost.createdDate = Date()
+
+ return PostCellView(post: testPost)
+ .environment(\.managedObjectContext, context)
+ }
+}
diff --git a/Shared/PostList/PostListModel.swift b/Shared/PostList/PostListModel.swift
index e6464e4..98e158b 100644
--- a/Shared/PostList/PostListModel.swift
+++ b/Shared/PostList/PostListModel.swift
@@ -1,21 +1,124 @@
import SwiftUI
import CoreData
class PostListModel: ObservableObject {
func remove(_ post: WFAPost) {
LocalStorageManager.persistentContainer.viewContext.delete(post)
LocalStorageManager().saveContext()
}
func purgePublishedPosts() {
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "WFAPost")
fetchRequest.predicate = NSPredicate(format: "status != %i", 0)
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try LocalStorageManager.persistentContainer.viewContext.executeAndMergeChanges(using: deleteRequest)
} catch {
print("Error: Failed to purge cached posts.")
}
}
+
+ 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)
+ let terminatingPunctuation = ".。?"
+ let terminatingCharacters = CharacterSet(charactersIn: terminatingPunctuation).union(.newlines)
+
+ 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
+ }
+ }
+ }
+ return lede
+ }
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Jan 31, 4:44 PM (18 h, 16 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3145907
Attached To
rWFSUI WriteFreely SwiftUI
Event Timeline
Log In to Comment