-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathNitroTextImpl.swift
More file actions
113 lines (95 loc) · 3.81 KB
/
NitroTextImpl.swift
File metadata and controls
113 lines (95 loc) · 3.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//
// NitroTextImpl.swift
// Pods
//
// Created by Patrick Kabwe on 01/09/2025.
//
import UIKit
final class NitroTextImpl {
weak var nitroTextView : NitroTextView?
var currentTextAlignment: NSTextAlignment = .natural
var currentTransform: TextTransform = .none
var currentEllipsize: NSLineBreakMode = .byTruncatingTail
var fontCache: [FontKey: UIFont] = [:]
init(_ nitroTextView: NitroTextView) {
self.nitroTextView = nitroTextView
}
func setSelectable(_ selectable: Bool?) {
nitroTextView?.isSelectable = selectable ?? true
}
func setNumberOfLines(_ value: Double?) {
let n = Int(value ?? 0)
nitroTextView?.textContainer.maximumNumberOfLines = n
nitroTextView?.textContainer.lineBreakMode = effectiveLineBreakMode(forLines: n)
}
func setEllipsizeMode(_ mode: EllipsizeMode?) {
switch mode {
case .some(.head): currentEllipsize = .byTruncatingHead
case .some(.middle): currentEllipsize = .byTruncatingMiddle
case .some(.tail): currentEllipsize = .byTruncatingTail
case .some(.clip): currentEllipsize = .byClipping
default: currentEllipsize = .byTruncatingTail
}
guard let n = nitroTextView?.textContainer.maximumNumberOfLines else { return }
nitroTextView?.textContainer.lineBreakMode = effectiveLineBreakMode(forLines: n)
}
func effectiveLineBreakMode(forLines n: Int) -> NSLineBreakMode {
guard n > 0 else { return .byWordWrapping }
if n == 1 { return currentEllipsize }
switch currentEllipsize {
case .byClipping:
return .byWordWrapping
default:
return .byTruncatingTail
}
}
func setText(_ attributedText: NSAttributedString) {
if let storage = nitroTextView?.tkStorage ?? nitroTextView?.layoutManager.textStorage {
storage.beginEditing()
storage.setAttributedString(attributedText)
storage.endEditing()
} else {
nitroTextView?.attributedText = attributedText
}
nitroTextView?.setNeedsLayout()
}
func setPlainText(_ value: String?) {
let attributed = NSAttributedString(string: value ?? "")
setText(attributed)
}
func setTextAlign(_ align: TextAlign?) {
switch align {
case .some(.center): currentTextAlignment = .center
case .some(.right): currentTextAlignment = .right
case .some(.justify): currentTextAlignment = .justified
case .some(.left): currentTextAlignment = .left
default: currentTextAlignment = .natural
}
nitroTextView?.textAlignment = currentTextAlignment
}
func setTextTransform(_ transform: TextTransform?) {
switch transform {
case .some(.uppercase): currentTransform = .uppercase
case .some(.lowercase): currentTransform = .lowercase
case .some(.capitalize): currentTransform = .capitalize
default: currentTransform = .none
}
}
func setFragments(_ fragments: [Fragment]?) {
guard let fragments = fragments, !fragments.isEmpty else {
nitroTextView?.attributedText = nil
return
}
let result = NSMutableAttributedString()
let defaultColor = nitroTextView?.textColor ?? UIColor.label
for fragment in fragments {
guard let rawText = fragment.text else { continue }
let text = transform(rawText, with: fragment)
let attributes = makeAttributes(for: fragment, defaultColor: defaultColor)
result.append(NSAttributedString(string: text, attributes: attributes))
}
setText(result)
}
// Attribute helpers moved to NitroTextImpl+Attributes.swift
}
// Fragment merging and font helpers moved to NitroTextImpl+Fragment.swift