diff --git a/Frameworks/Articles/Article.swift b/Frameworks/Articles/Article.swift index d2fbdda77..6e13633cc 100644 --- a/Frameworks/Articles/Article.swift +++ b/Frameworks/Articles/Article.swift @@ -86,38 +86,3 @@ public extension Array where Element == Article { return map { $0.articleID } } } - -public extension Article { - static let allowedTags: Set = ["b", "bdi", "bdo", "cite", "code", "del", "dfn", "em", "i", "ins", "kbd", "mark", "q", /* "rb", "rp", "rt", "rtc", "ruby", */ "s", "samp", "small", "strong", "sub", "sup", "time", "u", "var"] - - func sanitizedTitle(forHTML: Bool = true) -> String? { - guard let title = title else { return nil } - - let scanner = Scanner(string: title) - scanner.charactersToBeSkipped = nil - var result = "" - result.reserveCapacity(title.count) - - while !scanner.isAtEnd { - if let text = scanner.scanUpToString("<") { - result.append(text) - } - - if let _ = scanner.scanString("<") { - // All the allowed tags currently don't allow attributes - if let tag = scanner.scanUpToString(">") { - if Self.allowedTags.contains(tag.replacingOccurrences(of: "/", with: "")) { - forHTML ? result.append("<\(tag)>") : result.append("") - } else { - forHTML ? result.append("<\(tag)>") : result.append("<\(tag)>") - } - - let _ = scanner.scanString(">") - } - } - } - - return result - } - -} diff --git a/Frameworks/Articles/xcconfig/Articles_project.xcconfig b/Frameworks/Articles/xcconfig/Articles_project.xcconfig index d3bd6c6de..573284972 100644 --- a/Frameworks/Articles/xcconfig/Articles_project.xcconfig +++ b/Frameworks/Articles/xcconfig/Articles_project.xcconfig @@ -9,7 +9,7 @@ PROVISIONING_PROFILE_SPECIFIER = #include? "../../../SharedXcodeSettings/DeveloperSettings.xcconfig" SDKROOT = macosx -MACOSX_DEPLOYMENT_TARGET = 10.15 +MACOSX_DEPLOYMENT_TARGET = 10.14 IPHONEOS_DEPLOYMENT_TARGET = 13.0 SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator diff --git a/Frameworks/ArticlesDatabase/xcconfig/ArticlesDatabase_project.xcconfig b/Frameworks/ArticlesDatabase/xcconfig/ArticlesDatabase_project.xcconfig index d3bd6c6de..573284972 100644 --- a/Frameworks/ArticlesDatabase/xcconfig/ArticlesDatabase_project.xcconfig +++ b/Frameworks/ArticlesDatabase/xcconfig/ArticlesDatabase_project.xcconfig @@ -9,7 +9,7 @@ PROVISIONING_PROFILE_SPECIFIER = #include? "../../../SharedXcodeSettings/DeveloperSettings.xcconfig" SDKROOT = macosx -MACOSX_DEPLOYMENT_TARGET = 10.15 +MACOSX_DEPLOYMENT_TARGET = 10.14 IPHONEOS_DEPLOYMENT_TARGET = 13.0 SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator diff --git a/Frameworks/SyncDatabase/xcconfig/SyncDatabase_project.xcconfig b/Frameworks/SyncDatabase/xcconfig/SyncDatabase_project.xcconfig index d3bd6c6de..09f243ba8 100644 --- a/Frameworks/SyncDatabase/xcconfig/SyncDatabase_project.xcconfig +++ b/Frameworks/SyncDatabase/xcconfig/SyncDatabase_project.xcconfig @@ -9,7 +9,7 @@ PROVISIONING_PROFILE_SPECIFIER = #include? "../../../SharedXcodeSettings/DeveloperSettings.xcconfig" SDKROOT = macosx -MACOSX_DEPLOYMENT_TARGET = 10.15 +MACOSX_DEPLOYMENT_TARGET = 10.14 IPHONEOS_DEPLOYMENT_TARGET = 13.0 SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator @@ -18,6 +18,7 @@ SWIFT_VERSION = 5.1 COMBINE_HIDPI_IMAGES = YES COPY_PHASE_STRIP = NO +MACOSX_DEPLOYMENT_TARGET = 10.14 ALWAYS_SEARCH_USER_PATHS = NO CURRENT_PROJECT_VERSION = 1 VERSION_INFO_PREFIX = diff --git a/Mac/MainWindow/Timeline/Cell/MultilineTextFieldSizer.swift b/Mac/MainWindow/Timeline/Cell/MultilineTextFieldSizer.swift index de75fc46e..d5b979d25 100644 --- a/Mac/MainWindow/Timeline/Cell/MultilineTextFieldSizer.swift +++ b/Mac/MainWindow/Timeline/Cell/MultilineTextFieldSizer.swift @@ -34,7 +34,6 @@ final class MultilineTextFieldSizer { private let singleLineHeightEstimate: Int private let doubleLineHeightEstimate: Int private var cache = [String: WidthHeightCache]() // Each string has a cache. - private var attributedCache = [NSAttributedString: WidthHeightCache]() private static var sizers = [TextFieldSizerSpecifier: MultilineTextFieldSizer]() private init(numberOfLines: Int, font: NSFont) { @@ -52,14 +51,6 @@ final class MultilineTextFieldSizer { return sizer(numberOfLines: numberOfLines, font: font).sizeInfo(for: string, width: width) } - static func size(for attributedString: NSAttributedString, numberOfLines: Int, width: Int) -> TextFieldSizeInfo { - - // Assumes the same font family/size for the whole string - let font = attributedString.attribute(.font, at: 0, effectiveRange: nil) as! NSFont - - return sizer(numberOfLines: numberOfLines, font: font).sizeInfo(for: attributedString, width: width) - } - static func emptyCache() { sizers = [TextFieldSizerSpecifier: MultilineTextFieldSizer]() @@ -92,16 +83,6 @@ private extension MultilineTextFieldSizer { return sizeInfo } - func sizeInfo(for attributedString: NSAttributedString, width: Int) -> TextFieldSizeInfo { - - let textFieldHeight = height(for: attributedString, width: width) - let numberOfLinesUsed = numberOfLines(for: textFieldHeight) - - let size = NSSize(width: width, height: textFieldHeight) - let sizeInfo = TextFieldSizeInfo(size: size, numberOfLinesUsed: numberOfLinesUsed) - return sizeInfo - } - func height(for string: String, width: Int) -> Int { if cache[string] == nil { @@ -122,26 +103,6 @@ private extension MultilineTextFieldSizer { return height } - func height(for attribtuedString: NSAttributedString, width: Int) -> Int { - - if attributedCache[attribtuedString] == nil { - attributedCache[attribtuedString] = WidthHeightCache() - } - - if let height = attributedCache[attribtuedString]![width] { - return height - } - - if let height = heightConsideringNeighbors(attributedCache[attribtuedString]!, width) { - return height - } - - let height = calculateHeight(attribtuedString, width) - attributedCache[attribtuedString]![width] = height - - return height - } - static func createTextField(_ numberOfLines: Int, _ font: NSFont) -> NSTextField { let textField = NSTextField(wrappingLabelWithString: "") @@ -159,14 +120,6 @@ private extension MultilineTextFieldSizer { return MultilineTextFieldSizer.calculateHeight(string, width, textField) } - func calculateHeight(_ attributedString: NSAttributedString, _ width: Int) -> Int { - - textField.attributedStringValue = attributedString - textField.preferredMaxLayoutWidth = CGFloat(width) - let size = textField.fittingSize - return Int(ceil(size.height)) - } - static func calculateHeight(_ string: String, _ width: Int, _ textField: NSTextField) -> Int { textField.stringValue = string diff --git a/Mac/MainWindow/Timeline/Cell/TimelineCellData.swift b/Mac/MainWindow/Timeline/Cell/TimelineCellData.swift index 1e92a7714..b6ca525bc 100644 --- a/Mac/MainWindow/Timeline/Cell/TimelineCellData.swift +++ b/Mac/MainWindow/Timeline/Cell/TimelineCellData.swift @@ -12,7 +12,6 @@ import Articles struct TimelineCellData { let title: String - let attributedTitle: NSAttributedString let text: String let dateString: String let feedName: String @@ -27,7 +26,6 @@ struct TimelineCellData { init(article: Article, showFeedName: TimelineShowFeedName, feedName: String?, byline: String?, iconImage: IconImage?, showIcon: Bool, featuredImage: NSImage?) { self.title = ArticleStringFormatter.truncatedTitle(article) - self.attributedTitle = ArticleStringFormatter.attributedTruncatedTitle(article) self.text = ArticleStringFormatter.truncatedSummary(article) self.dateString = ArticleStringFormatter.dateString(article.logicalDatePublished) @@ -66,6 +64,5 @@ struct TimelineCellData { self.featuredImage = nil self.read = true self.starred = false - self.attributedTitle = NSAttributedString() } } diff --git a/Mac/MainWindow/Timeline/Cell/TimelineCellLayout.swift b/Mac/MainWindow/Timeline/Cell/TimelineCellLayout.swift index df4fb42b2..07bb08c9b 100644 --- a/Mac/MainWindow/Timeline/Cell/TimelineCellLayout.swift +++ b/Mac/MainWindow/Timeline/Cell/TimelineCellLayout.swift @@ -115,8 +115,7 @@ private extension TimelineCellLayout { return (r, 0) } - let attributedTitle = cellData.attributedTitle.adding(font: appearance.titleFont) - let sizeInfo = MultilineTextFieldSizer.size(for: attributedTitle, numberOfLines: appearance.titleNumberOfLines, width: Int(textBoxRect.width)) + let sizeInfo = MultilineTextFieldSizer.size(for: cellData.title, font: appearance.titleFont, numberOfLines: appearance.titleNumberOfLines, width: Int(textBoxRect.width)) r.size.height = sizeInfo.size.height if sizeInfo.numberOfLinesUsed < 1 { r.size.height = 0 diff --git a/Mac/MainWindow/Timeline/Cell/TimelineTableCellView.swift b/Mac/MainWindow/Timeline/Cell/TimelineTableCellView.swift index d0b9a7802..eb1e8a79e 100644 --- a/Mac/MainWindow/Timeline/Cell/TimelineTableCellView.swift +++ b/Mac/MainWindow/Timeline/Cell/TimelineTableCellView.swift @@ -221,7 +221,7 @@ private extension TimelineTableCellView { func updateTitleView() { - updateTextFieldAttributedText(titleView, cellData?.attributedTitle) + updateTextFieldText(titleView, cellData?.title) } func updateSummaryView() { @@ -247,19 +247,6 @@ private extension TimelineTableCellView { } } - func updateTextFieldAttributedText(_ textField: NSTextField, _ text: NSAttributedString?) { - var s = text ?? NSAttributedString(string: "") - - if let fieldFont = textField.font, let color = textField.textColor { - s = s.adding(font: fieldFont, color: color) - } - - if textField.attributedStringValue != s { - textField.attributedStringValue = s - needsLayout = true - } - } - func updateFeedNameView() { switch cellData.showFeedName { case .byline: diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 96d0e8804..599217fad 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -723,15 +723,12 @@ 84F9EAF4213660A100CF2DE4 /* testGenericScript.applescript in Sources */ = {isa = PBXBuildFile; fileRef = 84F9EAE1213660A100CF2DE4 /* testGenericScript.applescript */; }; 84F9EAF5213660A100CF2DE4 /* establishMainWindowStartingState.applescript in Sources */ = {isa = PBXBuildFile; fileRef = 84F9EAE2213660A100CF2DE4 /* establishMainWindowStartingState.applescript */; }; 84FF69B11FC3793300DC198E /* FaviconURLFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84FF69B01FC3793300DC198E /* FaviconURLFinder.swift */; }; - B26B9572243D176B0053EEF5 /* NSAttributedString+NetNewsWire.swift in Sources */ = {isa = PBXBuildFile; fileRef = B26B9571243D176B0053EEF5 /* NSAttributedString+NetNewsWire.swift */; }; - B26B9573243D176B0053EEF5 /* NSAttributedString+NetNewsWire.swift in Sources */ = {isa = PBXBuildFile; fileRef = B26B9571243D176B0053EEF5 /* NSAttributedString+NetNewsWire.swift */; }; B27EEBF9244D15F3000932E6 /* shared.css in Resources */ = {isa = PBXBuildFile; fileRef = B27EEBDF244D15F2000932E6 /* shared.css */; }; B27EEBFA244D15F3000932E6 /* shared.css in Resources */ = {isa = PBXBuildFile; fileRef = B27EEBDF244D15F2000932E6 /* shared.css */; }; B27EEBFB244D15F3000932E6 /* shared.css in Resources */ = {isa = PBXBuildFile; fileRef = B27EEBDF244D15F2000932E6 /* shared.css */; }; B2B8075E239C49D300F191E0 /* RSImage-AppIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B8075D239C49D300F191E0 /* RSImage-AppIcons.swift */; }; B2B80778239C4C7000F191E0 /* RSImage-AppIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B8075D239C49D300F191E0 /* RSImage-AppIcons.swift */; }; B2B80779239C4C7300F191E0 /* RSImage-AppIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B8075D239C49D300F191E0 /* RSImage-AppIcons.swift */; }; - B2C0FDEA2447A69100ADC150 /* NSAttributedString+NetNewsWire.swift in Sources */ = {isa = PBXBuildFile; fileRef = B26B9571243D176B0053EEF5 /* NSAttributedString+NetNewsWire.swift */; }; B528F81E23333C7E00E735DD /* page.html in Resources */ = {isa = PBXBuildFile; fileRef = B528F81D23333C7E00E735DD /* page.html */; }; BDCB516724282C8A00102A80 /* AccountsNewsBlur.xib in Resources */ = {isa = PBXBuildFile; fileRef = BDCB514D24282C8A00102A80 /* AccountsNewsBlur.xib */; }; BDCB516824282C8A00102A80 /* AccountsNewsBlur.xib in Resources */ = {isa = PBXBuildFile; fileRef = BDCB514D24282C8A00102A80 /* AccountsNewsBlur.xib */; }; @@ -1260,13 +1257,6 @@ remoteGlobalIDString = 84F22C541B52E0D9000060CE; remoteInfo = RSDatabase; }; - B234554A2453AB0F000F1D7F /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 517A754424451BD500B553B9 /* OAuthSwift.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = C48B28011AFA598D00C7DEF6; - remoteInfo = OAuthSwiftMacOS; - }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -1792,7 +1782,6 @@ 84FF69B01FC3793300DC198E /* FaviconURLFinder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconURLFinder.swift; sourceTree = ""; }; B24EFD482330FF99006C6242 /* NetNewsWire-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NetNewsWire-Bridging-Header.h"; sourceTree = ""; }; B24EFD5923310109006C6242 /* WKPreferencesPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WKPreferencesPrivate.h; sourceTree = ""; }; - B26B9571243D176B0053EEF5 /* NSAttributedString+NetNewsWire.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+NetNewsWire.swift"; sourceTree = ""; }; B27EEBDF244D15F2000932E6 /* shared.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = shared.css; sourceTree = ""; }; B2B8075D239C49D300F191E0 /* RSImage-AppIcons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RSImage-AppIcons.swift"; sourceTree = ""; }; B528F81D23333C7E00E735DD /* page.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = page.html; sourceTree = ""; }; @@ -2587,7 +2576,6 @@ B2B8075D239C49D300F191E0 /* RSImage-AppIcons.swift */, 51126DA3225FDE2F00722696 /* RSImage-Extensions.swift */, 84411E701FE5FBFA004B527F /* SmallIconProvider.swift */, - B26B9571243D176B0053EEF5 /* NSAttributedString+NetNewsWire.swift */, ); path = Extensions; sourceTree = ""; @@ -3257,7 +3245,6 @@ 84C37FB020DD8D9900CA8CF5 /* PBXTargetDependency */, 84C37FB820DD8DBB00CA8CF5 /* PBXTargetDependency */, 84C37FC820DD8E1D00CA8CF5 /* PBXTargetDependency */, - B234554B2453AB0F000F1D7F /* PBXTargetDependency */, 51C451AC226377C300C03939 /* PBXTargetDependency */, 51C451BC226377C900C03939 /* PBXTargetDependency */, 51C451C0226377D000C03939 /* PBXTargetDependency */, @@ -3304,36 +3291,36 @@ TargetAttributes = { 51314636235A7BBE00387FDC = { CreatedOnToolsVersion = 11.2; - DevelopmentTeam = M72QZ9W58G; + DevelopmentTeam = SHJK2V3AJG; LastSwiftMigration = 1120; ProvisioningStyle = Automatic; }; 513C5CE5232571C2003D4054 = { CreatedOnToolsVersion = 11.0; - DevelopmentTeam = M72QZ9W58G; + DevelopmentTeam = SHJK2V3AJG; ProvisioningStyle = Automatic; }; 518B2ED12351B3DD00400001 = { CreatedOnToolsVersion = 11.2; - DevelopmentTeam = M72QZ9W58G; + DevelopmentTeam = SHJK2V3AJG; ProvisioningStyle = Automatic; TestTargetID = 840D617B2029031C009BC708; }; 6581C73220CED60000F4AD34 = { - DevelopmentTeam = M72QZ9W58G; + DevelopmentTeam = SHJK2V3AJG; ProvisioningStyle = Automatic; }; 65ED3FA2235DEF6C0081F399 = { - DevelopmentTeam = M72QZ9W58G; + DevelopmentTeam = SHJK2V3AJG; ProvisioningStyle = Automatic; }; 65ED4090235DEF770081F399 = { - DevelopmentTeam = M72QZ9W58G; + DevelopmentTeam = SHJK2V3AJG; ProvisioningStyle = Automatic; }; 840D617B2029031C009BC708 = { CreatedOnToolsVersion = 9.3; - DevelopmentTeam = M72QZ9W58G; + DevelopmentTeam = SHJK2V3AJG; ProvisioningStyle = Automatic; SystemCapabilities = { com.apple.BackgroundModes = { @@ -3343,7 +3330,7 @@ }; 849C645F1ED37A5D003D8FC0 = { CreatedOnToolsVersion = 8.2.1; - DevelopmentTeam = M72QZ9W58G; + DevelopmentTeam = SHJK2V3AJG; ProvisioningStyle = Automatic; SystemCapabilities = { com.apple.HardenedRuntime = { @@ -3353,7 +3340,7 @@ }; 849C64701ED37A5D003D8FC0 = { CreatedOnToolsVersion = 8.2.1; - DevelopmentTeam = M72QZ9W58G; + DevelopmentTeam = SHJK2V3AJG; ProvisioningStyle = Automatic; TestTargetID = 849C645F1ED37A5D003D8FC0; }; @@ -4217,7 +4204,6 @@ 65ED4023235DEF6C0081F399 /* Folder+Scriptability.swift in Sources */, 65ED4024235DEF6C0081F399 /* TimelineCellLayout.swift in Sources */, 65ED4025235DEF6C0081F399 /* DetailWebView.swift in Sources */, - B26B9573243D176B0053EEF5 /* NSAttributedString+NetNewsWire.swift in Sources */, B2B80779239C4C7300F191E0 /* RSImage-AppIcons.swift in Sources */, 65ED4026235DEF6C0081F399 /* TimelineTableRowView.swift in Sources */, 65ED4027235DEF6C0081F399 /* UnreadIndicatorView.swift in Sources */, @@ -4314,7 +4300,6 @@ 51F9F3F923DFB16300A314FD /* UITableView-Extensions.swift in Sources */, 51C452792265091600C03939 /* MasterTimelineTableViewCell.swift in Sources */, 51C4526B226508F600C03939 /* MasterFeedViewController.swift in Sources */, - B2C0FDEA2447A69100ADC150 /* NSAttributedString+NetNewsWire.swift in Sources */, 5126EE97226CB48A00C22AFC /* SceneCoordinator.swift in Sources */, 84CAFCB022BC8C35007694F0 /* FetchRequestOperation.swift in Sources */, 51EF0F77227716200050506E /* FaviconGenerator.swift in Sources */, @@ -4554,7 +4539,6 @@ 8426119E1FCB6ED40086A189 /* HTMLMetadataDownloader.swift in Sources */, 849A976E1ED9EBC8007D329B /* TimelineViewController.swift in Sources */, 3B826DCC2385C84800FC1ADB /* AccountsFeedWranglerWindowController.swift in Sources */, - B26B9572243D176B0053EEF5 /* NSAttributedString+NetNewsWire.swift in Sources */, 5154368B229404D1005E1CDF /* FaviconGenerator.swift in Sources */, 5183CCE6226F4E110010922C /* RefreshInterval.swift in Sources */, 849A97771ED9EC04007D329B /* TimelineCellData.swift in Sources */, @@ -4769,11 +4753,6 @@ name = RSDatabase; targetProxy = 84C37FC720DD8E1D00CA8CF5 /* PBXContainerItemProxy */; }; - B234554B2453AB0F000F1D7F /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = OAuthSwiftMacOS; - targetProxy = B234554A2453AB0F000F1D7F /* PBXContainerItemProxy */; - }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ diff --git a/Shared/Article Rendering/ArticleRenderer.swift b/Shared/Article Rendering/ArticleRenderer.swift index 3588615bd..ef7a25a52 100644 --- a/Shared/Article Rendering/ArticleRenderer.swift +++ b/Shared/Article Rendering/ArticleRenderer.swift @@ -46,7 +46,7 @@ struct ArticleRenderer { self.article = article self.extractedArticle = extractedArticle self.articleStyle = style - self.title = article?.sanitizedTitle() ?? "" + self.title = article?.title ?? "" if let content = extractedArticle?.content { self.body = content self.baseURL = extractedArticle?.url diff --git a/Shared/Extensions/ArticleStringFormatter.swift b/Shared/Extensions/ArticleStringFormatter.swift index dac926b34..4fb9249ae 100644 --- a/Shared/Extensions/ArticleStringFormatter.swift +++ b/Shared/Extensions/ArticleStringFormatter.swift @@ -52,8 +52,8 @@ struct ArticleStringFormatter { return s } - static func truncatedTitle(_ article: Article, forHTML: Bool = false) -> String { - guard let title = article.sanitizedTitle(forHTML: forHTML) else { + static func truncatedTitle(_ article: Article) -> String { + guard let title = article.title else { return "" } @@ -64,11 +64,7 @@ struct ArticleStringFormatter { var s = title.replacingOccurrences(of: "\n", with: "") s = s.replacingOccurrences(of: "\r", with: "") s = s.replacingOccurrences(of: "\t", with: "") - - if !forHTML { - s = s.rsparser_stringByDecodingHTMLEntities() - } - + s = s.rsparser_stringByDecodingHTMLEntities() s = s.trimmingWhitespace s = s.collapsingWhitespace @@ -83,12 +79,6 @@ struct ArticleStringFormatter { return s } - static func attributedTruncatedTitle(_ article: Article) -> NSAttributedString { - let title = truncatedTitle(article, forHTML: true) - let attributed = NSAttributedString(html: title) - return attributed - } - static func truncatedSummary(_ article: Article) -> String { guard let body = article.body else { return "" diff --git a/Shared/Extensions/NSAttributedString+NetNewsWire.swift b/Shared/Extensions/NSAttributedString+NetNewsWire.swift deleted file mode 100644 index afd4fada9..000000000 --- a/Shared/Extensions/NSAttributedString+NetNewsWire.swift +++ /dev/null @@ -1,134 +0,0 @@ -// -// NSAttributedString+NetNewsWire.swift -// NetNewsWire -// -// Created by Nate Weaver on 2020-04-07. -// Copyright © 2020 Ranchero Software. All rights reserved. -// - -#if canImport(AppKit) -import AppKit -typealias Font = NSFont -typealias FontDescriptor = NSFontDescriptor -typealias Color = NSColor - -private let boldTrait = NSFontDescriptor.SymbolicTraits.bold -private let italicTrait = NSFontDescriptor.SymbolicTraits.italic -private let monoSpaceTrait = NSFontDescriptor.SymbolicTraits.monoSpace -#else -import UIKit -typealias Font = UIFont -typealias FontDescriptor = UIFontDescriptor -typealias Color = UIColor - -private let boldTrait = UIFontDescriptor.SymbolicTraits.traitBold -private let italicTrait = UIFontDescriptor.SymbolicTraits.traitItalic -private let monoSpaceTrait = UIFontDescriptor.SymbolicTraits.traitMonoSpace -#endif - -extension NSAttributedString { - - /// Adds a font and color to an attributed string. - /// - /// Additionally converts super-/subscript runs to super-/subscripted font variants - /// and converts bold text to heavy if the base font is semibold. - /// - /// - Parameters: - /// - baseFont: The font to add. - /// - color: The color to add. - func adding(font baseFont: Font, color: Color? = nil) -> NSAttributedString { - let mutable = self.mutableCopy() as! NSMutableAttributedString - let fullRange = NSRange(location: 0, length: mutable.length) - - if let color = color { - mutable.addAttribute(.foregroundColor, value: color as Any, range: fullRange) - } - - let size = baseFont.pointSize - let baseDescriptor = baseFont.fontDescriptor - let baseSymbolicTraits = baseDescriptor.symbolicTraits - - let baseTraits = baseDescriptor.object(forKey: .traits) as! [FontDescriptor.TraitKey: Any] - let baseWeight = baseTraits[.weight] as! Font.Weight - - mutable.enumerateAttribute(.font, in: fullRange, options: []) { (font: Any?, range: NSRange, stop: UnsafeMutablePointer) in - guard let font = font as? Font else { return } - - var newSymbolicTraits = baseSymbolicTraits - - let symbolicTraits = font.fontDescriptor.symbolicTraits - - if symbolicTraits.contains(italicTrait) { - newSymbolicTraits.insert(italicTrait) - } - - if symbolicTraits.contains(monoSpaceTrait) { - newSymbolicTraits.insert(monoSpaceTrait) - } - - #if canImport(AppKit) - var descriptor = baseDescriptor.withSymbolicTraits(newSymbolicTraits) - #else - var descriptor = baseDescriptor.withSymbolicTraits(newSymbolicTraits)! - #endif - - if symbolicTraits.contains(boldTrait) { - // If the base font is semibold (as timeline titles are), make the "bold" - // text heavy for better contrast. - - if baseWeight == .semibold { - let traits: [FontDescriptor.TraitKey: Any] = [.weight: Font.Weight.heavy] - let attributes: [FontDescriptor.AttributeName: Any] = [.traits: traits] - descriptor = descriptor.addingAttributes(attributes) - } - } - - let newFont = Font(descriptor: descriptor, size: size) - - mutable.addAttribute(.font, value: newFont as Any, range: range) - } - - // make sup/sub smaller. `Key("NSSupeScript")` is used here because `.superscript` - // isn't defined in UIKit. - let superscriptAttribute = Key("NSSuperScript") - - mutable.enumerateAttributes(in: fullRange, options: []) { (attributes: [Key : Any], range: NSRange, stop: UnsafeMutablePointer) in - guard let superscript = attributes[superscriptAttribute] as? Int else { - return - } - - if superscript != 0 { - let font = mutable.attribute(.font, at: range.location, effectiveRange: nil) as! Font - - // There's some discrepancy here: The raw value of AppKit's .typeIdentifier is UIKit's .featureIdentifier, - // and AppKit's .selectorIdentifier is UIKit's .typeIdentifier - #if canImport(AppKit) - let features: [FontDescriptor.FeatureKey: Any] = [.typeIdentifier: kVerticalPositionType, .selectorIdentifier: superscript > 0 ? kSuperiorsSelector : kInferiorsSelector] - #else - let features: [FontDescriptor.FeatureKey: Any] = [.featureIdentifier: kVerticalPositionType, .typeIdentifier: superscript > 0 ? kSuperiorsSelector : kInferiorsSelector] - #endif - let attributes: [FontDescriptor.AttributeName: Any] = [.featureSettings: [features]] - let descriptor = font.fontDescriptor.addingAttributes(attributes) - - let newFont = Font(descriptor: descriptor, size: font.pointSize) - - let newAttributes: [NSAttributedString.Key: Any] = [ - .font: newFont as Any, - superscriptAttribute: 0, - ] - - mutable.addAttributes(newAttributes, range: range) - } - } - - return mutable.copy() as! NSAttributedString - } - - /// Creates an attributed string from HTML. - convenience init(html: String) { - let data = html.data(using: .utf8)! - let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [.characterEncoding: String.Encoding.utf8.rawValue, .documentType: NSAttributedString.DocumentType.html] - try! self.init(data: data, options: options, documentAttributes: nil) - } - -} diff --git a/iOS/MasterTimeline/Cell/MasterTimelineCellData.swift b/iOS/MasterTimeline/Cell/MasterTimelineCellData.swift index d1d1c3782..8996654f8 100644 --- a/iOS/MasterTimeline/Cell/MasterTimelineCellData.swift +++ b/iOS/MasterTimeline/Cell/MasterTimelineCellData.swift @@ -12,7 +12,6 @@ import Articles struct MasterTimelineCellData { let title: String - let attributedTitle: NSAttributedString let summary: String let dateString: String let feedName: String @@ -29,7 +28,6 @@ struct MasterTimelineCellData { init(article: Article, showFeedName: ShowFeedName, feedName: String?, byline: String?, iconImage: IconImage?, showIcon: Bool, featuredImage: UIImage?, numberOfLines: Int, iconSize: IconSize) { self.title = ArticleStringFormatter.truncatedTitle(article) - self.attributedTitle = ArticleStringFormatter.attributedTruncatedTitle(article) self.summary = ArticleStringFormatter.truncatedSummary(article) self.dateString = ArticleStringFormatter.dateString(article.logicalDatePublished) @@ -62,7 +60,6 @@ struct MasterTimelineCellData { init() { //Empty self.title = "" - self.attributedTitle = NSAttributedString() self.summary = "" self.dateString = "" self.feedName = "" diff --git a/iOS/MasterTimeline/Cell/MasterTimelineTableViewCell.swift b/iOS/MasterTimeline/Cell/MasterTimelineTableViewCell.swift index 0c2d9d4a5..863ee7631 100644 --- a/iOS/MasterTimeline/Cell/MasterTimelineTableViewCell.swift +++ b/iOS/MasterTimeline/Cell/MasterTimelineTableViewCell.swift @@ -148,7 +148,7 @@ private extension MasterTimelineTableViewCell { func updateTitleView() { titleView.font = MasterTimelineDefaultCellLayout.titleFont titleView.textColor = labelColor - updateTextFieldAttributedText(titleView, cellData?.attributedTitle) + updateTextFieldText(titleView, cellData?.title) } func updateSummaryView() { @@ -170,19 +170,6 @@ private extension MasterTimelineTableViewCell { setNeedsLayout() } } - - func updateTextFieldAttributedText(_ label: UILabel, _ text: NSAttributedString?) { - var s = text ?? NSAttributedString(string: "") - - if let fieldFont = label.font, let color = label.textColor { - s = s.adding(font: fieldFont, color: color) - } - - if label.attributedText != s { - label.attributedText = s - setNeedsLayout() - } - } func updateFeedNameView() { switch cellData.showFeedName {