From c4d49c423aae77ee9dd04983160dbf37ca2a4d59 Mon Sep 17 00:00:00 2001 From: redstrate <54911369+redstrate@users.noreply.github.com> Date: Wed, 18 Nov 2020 09:03:56 -0500 Subject: [PATCH] Add proper support for dark mode on attributed text --- .../Common/AttributedStringExtensions.swift | 64 +++++++++++++++++++ .../MobileFort (iOS)/AttributedText.swift | 27 -------- .../MobileFort (macOS)/AttributedText.swift | 31 +-------- .../MobileFort.xcodeproj/project.pbxproj | 6 ++ 4 files changed, 73 insertions(+), 55 deletions(-) create mode 100644 MobileFort/Common/AttributedStringExtensions.swift diff --git a/MobileFort/Common/AttributedStringExtensions.swift b/MobileFort/Common/AttributedStringExtensions.swift new file mode 100644 index 0000000..b692b9c --- /dev/null +++ b/MobileFort/Common/AttributedStringExtensions.swift @@ -0,0 +1,64 @@ +import Foundation + +#if os(macOS) +import AppKit + +extension NSMutableAttributedString { + func with(font: NSFont) -> NSMutableAttributedString { + enumerateAttribute(NSAttributedString.Key.font, in: NSMakeRange(0, length), options: .longestEffectiveRangeNotRequired, using: { (value, range, stop) in + if let originalFont = value as? NSFont, let newFont = applyTraitsFromFont(originalFont, to: font) { + addAttribute(NSAttributedString.Key.font, value: newFont, range: range) + } + }) + + addAttribute(NSAttributedString.Key.foregroundColor, value: NSColor.controlTextColor, range: NSRange(location: 0, length: self.length)) + + return self + } + + func applyTraitsFromFont(_ originalFont: NSFont, to newFont: NSFont) -> NSFont? { + let originalTrait = originalFont.fontDescriptor.symbolicTraits + + if(originalTrait.contains(NSFontDescriptor.SymbolicTraits.bold)) { + var traits = newFont.fontDescriptor.symbolicTraits + traits.insert(.bold) + + let fontDescriptor = newFont.fontDescriptor.withSymbolicTraits(traits) + return NSFont.init(descriptor: fontDescriptor, size: 0) + } + + return newFont + } +} +#elseif os(iOS) +import UIKit + +extension NSMutableAttributedString { + func with(font: UIFont) -> NSMutableAttributedString { + enumerateAttribute(NSAttributedString.Key.font, in: NSMakeRange(0, length), options: .longestEffectiveRangeNotRequired, using: { (value, range, stop) in + if let originalFont = value as? UIFont, let newFont = applyTraitsFromFont(originalFont, to: font) { + addAttribute(NSAttributedString.Key.font, value: newFont, range: range) + } + }) + + addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.label, range: NSRange(location: 0, length: self.length)) + + return self + } + + func applyTraitsFromFont(_ originalFont: UIFont, to newFont: UIFont) -> UIFont? { + let originalTrait = originalFont.fontDescriptor.symbolicTraits + + if originalTrait.contains(.traitBold) { + var traits = newFont.fontDescriptor.symbolicTraits + traits.insert(.traitBold) + + if let fontDescriptor = newFont.fontDescriptor.withSymbolicTraits(traits) { + return UIFont.init(descriptor: fontDescriptor, size: 0) + } + } + + return newFont + } +} +#endif diff --git a/MobileFort/MobileFort (iOS)/AttributedText.swift b/MobileFort/MobileFort (iOS)/AttributedText.swift index 0065bf4..e87ad28 100644 --- a/MobileFort/MobileFort (iOS)/AttributedText.swift +++ b/MobileFort/MobileFort (iOS)/AttributedText.swift @@ -1,32 +1,5 @@ import SwiftUI -extension NSMutableAttributedString { - func with(font: UIFont) -> NSMutableAttributedString { - enumerateAttribute(NSAttributedString.Key.font, in: NSMakeRange(0, length), options: .longestEffectiveRangeNotRequired, using: { (value, range, stop) in - if let originalFont = value as? UIFont, let newFont = applyTraitsFromFont(originalFont, to: font) { - addAttribute(NSAttributedString.Key.font, value: newFont, range: range) - } - }) - - return self - } - - func applyTraitsFromFont(_ originalFont: UIFont, to newFont: UIFont) -> UIFont? { - let originalTrait = originalFont.fontDescriptor.symbolicTraits - - if originalTrait.contains(.traitBold) { - var traits = newFont.fontDescriptor.symbolicTraits - traits.insert(.traitBold) - - if let fontDescriptor = newFont.fontDescriptor.withSymbolicTraits(traits) { - return UIFont.init(descriptor: fontDescriptor, size: 0) - } - } - - return newFont - } -} - final class AttributedTextComponent: UIViewRepresentable { let string: NSMutableAttributedString diff --git a/MobileFort/MobileFort (macOS)/AttributedText.swift b/MobileFort/MobileFort (macOS)/AttributedText.swift index 9c0adea..f93d13c 100644 --- a/MobileFort/MobileFort (macOS)/AttributedText.swift +++ b/MobileFort/MobileFort (macOS)/AttributedText.swift @@ -1,31 +1,5 @@ import SwiftUI -extension NSMutableAttributedString { - func with(font: NSFont) -> NSMutableAttributedString { - enumerateAttribute(NSAttributedString.Key.font, in: NSMakeRange(0, length), options: .longestEffectiveRangeNotRequired, using: { (value, range, stop) in - if let originalFont = value as? NSFont, let newFont = applyTraitsFromFont(originalFont, to: font) { - addAttribute(NSAttributedString.Key.font, value: newFont, range: range) - } - }) - - return self - } - - func applyTraitsFromFont(_ originalFont: NSFont, to newFont: NSFont) -> NSFont? { - let originalTrait = originalFont.fontDescriptor.symbolicTraits - - if(originalTrait.contains(NSFontDescriptor.SymbolicTraits.bold)) { - var traits = newFont.fontDescriptor.symbolicTraits - traits.insert(.bold) - - let fontDescriptor = newFont.fontDescriptor.withSymbolicTraits(traits) - return NSFont.init(descriptor: fontDescriptor, size: 0) - } - - return newFont - } -} - final class AttributedTextComponent: NSViewRepresentable { let string: NSMutableAttributedString @@ -39,9 +13,9 @@ final class AttributedTextComponent: NSViewRepresentable { func updateNSView(_ uiView: NSTextField, context: Context) { uiView.backgroundColor = .clear - //uiView.numberOfLines = 0 uiView.lineBreakMode = .byWordWrapping uiView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) + uiView.attributedStringValue = string } } @@ -62,7 +36,7 @@ struct AttributedText: View { @State var lastSize: CGSize = .zero init(_ html: NSMutableAttributedString) { - self.html = html.with(font: NSFont.systemFont(ofSize: 15)) + self.html = html.with(font: NSFont.systemFont(ofSize: NSFont.systemFontSize)) self.component = AttributedTextComponent(html) } @@ -73,6 +47,7 @@ struct AttributedText: View { label.lineBreakMode = .byWordWrapping //label.attributedText = self.html + label.attributedStringValue = self.html label.sizeToFit() diff --git a/MobileFort/MobileFort.xcodeproj/project.pbxproj b/MobileFort/MobileFort.xcodeproj/project.pbxproj index e5e79b1..93d2e9c 100644 --- a/MobileFort/MobileFort.xcodeproj/project.pbxproj +++ b/MobileFort/MobileFort.xcodeproj/project.pbxproj @@ -26,6 +26,8 @@ 03B2BAA8256556D100483FE3 /* URLImage in Frameworks */ = {isa = PBXBuildFile; productRef = 03B2BAA7256556D100483FE3 /* URLImage */; }; 03B2BAB225655A1100483FE3 /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B2BAB125655A1100483FE3 /* WebView.swift */; }; 03B2BAB325655A1100483FE3 /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B2BAB125655A1100483FE3 /* WebView.swift */; }; + 03B2BAB72565608400483FE3 /* AttributedStringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B2BAB62565608400483FE3 /* AttributedStringExtensions.swift */; }; + 03B2BAB82565608400483FE3 /* AttributedStringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B2BAB62565608400483FE3 /* AttributedStringExtensions.swift */; }; 03BCD7432488947200DA1F27 /* ProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03BCD7422488947200DA1F27 /* ProfileView.swift */; }; 03BCD7452488948200DA1F27 /* PostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03BCD7442488948200DA1F27 /* PostView.swift */; }; 03BCD74A2489322500DA1F27 /* AttributedText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03BCD7492489322500DA1F27 /* AttributedText.swift */; }; @@ -50,6 +52,7 @@ 03B2BA84256550FA00483FE3 /* AttributedText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedText.swift; sourceTree = ""; }; 03B2BA9E2565555500483FE3 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; 03B2BAB125655A1100483FE3 /* WebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebView.swift; sourceTree = ""; }; + 03B2BAB62565608400483FE3 /* AttributedStringExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringExtensions.swift; sourceTree = ""; }; 03BCD7422488947200DA1F27 /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = ""; }; 03BCD7442488948200DA1F27 /* PostView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostView.swift; sourceTree = ""; }; 03BCD7492489322500DA1F27 /* AttributedText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedText.swift; sourceTree = ""; }; @@ -139,6 +142,7 @@ 03BCD7422488947200DA1F27 /* ProfileView.swift */, 03BCD7442488948200DA1F27 /* PostView.swift */, 03B2BAB125655A1100483FE3 /* WebView.swift */, + 03B2BAB62565608400483FE3 /* AttributedStringExtensions.swift */, ); path = Common; sourceTree = ""; @@ -262,6 +266,7 @@ 03427F6D248887D200A0073D /* Common.swift in Sources */, 03B2BAB225655A1100483FE3 /* WebView.swift in Sources */, 03427F592488856C00A0073D /* AppDelegate.swift in Sources */, + 03B2BAB72565608400483FE3 /* AttributedStringExtensions.swift in Sources */, 03BCD7432488947200DA1F27 /* ProfileView.swift in Sources */, 03427F5B2488856C00A0073D /* SceneDelegate.swift in Sources */, 03BCD7452488948200DA1F27 /* PostView.swift in Sources */, @@ -278,6 +283,7 @@ 03B2BA9F2565555500483FE3 /* MainView.swift in Sources */, 03B2BA7025654F0500483FE3 /* Common.swift in Sources */, 03B2BA7125654F0500483FE3 /* ProfileView.swift in Sources */, + 03B2BAB82565608400483FE3 /* AttributedStringExtensions.swift in Sources */, 03B2BA7225654F0500483FE3 /* PostView.swift in Sources */, 03B2BA5C25654E9700483FE3 /* AppDelegate.swift in Sources */, 03B2BAB325655A1100483FE3 /* WebView.swift in Sources */,