Skip to content

Commit

Permalink
Merge branch 'main' into native-editor-lists-actions
Browse files Browse the repository at this point in the history
  • Loading branch information
tonisevener committed Jan 8, 2024
2 parents 6b1f356 + 141ec7f commit 8813839
Show file tree
Hide file tree
Showing 71 changed files with 1,526 additions and 133 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ class WKEditorToolbarGroupedView: WKEditorToolbarView {
}

// MARK: - Notifications

@objc private func updateButtonSelectionState(_ notification: NSNotification) {
guard let selectionState = notification.userInfo?[Notification.WKSourceEditorSelectionStateKey] as? WKSourceEditorSelectionState else {
return
}

unorderedListButton.isSelected = selectionState.isBulletSingleList || selectionState.isBulletMultipleList
unorderedListButton.isEnabled = !selectionState.isNumberSingleList && !selectionState.isNumberMultipleList

Expand All @@ -83,6 +83,8 @@ class WKEditorToolbarGroupedView: WKEditorToolbarView {
} else {
increaseIndentButton.isEnabled = false
}

strikethroughButton.isSelected = selectionState.isStrikethrough
}

// MARK: - Button Actions
Expand Down Expand Up @@ -113,6 +115,7 @@ class WKEditorToolbarGroupedView: WKEditorToolbarView {
}

