Clean up TimelineStringUtilities, rename to TimelineStringFormatter.

This commit is contained in:
Brent Simmons 2018-12-02 10:51:32 -08:00
parent 119a854ef0
commit 9e941cfc9f
5 changed files with 118 additions and 174 deletions

View File

@ -79,7 +79,7 @@
849A97761ED9EC04007D329B /* TimelineCellAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97701ED9EC04007D329B /* TimelineCellAppearance.swift */; };
849A97771ED9EC04007D329B /* TimelineCellData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97711ED9EC04007D329B /* TimelineCellData.swift */; };
849A97781ED9EC04007D329B /* TimelineCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97721ED9EC04007D329B /* TimelineCellLayout.swift */; };
849A97791ED9EC04007D329B /* TimelineStringUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97731ED9EC04007D329B /* TimelineStringUtilities.swift */; };
849A97791ED9EC04007D329B /* TimelineStringFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97731ED9EC04007D329B /* TimelineStringFormatter.swift */; };
849A977A1ED9EC04007D329B /* TimelineTableCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97741ED9EC04007D329B /* TimelineTableCellView.swift */; };
849A977B1ED9EC04007D329B /* UnreadIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97751ED9EC04007D329B /* UnreadIndicatorView.swift */; };
849A977F1ED9EC42007D329B /* ArticleRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A977D1ED9EC42007D329B /* ArticleRenderer.swift */; };
@ -557,7 +557,7 @@
849A97701ED9EC04007D329B /* TimelineCellAppearance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimelineCellAppearance.swift; sourceTree = "<group>"; };
849A97711ED9EC04007D329B /* TimelineCellData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimelineCellData.swift; sourceTree = "<group>"; };
849A97721ED9EC04007D329B /* TimelineCellLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimelineCellLayout.swift; sourceTree = "<group>"; };
849A97731ED9EC04007D329B /* TimelineStringUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimelineStringUtilities.swift; sourceTree = "<group>"; };
849A97731ED9EC04007D329B /* TimelineStringFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimelineStringFormatter.swift; sourceTree = "<group>"; };
849A97741ED9EC04007D329B /* TimelineTableCellView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimelineTableCellView.swift; sourceTree = "<group>"; };
849A97751ED9EC04007D329B /* UnreadIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnreadIndicatorView.swift; sourceTree = "<group>"; };
849A977D1ED9EC42007D329B /* ArticleRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArticleRenderer.swift; sourceTree = "<group>"; };
@ -1013,7 +1013,7 @@
84E185B2203B74E500F69BFA /* SingleLineTextFieldSizer.swift */,
84E185C2203BB12600F69BFA /* MultilineTextFieldSizer.swift */,
849A97711ED9EC04007D329B /* TimelineCellData.swift */,
849A97731ED9EC04007D329B /* TimelineStringUtilities.swift */,
849A97731ED9EC04007D329B /* TimelineStringFormatter.swift */,
849A97751ED9EC04007D329B /* UnreadIndicatorView.swift */,
);
path = Cell;
@ -1950,7 +1950,7 @@
849A978A1ED9ECEF007D329B /* ArticleStylesManager.swift in Sources */,
519B8D332143397200FA689C /* SharingServiceDelegate.swift in Sources */,
84E8E0DB202EC49300562D8F /* TimelineViewController+ContextualMenus.swift in Sources */,
849A97791ED9EC04007D329B /* TimelineStringUtilities.swift in Sources */,
849A97791ED9EC04007D329B /* TimelineStringFormatter.swift in Sources */,
84E185C3203BB12600F69BFA /* MultilineTextFieldSizer.swift in Sources */,
8472058120142E8900AD578B /* FeedInspectorViewController.swift in Sources */,
84AD1EAA2031617300BC20B7 /* FolderPasteboardWriter.swift in Sources */,

View File

@ -180,7 +180,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
func applicationDidResignActive(_ notification: Notification) {
timelineEmptyCaches()
TimelineStringFormatter.emptyCaches()
saveState()
}

View File

