Skip to content

Commit c05ea3b

Browse files
TextKit 2 - Implement basic TK2 class and graceful fallback to TK1 (#1690)
2 parents d344c21 + 0a48d63 commit c05ea3b

File tree

3 files changed

+101
-7
lines changed

3 files changed

+101
-7
lines changed

Simplenote.xcodeproj/project.pbxproj

+4
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,7 @@
540540
BAB6C04526BA4A04007495C4 /* String+Simplenote.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5476BC023D8E5D0000E7723 /* String+Simplenote.swift */; };
541541
BAB6C04726BA4CAF007495C4 /* WidgetController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAB6C04626BA4CAF007495C4 /* WidgetController.swift */; };
542542
BAB898D32BEC404200E238B8 /* CreateNewNoteIntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAB898D22BEC404200E238B8 /* CreateNewNoteIntentHandler.swift */; };
543+
BABB22DF2D14DA6600FCF47D /* SPTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BABB22DE2D14DA6300FCF47D /* SPTextView.swift */; };
543544
BABFFF2226CF9094003A4C25 /* WidgetDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = BABFFF2126CF9094003A4C25 /* WidgetDefaults.swift */; };
544545
BABFFF2326CF9094003A4C25 /* WidgetDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = BABFFF2126CF9094003A4C25 /* WidgetDefaults.swift */; };
545546
BABFFF2426CF9094003A4C25 /* WidgetDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = BABFFF2126CF9094003A4C25 /* WidgetDefaults.swift */; };
@@ -1242,6 +1243,7 @@
12421243
BAB576BD2670512C00B0C56F /* NoteWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteWidget.swift; sourceTree = "<group>"; };
12431244
BAB6C04626BA4CAF007495C4 /* WidgetController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetController.swift; sourceTree = "<group>"; };
12441245
BAB898D22BEC404200E238B8 /* CreateNewNoteIntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateNewNoteIntentHandler.swift; sourceTree = "<group>"; };
1246+
BABB22DE2D14DA6300FCF47D /* SPTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPTextView.swift; sourceTree = "<group>"; };
12451247
BABFFF2126CF9094003A4C25 /* WidgetDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetDefaults.swift; sourceTree = "<group>"; };
12461248
BAD0F1EC2BED49C200E73E45 /* FindNoteIntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FindNoteIntentHandler.swift; sourceTree = "<group>"; };
12471249
BAE08625261282D1009D40CD /* Note+Publish.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Note+Publish.swift"; sourceTree = "<group>"; };
@@ -1872,6 +1874,7 @@
18721874
children = (
18731875
B5E3F3972539F1E900271AEA /* SPTextView.h */,
18741876
B5E3F3962539F1E900271AEA /* SPTextView.m */,
1877+
BABB22DE2D14DA6300FCF47D /* SPTextView.swift */,
18751878
E21F57B717C1244E001F02D3 /* SPEditorTextView.h */,
18761879
E21F57B817C1244E001F02D3 /* SPEditorTextView.m */,
18771880
A6BBDA45255034E6005C8343 /* SPEditorTextView+Simplenote.swift */,
@@ -3562,6 +3565,7 @@
35623565
B53C5A5A230330CD00DA2143 /* SPNoteListViewController+Extensions.swift in Sources */,
35633566
A6C0DFB525C1581D00B9BE39 /* UIScrollView+Simplenote.swift in Sources */,
35643567
375D24B621E01131007AB25A /* html_blocks.c in Sources */,
3568+
BABB22DF2D14DA6600FCF47D /* SPTextView.swift in Sources */,
35653569
46A3C98217DFA81A002865AE /* NSString+Attributed.m in Sources */,
35663570
375D24BA21E01131007AB25A /* document.c in Sources */,
35673571
BA6DA19126DB5F1B000464C8 /* URLComponents.swift in Sources */,

Simplenote/Classes/SPTextView.m

