Add proper support for dark mode on attributed text
This commit is contained in:
parent
99620c849f
commit
c4d49c423a
4 changed files with 73 additions and 55 deletions
64
MobileFort/Common/AttributedStringExtensions.swift
Normal file
64
MobileFort/Common/AttributedStringExtensions.swift
Normal file
|
@ -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
|
|
@ -1,32 +1,5 @@
|
||||||
import SwiftUI
|
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 {
|
final class AttributedTextComponent: UIViewRepresentable {
|
||||||
let string: NSMutableAttributedString
|
let string: NSMutableAttributedString
|
||||||
|
|
||||||
|
|
|
@ -1,31 +1,5 @@
|
||||||
import SwiftUI
|
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 {
|
final class AttributedTextComponent: NSViewRepresentable {
|
||||||
let string: NSMutableAttributedString
|
let string: NSMutableAttributedString
|
||||||
|
|
||||||
|
@ -39,9 +13,9 @@ final class AttributedTextComponent: NSViewRepresentable {
|
||||||
|
|
||||||
func updateNSView(_ uiView: NSTextField, context: Context) {
|
func updateNSView(_ uiView: NSTextField, context: Context) {
|
||||||
uiView.backgroundColor = .clear
|
uiView.backgroundColor = .clear
|
||||||
//uiView.numberOfLines = 0
|
|
||||||
uiView.lineBreakMode = .byWordWrapping
|
uiView.lineBreakMode = .byWordWrapping
|
||||||
uiView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
uiView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
||||||
|
|
||||||
uiView.attributedStringValue = string
|
uiView.attributedStringValue = string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +36,7 @@ struct AttributedText: View {
|
||||||
@State var lastSize: CGSize = .zero
|
@State var lastSize: CGSize = .zero
|
||||||
|
|
||||||
init(_ html: NSMutableAttributedString) {
|
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)
|
self.component = AttributedTextComponent(html)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +47,7 @@ struct AttributedText: View {
|
||||||
label.lineBreakMode = .byWordWrapping
|
label.lineBreakMode = .byWordWrapping
|
||||||
|
|
||||||
//label.attributedText = self.html
|
//label.attributedText = self.html
|
||||||
|
|
||||||
label.attributedStringValue = self.html
|
label.attributedStringValue = self.html
|
||||||
|
|
||||||
label.sizeToFit()
|
label.sizeToFit()
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
03B2BAA8256556D100483FE3 /* URLImage in Frameworks */ = {isa = PBXBuildFile; productRef = 03B2BAA7256556D100483FE3 /* URLImage */; };
|
03B2BAA8256556D100483FE3 /* URLImage in Frameworks */ = {isa = PBXBuildFile; productRef = 03B2BAA7256556D100483FE3 /* URLImage */; };
|
||||||
03B2BAB225655A1100483FE3 /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B2BAB125655A1100483FE3 /* WebView.swift */; };
|
03B2BAB225655A1100483FE3 /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B2BAB125655A1100483FE3 /* WebView.swift */; };
|
||||||
03B2BAB325655A1100483FE3 /* 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 */; };
|
03BCD7432488947200DA1F27 /* ProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03BCD7422488947200DA1F27 /* ProfileView.swift */; };
|
||||||
03BCD7452488948200DA1F27 /* PostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03BCD7442488948200DA1F27 /* PostView.swift */; };
|
03BCD7452488948200DA1F27 /* PostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03BCD7442488948200DA1F27 /* PostView.swift */; };
|
||||||
03BCD74A2489322500DA1F27 /* AttributedText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03BCD7492489322500DA1F27 /* AttributedText.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 = "<group>"; };
|
03B2BA84256550FA00483FE3 /* AttributedText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedText.swift; sourceTree = "<group>"; };
|
||||||
03B2BA9E2565555500483FE3 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
|
03B2BA9E2565555500483FE3 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
|
||||||
03B2BAB125655A1100483FE3 /* WebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebView.swift; sourceTree = "<group>"; };
|
03B2BAB125655A1100483FE3 /* WebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebView.swift; sourceTree = "<group>"; };
|
||||||
|
03B2BAB62565608400483FE3 /* AttributedStringExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringExtensions.swift; sourceTree = "<group>"; };
|
||||||
03BCD7422488947200DA1F27 /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = "<group>"; };
|
03BCD7422488947200DA1F27 /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = "<group>"; };
|
||||||
03BCD7442488948200DA1F27 /* PostView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostView.swift; sourceTree = "<group>"; };
|
03BCD7442488948200DA1F27 /* PostView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostView.swift; sourceTree = "<group>"; };
|
||||||
03BCD7492489322500DA1F27 /* AttributedText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedText.swift; sourceTree = "<group>"; };
|
03BCD7492489322500DA1F27 /* AttributedText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedText.swift; sourceTree = "<group>"; };
|
||||||
|
@ -139,6 +142,7 @@
|
||||||
03BCD7422488947200DA1F27 /* ProfileView.swift */,
|
03BCD7422488947200DA1F27 /* ProfileView.swift */,
|
||||||
03BCD7442488948200DA1F27 /* PostView.swift */,
|
03BCD7442488948200DA1F27 /* PostView.swift */,
|
||||||
03B2BAB125655A1100483FE3 /* WebView.swift */,
|
03B2BAB125655A1100483FE3 /* WebView.swift */,
|
||||||
|
03B2BAB62565608400483FE3 /* AttributedStringExtensions.swift */,
|
||||||
);
|
);
|
||||||
path = Common;
|
path = Common;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -262,6 +266,7 @@
|
||||||
03427F6D248887D200A0073D /* Common.swift in Sources */,
|
03427F6D248887D200A0073D /* Common.swift in Sources */,
|
||||||
03B2BAB225655A1100483FE3 /* WebView.swift in Sources */,
|
03B2BAB225655A1100483FE3 /* WebView.swift in Sources */,
|
||||||
03427F592488856C00A0073D /* AppDelegate.swift in Sources */,
|
03427F592488856C00A0073D /* AppDelegate.swift in Sources */,
|
||||||
|
03B2BAB72565608400483FE3 /* AttributedStringExtensions.swift in Sources */,
|
||||||
03BCD7432488947200DA1F27 /* ProfileView.swift in Sources */,
|
03BCD7432488947200DA1F27 /* ProfileView.swift in Sources */,
|
||||||
03427F5B2488856C00A0073D /* SceneDelegate.swift in Sources */,
|
03427F5B2488856C00A0073D /* SceneDelegate.swift in Sources */,
|
||||||
03BCD7452488948200DA1F27 /* PostView.swift in Sources */,
|
03BCD7452488948200DA1F27 /* PostView.swift in Sources */,
|
||||||
|
@ -278,6 +283,7 @@
|
||||||
03B2BA9F2565555500483FE3 /* MainView.swift in Sources */,
|
03B2BA9F2565555500483FE3 /* MainView.swift in Sources */,
|
||||||
03B2BA7025654F0500483FE3 /* Common.swift in Sources */,
|
03B2BA7025654F0500483FE3 /* Common.swift in Sources */,
|
||||||
03B2BA7125654F0500483FE3 /* ProfileView.swift in Sources */,
|
03B2BA7125654F0500483FE3 /* ProfileView.swift in Sources */,
|
||||||
|
03B2BAB82565608400483FE3 /* AttributedStringExtensions.swift in Sources */,
|
||||||
03B2BA7225654F0500483FE3 /* PostView.swift in Sources */,
|
03B2BA7225654F0500483FE3 /* PostView.swift in Sources */,
|
||||||
03B2BA5C25654E9700483FE3 /* AppDelegate.swift in Sources */,
|
03B2BA5C25654E9700483FE3 /* AppDelegate.swift in Sources */,
|
||||||
03B2BAB325655A1100483FE3 /* WebView.swift in Sources */,
|
03B2BAB325655A1100483FE3 /* WebView.swift in Sources */,
|
||||||
|
|
Reference in a new issue