@ -24,13 +24,13 @@ struct TimelineCellData {
init(article: Article, appearance: TimelineCellAppearance, showFeedName: Bool, feedName: String?, avatar: NSImage?, showAvatar: Bool, featuredImage: NSImage?) {
self.title = timelineTruncatedTitle(article)
self.text = timelineTruncatedSummary(article)
self.title = TimelineStringFormatter.truncatedTitle(article)
self.text = TimelineStringFormatter.truncatedSummary(article)
self.dateString = timelineDateString(article.logicalDatePublished)
self.dateString = TimelineStringFormatter.dateString(article.logicalDatePublished)
if let feedName = feedName {
self.feedName = timelineTruncatedFeedName(feedName)
self.feedName = TimelineStringFormatter.truncatedFeedName(feedName)
}
else {
self.feedName = ""

View File

@ -0,0 +1,109 @@
//
// TimelineStringFormatter.swift
// NetNewsWire
//
// Created by Brent Simmons on 8/31/15.
// Copyright © 2015 Ranchero Software, LLC. All rights reserved.
//
import Foundation
import Articles
import RSParser
class TimelineStringFormatter {
private static var feedNameCache = [String: String]()
private static var titleCache = [String: String]()
private static var summaryCache = [String: String]()
private static let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .none
return formatter
}()
private static let timeFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .none
formatter.timeStyle = .short
return formatter
}()
static func emptyCaches() {
feedNameCache = [String: String]()
titleCache = [String: String]()
summaryCache = [String: String]()
}
static func truncatedFeedName(_ feedName: String) -> String {
if let cachedFeedName = feedNameCache[feedName] {
return cachedFeedName
}
let maxFeedNameLength = 100
if feedName.count < maxFeedNameLength {
feedNameCache[feedName] = feedName
return feedName
}
let s = (feedName as NSString).substring(to: maxFeedNameLength)
feedNameCache[feedName] = s
return s
}
static func truncatedTitle(_ article: Article) -> String {
guard let title = article.title else {
return ""
}
if let cachedTitle = titleCache[title] {
return cachedTitle
}
var s = title.replacingOccurrences(of: "\n", with: "")
s = s.replacingOccurrences(of: "\r", with: "")
s = s.replacingOccurrences(of: "\t", with: "")
s = s.rsparser_stringByDecodingHTMLEntities()
s = s.replacingOccurrences(of: "", with: "")
s = s.rs_stringByTrimmingWhitespace()
s = s.rs_stringWithCollapsedWhitespace()
let maxLength = 1000
if s.count < maxLength {
titleCache[title] = s
return s
}
s = (s as NSString).substring(to: maxLength)
titleCache[title] = s
return s
}
static func truncatedSummary(_ article: Article) -> String {
guard let body = article.body else {
return ""
}
if let cachedBody = summaryCache[body] {
return cachedBody
}
var s = body.rsparser_stringByDecodingHTMLEntities()
s = s.rs_string(byStrippingHTML: 300)
s = s.rs_stringByTrimmingWhitespace()
s = s.rs_stringWithCollapsedWhitespace()
if s == "Comments" { // Hacker News.
s = ""
}
summaryCache[body] = s
return s
}
static func dateString(_ date: Date) -> String {
if NSCalendar.rs_dateIsToday(date) {
return timeFormatter.string(from: date)
}
return dateFormatter.string(from: date)
}
}

View File

@ -1,165 +0,0 @@
//
// TimelineStringUtilities.swift
// NetNewsWire
//
// Created by Brent Simmons on 8/31/15.
// Copyright © 2015 Ranchero Software, LLC. All rights reserved.
//
import Foundation
import Articles
import RSParser
// TODO: Dont make all this at top level.
private var truncatedFeedNameCache = [String: String]()
private let truncatedTitleCache = NSMutableDictionary()
private let normalizedTextCache = NSMutableDictionary()
private let textCache = NSMutableDictionary()
private let summaryCache = NSMutableDictionary()
func timelineEmptyCaches() {
truncatedFeedNameCache = [String: String]()
truncatedTitleCache.removeAllObjects()
normalizedTextCache.removeAllObjects()
textCache.removeAllObjects()
summaryCache.removeAllObjects()
}
func timelineTruncatedFeedName(_ feedName: String) -> String {
if let cachedFeedName = truncatedFeedNameCache[feedName] {
return cachedFeedName
}
let maxFeedNameLength = 100
if feedName.count < maxFeedNameLength {
truncatedFeedNameCache[feedName] = feedName
return feedName
}
let s = (feedName as NSString).substring(to: maxFeedNameLength)
truncatedFeedNameCache[feedName] = s
return s
}
func timelineTruncatedTitle(_ article: Article) -> String {
guard let title = article.title else {
return ""
}
if let cachedTitle = truncatedTitleCache[title] as? String {
return cachedTitle
}
var s = title.replacingOccurrences(of: "\n", with: "")
s = s.replacingOccurrences(of: "\r", with: "")
s = s.replacingOccurrences(of: "\t", with: "")
s = s.replacingOccurrences(of: "", with: "")
s = s.rs_stringByTrimmingWhitespace()
let maxLength = 1000
if s.count < maxLength {
truncatedTitleCache[title] = s
return s
}
s = (s as NSString).substring(to: maxLength)
truncatedTitleCache[title] = s
return s
}
func timelineTruncatedSummary(_ article: Article) -> String {
return timelineSummaryForArticle(article)
}
func timelineNormalizedText(_ text: String) -> String {
if text.isEmpty {
return ""
}
if let cachedText = normalizedTextCache[text] as? String {
return cachedText
}
var s = (text as NSString).rs_stringByTrimmingWhitespace()
s = s.rs_stringWithCollapsedWhitespace()
let result = s as String
normalizedTextCache[text] = result
return result
}
func timelineNormalizedTextTruncated(_ text: String) -> String {
if text.isEmpty {
return ""
}
if let cachedText = textCache[text] as? String {
return cachedText
}
var s: NSString = (text as NSString).rsparser_stringByDecodingHTMLEntities() as NSString
s = s.rs_stringByTrimmingWhitespace() as NSString
s = s.rs_stringWithCollapsedWhitespace() as NSString
let maxLength = 512
if s.length > maxLength {
s = s.substring(to: maxLength) as NSString
}
textCache[text] = String(s)
return s as String
}
func timelineSummaryForArticle(_ article: Article) -> String {
guard let body = article.body else {
return ""
}
if let cachedBody = summaryCache[body] as? String {
return cachedBody
}
var s = body.rs_string(byStrippingHTML: 300)
s = timelineNormalizedText(s)
if s == "Comments" { // Hacker News.
s = ""
}
summaryCache[body] = s
return s
}
private let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .none
return formatter
}()
private let timeFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .none
formatter.timeStyle = .short
return formatter
}()
private var token: Int = 0
func timelineDateString(_ date: Date) -> String {
if NSCalendar.rs_dateIsToday(date) {
return timeFormatter.string(from: date)
}
return dateFormatter.string(from: date)
}