Skip to content

Commit

Permalink
Refactor context styles to use a single published property
Browse files Browse the repository at this point in the history
  • Loading branch information
danielsaidi committed Feb 15, 2024
1 parent f4d7be8 commit 61c7726
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 64 deletions.
5 changes: 4 additions & 1 deletion Demo/macOS/AboutCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ struct AboutCommand: Commands {
var body: some Commands {
CommandGroup(replacing: .appInfo) {
Button("About RichTextKit") {
NSApplication.shared.orderFrontStandardAboutPanel(options: .richTextKit)
NSApplication.shared
.orderFrontStandardAboutPanel(
options: .richTextKit
)
}
}
}
Expand Down
1 change: 1 addition & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ By deprecating these functions, we can simplify the library in 1.0, and focus mo
* `RichTextCommand.StyleOptionsGroup` has been deprecated.
* `RichTextCommand.SuperscriptOptionsGroup` has been deprecated.
* `RichTextContext` replaces individual colors with a single `colors`.
* `RichTextContext` replaces individual styles with a single `styles`.
* `RichTextContext` `userActionPublisher` is renamed to `actionPublisher`.
* `RichTextCoordinator` functions calling `handle(_:)` have been deprecated.
* `RTKL10n.bundle` has been deprecated since we can use the `.module` bundle.
Expand Down
36 changes: 20 additions & 16 deletions Sources/RichTextKit/Context/RichTextContext+Styles.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,39 @@ public extension RichTextContext {
func binding(for style: RichTextStyle) -> Binding<Bool> {
Binding(
get: { Bool(self.hasStyle(style)) },
set: { self.set(style, to: $0) }
set: { self.setStyle(style, to: $0) }
)
}

/// Check whether or not the context has a certain style.
func hasStyle(_ style: RichTextStyle) -> Bool {
switch style {
case .bold: isBold
case .italic: isItalic
case .underlined: isUnderlined
case .strikethrough: isStrikethrough
}
styles[style] == true
}

/// Set whether or not the context has a certain style.
func set(
func setStyle(
_ style: RichTextStyle,
to val: Bool
) {
switch style {
case .bold: actionPublisher.send(.setStyle(.bold, val)); isBold = val
case .italic: actionPublisher.send(.setStyle(.italic, val)); isItalic = val
case .underlined: actionPublisher.send(.setStyle(.underlined, val)); isUnderlined = val
case .strikethrough: actionPublisher.send(.setStyle(.strikethrough, val)); isStrikethrough = val
}
guard styles[style] != val else { return }
actionPublisher.send(.setStyle(style, val))
setStyleInternal(style, to: val)
}

/// Toggle a certain style for the context.
func toggle(_ style: RichTextStyle) {
set(style, to: !hasStyle(style))
func toggleStyle(_ style: RichTextStyle) {
setStyle(style, to: !hasStyle(style))
}
}

extension RichTextContext {

/// Set the value for a certain color, or remove it.
func setStyleInternal(
_ style: RichTextStyle,
to val: Bool?
) {
guard let val else { return styles[style] = nil }
styles[style] = val
}
}
59 changes: 33 additions & 26 deletions Sources/RichTextKit/Context/RichTextContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,27 +75,47 @@ public class RichTextContext: ObservableObject {
public var highlightedRange: NSRange?


// MARK: - Deprecations (to avoid library warnings)
// MARK: - Deprecated Colors

@Published
@available(*, deprecated, renamed: "colors")
public internal(set) var backgroundColor: ColorRepresentable?
public var backgroundColor: ColorRepresentable? {
colors[.background]
}

@Published
@available(*, deprecated, renamed: "colors")
public internal(set) var foregroundColor: ColorRepresentable?
public var foregroundColor: ColorRepresentable? {
colors[.foreground]
}

@Published
@available(*, deprecated, renamed: "colors")
public internal(set) var strikethroughColor: ColorRepresentable?
public var strikethroughColor: ColorRepresentable? {
colors[.strikethrough]
}

@Published
@available(*, deprecated, renamed: "colors")
public internal(set) var strokeColor: ColorRepresentable?
public var strokeColor: ColorRepresentable? {
colors[.stroke]
}

@Published
@available(*, deprecated, renamed: "colors")
public internal(set) var underlineColor: ColorRepresentable?
public var underlineColor: ColorRepresentable? {
colors[.underline]
}


// MARK: - Deprecated Styles

@available(*, deprecated, renamed: "styles")
public var isBold: Bool { hasStyle(.bold) }

@available(*, deprecated, renamed: "styles")
public var isItalic: Bool { hasStyle(.italic) }

@available(*, deprecated, renamed: "styles")
public var isStrikethrough: Bool { hasStyle(.strikethrough) }

@available(*, deprecated, renamed: "styles")
public var isUnderlined: Bool { hasStyle(.underlined) }


// MARK: - Observable Properties
Expand Down Expand Up @@ -126,22 +146,9 @@ public class RichTextContext: ObservableObject {
/// The style to apply when highlighting a range.
@Published
public internal(set) var highlightingStyle = RichTextHighlightingStyle.standard

/// Whether or not the current text is bold.
@Published
public internal(set) var isBold = false

/// Whether or not the current text is italic.
@Published
public internal(set) var isItalic = false

/// Whether or not the current text is striked through.
@Published
public internal(set) var isStrikethrough = false

/// Whether or not the current text is underlined.

@Published
public internal(set) var isUnderlined = false
public internal(set) var styles = [RichTextStyle: Bool]()
}

public extension RichTextContext {
Expand Down
20 changes: 6 additions & 14 deletions Sources/RichTextKit/Coordinator/RichTextCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -237,24 +237,16 @@ extension RichTextCoordinator {
}

let isBold = styles.hasStyle(.bold)
if context.isBold != isBold {
context.isBold = isBold
}
context.setStyleInternal(.bold, to: isBold)

let isItalic = styles.hasStyle(.italic)
if context.isItalic != isItalic {
context.isItalic = isItalic
}

context.setStyleInternal(.italic, to: isItalic)

let isStrikethrough = styles.hasStyle(.strikethrough)
if context.isStrikethrough != isStrikethrough {
context.isStrikethrough = isStrikethrough
}

context.setStyleInternal(.strikethrough, to: isStrikethrough)

let isUnderlined = styles.hasStyle(.underlined)
if context.isUnderlined != isUnderlined {
context.isUnderlined = isUnderlined
}
context.setStyleInternal(.underlined, to: isUnderlined)

let isEditingText = textView.isFirstResponder
if context.isEditingText != isEditingText {
Expand Down
10 changes: 10 additions & 0 deletions Sources/RichTextKit/_Deprecated/RichTextContext+Deprecated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,14 @@ public extension RichTextContext {
)
)
}

@available(*, deprecated, renamed: "setStyle")
func set(_ style: RichTextStyle, to val: Bool) {
setStyle(style, to: val)
}

@available(*, deprecated, renamed: "toggleStyle")
func toggle(_ style: RichTextStyle) {
toggleStyle(style)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,25 +96,25 @@ final class RichTextCoordinator_SubscriptionsTests: XCTestCase {

func testIsBoldUpdatesTextView() {
XCTAssertFalse(textView.richTextStyles.hasStyle(.bold))
textContext.userActionPublisher.send(.setStyle(.bold, true))
textContext.actionPublisher.send(.setStyle(.bold, true))
XCTAssertTrue(textView.richTextStyles.hasStyle(.bold))
}

func testIsItalicUpdatesTextView() {
XCTAssertFalse(textView.richTextStyles.hasStyle(.italic))
textContext.userActionPublisher.send(.setStyle(.italic, true))
textContext.actionPublisher.send(.setStyle(.italic, true))
XCTAssertTrue(textView.richTextStyles.hasStyle(.italic))
}

func testIsUnderlinedUpdatesTextView() {
XCTAssertFalse(textView.richTextStyles.hasStyle(.underlined))
textContext.userActionPublisher.send(.setStyle(.underlined, true))
textContext.actionPublisher.send(.setStyle(.underlined, true))
XCTAssertTrue(textView.richTextStyles.hasStyle(.underlined))
}

func testIsStrikeThroughUpdatesTextView() {
XCTAssertFalse(textView.richTextStyles.hasStyle(.strikethrough))
textContext.userActionPublisher.send(.setStyle(.strikethrough, true))
textContext.actionPublisher.send(.setStyle(.strikethrough, true))
XCTAssertTrue(textView.richTextStyles.hasStyle(.strikethrough))
}

Expand Down
6 changes: 3 additions & 3 deletions Tests/RichTextKitTests/RichTextCoordinatorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ final class RichTextCoordinatorTests: XCTestCase {
let styles = view.richTextStyles
XCTAssertEqual(context.fontName, view.richTextFont?.fontName)
XCTAssertEqual(context.fontSize, view.richTextFont?.pointSize)
XCTAssertEqual(context.isBold, styles.hasStyle(.bold))
XCTAssertEqual(context.isItalic, styles.hasStyle(.italic))
XCTAssertEqual(context.isUnderlined, styles.hasStyle(.underlined))
XCTAssertEqual(context.styles[.bold], styles.hasStyle(.bold))
XCTAssertEqual(context.styles[.italic], styles.hasStyle(.italic))
XCTAssertEqual(context.styles[.underlined], styles.hasStyle(.underlined))
XCTAssertEqual(context.selectedRange, view.selectedRange)
#if iOS || os(tvOS)
XCTAssertEqual(context.textAlignment, view.richTextAlignment)
Expand Down

0 comments on commit 61c7726

Please sign in to comment.