+2-7
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,9 @@ @implementation SPTextView
2222
- (instancetype)init {
2323

2424
SPInteractiveTextStorage *textStorage = [[SPInteractiveTextStorage alloc] init];
25-
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
26-
27-
NSTextContainer *container = [[NSTextContainer alloc] initWithSize:CGSizeMake(0, CGFLOAT_MAX)];
28-
container.widthTracksTextView = YES;
29-
container.heightTracksTextView = YES;
30-
[layoutManager addTextContainer:container];
31-
[textStorage addLayoutManager:layoutManager];
3225

26+
NSTextContainer *container = [self setupTextContainerWith:textStorage];
27+
3328
self = [super initWithFrame:CGRectZero textContainer:container];
3429
if (self) {
3530
self.interactiveTextStorage = textStorage;

Simplenote/SPTextView.swift

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//
2+
// SPTextView.swift
3+
// Simplenote
4+
//
5+
// Created by Charlie Scheer on 12/19/24.
6+
// Copyright © 2024 Automattic. All rights reserved.
7+
//
8+
9+
extension SPTextView {
10+
@objc
11+
func setupTextContainer(with textStorage: SPInteractiveTextStorage) -> NSTextContainer {
12+
let container = NSTextContainer(size: .zero)
13+
container.widthTracksTextView = true
14+
container.heightTracksTextView = true
15+
16+
17+
if #available(iOS 16.0, *) {
18+
let textLayoutManager = NSTextLayoutManager()
19+
let contentStorage = NSTextContentStorage()
20+
contentStorage.delegate = self
21+
contentStorage.addTextLayoutManager(textLayoutManager)
22+
textLayoutManager.textContainer = container
23+
24+
} else {
25+
let layoutManager = NSLayoutManager()
26+
layoutManager.addTextContainer(container)
27+
textStorage.addLayoutManager(layoutManager)
28+
}
29+
30+
return container
31+
}
32+
}
33+
34+
// MARK: NSTextContentStorageDelegate
35+
//
36+
extension SPTextView: NSTextContentStorageDelegate {
37+
public func textContentStorage(_ textContentStorage: NSTextContentStorage, textParagraphWith range: NSRange) -> NSTextParagraph? {
38+
guard let originalText = textContentStorage.textStorage?.attributedSubstring(from: range) as? NSMutableAttributedString else {
39+
return nil
40+
}
41+
42+
let style = textInRangeIsHeader(range) ? headlineStyle : defaultStyle
43+
originalText.addAttributes(style, range: originalText.fullRange)
44+
45+
return NSTextParagraph(attributedString: originalText)
46+
}
47+
48+
func textInRangeIsHeader(_ range: NSRange) -> Bool {
49+
range.location == .zero
50+
}
51+
52+
// MARK: Styles
53+
//
54+
var headlineFont: UIFont {
55+
UIFont.preferredFont(for: .title1, weight: .bold)
56+
}
57+
58+
var defaultFont: UIFont {
59+
UIFont.preferredFont(forTextStyle: .body)
60+
}
61+
62+
var defaultTextColor: UIColor {
63+
UIColor.simplenoteNoteHeadlineColor
64+
}
65+
66+
var lineSpacing: CGFloat {
67+
defaultFont.lineHeight * Metrics.lineSpacingMultipler
68+
}
69+
70+
var defaultStyle: [NSAttributedString.Key: Any] {
71+
[
72+
.font: defaultFont,
73+
.foregroundColor: defaultTextColor,
74+
.paragraphStyle: NSMutableParagraphStyle(lineSpacing: lineSpacing)
75+
]
76+
}
77+
78+
var headlineStyle: [NSAttributedString.Key: Any] {
79+
[
80+
.font: headlineFont,
81+
.foregroundColor: defaultTextColor,
82+
]
83+
}
84+
}
85+
86+
// MARK: - Metrics
87+
//
88+
private enum Metrics {
89+
static let lineSpacingMultiplerPad: CGFloat = 0.40
90+
static let lineSpacingMultiplerPhone: CGFloat = 0.20
91+
92+
static var lineSpacingMultipler: CGFloat {
93+
UIDevice.isPad ? lineSpacingMultiplerPad : lineSpacingMultiplerPhone
94+
}
95+
}

0 commit comments

Comments
 (0)