@objc private func tappedStrikethrough() {
delegate?.didTapStrikethrough(isSelected: strikethroughButton.isSelected)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ protocol WKEditorInputViewDelegate: AnyObject {
func didTapNumberList(isSelected: Bool)
func didTapIncreaseIndent()
func didTapDecreaseIndent()
func didTapStrikethrough(isSelected: Bool)
}

class WKEditorInputViewController: WKComponentViewController {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Foundation
import ComponentsObjC

extension WKSourceEditorFormatterStrikethrough {
func toggleStrikethroughFormatting(action: WKSourceEditorFormatterButtonAction, in textView: UITextView) {
toggleFormatting(startingFormattingString: "<s>", endingFormattingString: "</s>", action: action, in: textView)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,17 @@ fileprivate var needsTextKit2: Bool {
let isBulletMultipleList: Bool
let isNumberSingleList: Bool
let isNumberMultipleList: Bool
let isStrikethrough: Bool

init(isBold: Bool, isItalics: Bool, isHorizontalTemplate: Bool, isBulletSingleList: Bool, isBulletMultipleList: Bool, isNumberSingleList: Bool, isNumberMultipleList: Bool) {
init(isBold: Bool, isItalics: Bool, isHorizontalTemplate: Bool, isBulletSingleList: Bool, isBulletMultipleList: Bool, isNumberSingleList: Bool, isNumberMultipleList: Bool, isStrikethrough: Bool) {
self.isBold = isBold
self.isItalics = isItalics
self.isHorizontalTemplate = isHorizontalTemplate
self.isBulletSingleList = isBulletSingleList
self.isBulletMultipleList = isBulletMultipleList
self.isNumberSingleList = isNumberSingleList
self.isNumberMultipleList = isNumberMultipleList
self.isStrikethrough = isStrikethrough
}
}

Expand All @@ -44,6 +46,7 @@ final class WKSourceEditorTextFrameworkMediator: NSObject {
private(set) var boldItalicsFormatter: WKSourceEditorFormatterBoldItalics?
private(set) var templateFormatter: WKSourceEditorFormatterTemplate?
private(set) var listFormatter: WKSourceEditorFormatterList?
private(set) var strikethroughFormatter: WKSourceEditorFormatterStrikethrough?

var isSyntaxHighlightingEnabled: Bool = true {
didSet {
Expand Down Expand Up @@ -110,16 +113,15 @@ final class WKSourceEditorTextFrameworkMediator: NSObject {
let colors = self.colors
let fonts = self.fonts

let boldItalicsFormatter = WKSourceEditorFormatterBoldItalics(colors: colors, fonts: fonts)
let templateFormatter = WKSourceEditorFormatterTemplate(colors: colors, fonts: fonts)
let boldItalicsFormatter = WKSourceEditorFormatterBoldItalics(colors: colors, fonts: fonts)
let listFormatter = WKSourceEditorFormatterList(colors: colors, fonts: fonts)
let strikethroughFormatter = WKSourceEditorFormatterStrikethrough(colors: colors, fonts: fonts)
self.formatters = [WKSourceEditorFormatterBase(colors: colors, fonts: fonts, textAlignment: viewModel.textAlignment),
templateFormatter,
boldItalicsFormatter,
listFormatter]
self.boldItalicsFormatter = boldItalicsFormatter
self.templateFormatter = templateFormatter
self.listFormatter = listFormatter
listFormatter,
strikethroughFormatter]

if needsTextKit2 {
if #available(iOS 16.0, *) {
Expand Down Expand Up @@ -159,7 +161,7 @@ final class WKSourceEditorTextFrameworkMediator: NSObject {

if needsTextKit2 {
guard let textKit2Data = textkit2SelectionData(selectedDocumentRange: selectedDocumentRange) else {
return WKSourceEditorSelectionState(isBold: false, isItalics: false, isHorizontalTemplate: false, isBulletSingleList: false, isBulletMultipleList: false, isNumberSingleList: false, isNumberMultipleList: false)
return WKSourceEditorSelectionState(isBold: false, isItalics: false, isHorizontalTemplate: false, isBulletSingleList: false, isBulletMultipleList: false, isNumberSingleList: false, isNumberMultipleList: false, isStrikethrough: false)
}

let isBold = boldItalicsFormatter?.attributedString(textKit2Data.paragraphAttributedString, isBoldIn: textKit2Data.paragraphSelectedRange) ?? false
Expand All @@ -169,11 +171,12 @@ final class WKSourceEditorTextFrameworkMediator: NSObject {
let isBulletMultipleList = listFormatter?.attributedString(textKit2Data.paragraphAttributedString, isBulletMultipleIn: textKit2Data.paragraphSelectedRange) ?? false
let isNumberSingleList = listFormatter?.attributedString(textKit2Data.paragraphAttributedString, isNumberSingleIn: textKit2Data.paragraphSelectedRange) ?? false
let isNumberMultipleList = listFormatter?.attributedString(textKit2Data.paragraphAttributedString, isNumberMultipleIn: textKit2Data.paragraphSelectedRange) ?? false
let isStrikethrough = strikethroughFormatter?.attributedString(textKit2Data.paragraphAttributedString, isStrikethroughIn: textKit2Data.paragraphSelectedRange) ?? false

return WKSourceEditorSelectionState(isBold: isBold, isItalics: isItalics, isHorizontalTemplate: isHorizontalTemplate, isBulletSingleList: isBulletSingleList, isBulletMultipleList: isBulletMultipleList, isNumberSingleList: isNumberSingleList, isNumberMultipleList: isNumberMultipleList)
return WKSourceEditorSelectionState(isBold: isBold, isItalics: isItalics, isHorizontalTemplate: isHorizontalTemplate, isBulletSingleList: isBulletSingleList, isBulletMultipleList: isBulletMultipleList, isNumberSingleList: isNumberSingleList, isNumberMultipleList: isNumberMultipleList, isStrikethrough: isStrikethrough)
} else {
guard let textKit1Storage else {
return WKSourceEditorSelectionState(isBold: false, isItalics: false, isHorizontalTemplate: false, isBulletSingleList: false, isBulletMultipleList: false, isNumberSingleList: false, isNumberMultipleList: false)
return WKSourceEditorSelectionState(isBold: false, isItalics: false, isHorizontalTemplate: false, isBulletSingleList: false, isBulletMultipleList: false, isNumberSingleList: false, isNumberMultipleList: false, isStrikethrough: false)
}

let isBold = boldItalicsFormatter?.attributedString(textKit1Storage, isBoldIn: selectedDocumentRange) ?? false
Expand All @@ -183,8 +186,9 @@ final class WKSourceEditorTextFrameworkMediator: NSObject {
let isBulletMultipleList = listFormatter?.attributedString(textKit1Storage, isBulletMultipleIn: selectedDocumentRange) ?? false
let isNumberSingleList = listFormatter?.attributedString(textKit1Storage, isNumberSingleIn: selectedDocumentRange) ?? false
let isNumberMultipleList = listFormatter?.attributedString(textKit1Storage, isNumberMultipleIn: selectedDocumentRange) ?? false
let isStrikethrough = strikethroughFormatter?.attributedString(textKit1Storage, isStrikethroughIn: selectedDocumentRange) ?? false

return WKSourceEditorSelectionState(isBold: isBold, isItalics: isItalics, isHorizontalTemplate: isHorizontalTemplate, isBulletSingleList: isBulletSingleList, isBulletMultipleList: isBulletMultipleList, isNumberSingleList: isNumberSingleList, isNumberMultipleList: isNumberMultipleList)
return WKSourceEditorSelectionState(isBold: isBold, isItalics: isItalics, isHorizontalTemplate: isHorizontalTemplate, isBulletSingleList: isBulletSingleList, isBulletMultipleList: isBulletMultipleList, isNumberSingleList: isNumberSingleList, isNumberMultipleList: isNumberMultipleList, isStrikethrough: isStrikethrough)
}
}

Expand Down Expand Up @@ -221,6 +225,7 @@ extension WKSourceEditorTextFrameworkMediator: WKSourceEditorStorageDelegate {
colors.baseForegroundColor = WKAppEnvironment.current.theme.text
colors.orangeForegroundColor = isSyntaxHighlightingEnabled ? WKAppEnvironment.current.theme.editorOrange : WKAppEnvironment.current.theme.text
colors.purpleForegroundColor = isSyntaxHighlightingEnabled ? WKAppEnvironment.current.theme.editorPurple : WKAppEnvironment.current.theme.text
colors.greenForegroundColor = isSyntaxHighlightingEnabled ? WKAppEnvironment.current.theme.editorGreen : WKAppEnvironment.current.theme.text
return colors
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,11 @@ extension WKSourceEditorViewController: WKEditorInputViewDelegate {
textFrameworkMediator.listFormatter?.tappedDecreaseIndent(currentSelectionState: selectionState(), textView: textView)
}

func didTapStrikethrough(isSelected: Bool) {
let action: WKSourceEditorFormatterButtonAction = isSelected ? .remove : .add
textFrameworkMediator.strikethroughFormatter?.toggleStrikethroughFormatting(action: action, in: textView)
}

func didTapClose() {
inputViewType = nil
let isRangeSelected = textView.selectedRange.length > 0
Expand Down
13 changes: 9 additions & 4 deletions Components/Sources/Components/Style/WKTheme.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public struct WKTheme: Equatable {
public let diffCompareAccent: UIColor
public let editorOrange: UIColor
public let editorPurple: UIColor
public let editorGreen: UIColor

public static let light = WKTheme(
name: "Light",
Expand All @@ -50,7 +51,8 @@ public struct WKTheme: Equatable {
keyboardBarSearchFieldBackground: WKColor.gray200,
diffCompareAccent: WKColor.orange600,
editorOrange: WKColor.orange600,
editorPurple: WKColor.purple600
editorPurple: WKColor.purple600,
editorGreen: WKColor.green600
)

public static let sepia = WKTheme(
Expand All @@ -76,7 +78,8 @@ public struct WKTheme: Equatable {
keyboardBarSearchFieldBackground: WKColor.gray200,
diffCompareAccent: WKColor.orange600,
editorOrange: WKColor.orange600,
editorPurple: WKColor.purple600
editorPurple: WKColor.purple600,
editorGreen: WKColor.green600
)

public static let dark = WKTheme(
Expand All @@ -102,7 +105,8 @@ public struct WKTheme: Equatable {
keyboardBarSearchFieldBackground: WKColor.gray650,
diffCompareAccent: WKColor.orange600,
editorOrange: WKColor.yellow600,
editorPurple: WKColor.red100
editorPurple: WKColor.red100,
editorGreen: WKColor.green600
)

public static let black = WKTheme(
Expand All @@ -128,7 +132,8 @@ public struct WKTheme: Equatable {
keyboardBarSearchFieldBackground: WKColor.gray650,
diffCompareAccent: WKColor.orange600,
editorOrange: WKColor.yellow600,
editorPurple: WKColor.red100
editorPurple: WKColor.red100,
editorGreen: WKColor.green600
)

}
1 change: 1 addition & 0 deletions Components/Sources/ComponentsObjC/WKSourceEditorColors.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, strong) UIColor *baseForegroundColor;
@property (nonatomic, strong) UIColor *orangeForegroundColor;
@property (nonatomic, strong) UIColor *purpleForegroundColor;
@property (nonatomic, strong) UIColor *greenForegroundColor;
@end

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface WKSourceEditorFormatter : NSObject

extern NSString *const WKSourceEditorCustomKeyColorOrange;
extern NSString *const WKSourceEditorCustomKeyColorGreen;

- (instancetype)initWithColors:(nonnull WKSourceEditorColors *)colors fonts:(nonnull WKSourceEditorFonts *)fonts;
- (void)addSyntaxHighlightingToAttributedString:(NSMutableAttributedString *)attributedString inRange:(NSRange)range;
Expand Down
2 changes: 2 additions & 0 deletions Components/Sources/ComponentsObjC/WKSourceEditorFormatter.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
@implementation WKSourceEditorFormatter

#pragma mark - Common Custom Attributed String Keys

// Font and Color custom attributes allow us to easily target already-formatted ranges. This is handy for speedy updates upon theme and text size change, as well as determining keyboard button selection states.
NSString * const WKSourceEditorCustomKeyColorOrange = @"WKSourceEditorKeyColorOrange";
NSString * const WKSourceEditorCustomKeyColorGreen = @"WKSourceEditorKeyColorGreen";

- (nonnull instancetype)initWithColors:(nonnull WKSourceEditorColors *)colors fonts:(nonnull WKSourceEditorFonts *)fonts {
self = [super init];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,13 @@ - (instancetype)initWithColors:(nonnull WKSourceEditorColors *)colors fonts:(non

- (void)addSyntaxHighlightingToAttributedString:(NSMutableAttributedString *)attributedString inRange:(NSRange)range {

// reset old attributes
// reset base attributes
[attributedString removeAttribute:NSFontAttributeName range:range];
[attributedString removeAttribute:NSForegroundColorAttributeName range:range];

// reset shared custom attributes
[attributedString removeAttribute:WKSourceEditorCustomKeyColorGreen range:range];

[attributedString addAttributes:self.attributes range:range];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,54 +275,56 @@ - (void)updateFonts:(WKSourceEditorFonts *)fonts inAttributedString:(NSMutableAt
#pragma mark - Public

- (BOOL)attributedString:(NSMutableAttributedString *)attributedString isBoldInRange:(NSRange)range {
__block BOOL isBold = NO;
if (range.length == 0) {

if (attributedString.length > range.location) {
NSDictionary<NSAttributedStringKey,id> *attrs = [attributedString attributesAtIndex:range.location effectiveRange:nil];

if (attrs[WKSourceEditorCustomKeyFontBoldItalics] != nil || attrs[WKSourceEditorCustomKeyFontBold] != nil) {
isBold = YES;
}
}

} else {
[attributedString enumerateAttributesInRange:range options:nil usingBlock:^(NSDictionary<NSAttributedStringKey,id> * _Nonnull attrs, NSRange loopRange, BOOL * _Nonnull stop) {
if ((attrs[WKSourceEditorCustomKeyFontBoldItalics] != nil || attrs[WKSourceEditorCustomKeyFontBold] != nil) &&
(loopRange.location == range.location && loopRange.length == range.length)) {
isBold = YES;
stop = YES;
}
}];
}


return isBold;
return [self attributedString:attributedString isFormattedInRange:range formattingKey:WKSourceEditorCustomKeyFontBold];
}

- (BOOL)attributedString:(NSMutableAttributedString *)attributedString isItalicsInRange:(NSRange)range {
__block BOOL isItalics = NO;
return [self attributedString:attributedString isFormattedInRange:range formattingKey:WKSourceEditorCustomKeyFontItalics];
}

#pragma mark - Private

- (BOOL)attributedString:(NSMutableAttributedString *)attributedString isFormattedInRange:(NSRange)range formattingKey: (NSString *)formattingKey {
__block BOOL isFormatted = NO;

if (range.length == 0) {

if (attributedString.length > range.location) {
NSDictionary<NSAttributedStringKey,id> *attrs = [attributedString attributesAtIndex:range.location effectiveRange:nil];

if (attrs[WKSourceEditorCustomKeyFontBoldItalics] != nil || attrs[WKSourceEditorCustomKeyFontItalics] != nil) {
isItalics = YES;
isFormatted = YES;
} else {
// Edge case, check previous character if we are up against a closing bold or italic
if (attrs[WKSourceEditorCustomKeyColorOrange]) {
attrs = [attributedString attributesAtIndex:range.location - 1 effectiveRange:nil];
if (attrs[WKSourceEditorCustomKeyFontBold] != nil || attrs[WKSourceEditorCustomKeyFontItalics] != nil) {
isFormatted = YES;
}
}
}
}

} else {

__block NSRange unionRange = NSMakeRange(NSNotFound, 0);
[attributedString enumerateAttributesInRange:range options:nil usingBlock:^(NSDictionary<NSAttributedStringKey,id> * _Nonnull attrs, NSRange loopRange, BOOL * _Nonnull stop) {
if ((attrs[WKSourceEditorCustomKeyFontBoldItalics] != nil || attrs[WKSourceEditorCustomKeyFontItalics] != nil) &&
(loopRange.location == range.location && loopRange.length == range.length)) {
isItalics = YES;
if (attrs[WKSourceEditorCustomKeyFontBoldItalics] != nil || attrs[formattingKey] != nil) {
if (unionRange.location == NSNotFound) {
unionRange = loopRange;
} else {
unionRange = NSUnionRange(unionRange, loopRange);
}
stop = YES;
}
}];

if (NSEqualRanges(unionRange, range)) {
isFormatted = YES;
}
}

return isItalics;
return isFormatted;
}

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#import "WKSourceEditorFormatter.h"

NS_ASSUME_NONNULL_BEGIN

@interface WKSourceEditorFormatterStrikethrough : WKSourceEditorFormatter

- (BOOL)attributedString:(NSMutableAttributedString *)attributedString isStrikethroughInRange:(NSRange)range;

@end

NS_ASSUME_NONNULL_END
Loading

0 comments on commit 8813839

Please sign in to comment.