Skip to content

Commit

Permalink
Introduced EditorViewContext.selectedEditorView to get currently sele…
Browse files Browse the repository at this point in the history
…cted EditorView (#203)
  • Loading branch information
rajdeep authored Jul 21, 2023
1 parent ba0ae71 commit 6816cf4
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 4 deletions.
11 changes: 7 additions & 4 deletions Proton/Sources/Swift/Core/RichTextEditorContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ class RichTextEditorContext: RichTextViewContext {

func textViewDidBeginEditing(_ textView: UITextView) {
guard textView.delegate === self else { return }
selectedTextView = textView.asRichTextView
activeTextView = textView.asRichTextView

activeTextView = textView as? RichTextView
guard let richTextView = activeTextView else { return }

let range = richTextView.selectedRange
Expand All @@ -51,6 +52,7 @@ class RichTextEditorContext: RichTextViewContext {

defer {
activeTextView = nil
selectedTextView = nil
}
guard let richTextView = activeTextView else { return }
richTextView.richTextViewDelegate?.richTextView(richTextView, didLoseFocusFrom: textView.selectedRange)
Expand Down Expand Up @@ -150,9 +152,10 @@ class RichTextEditorContext: RichTextViewContext {
}

func textViewDidChange(_ textView: UITextView) {
guard textView.delegate === self,
let richTextView = activeTextView
else { return }
guard textView.delegate === self else { return }
selectedTextView = textView.asRichTextView

guard let richTextView = activeTextView else { return }

applyFontFixForEmojiIfRequired(in: richTextView, at: textView.selectedRange)
invokeDidProcessIfRequired(richTextView)
Expand Down
5 changes: 5 additions & 0 deletions Proton/Sources/Swift/Core/RichTextView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ class RichTextView: AutogrowingTextView {
selectedTextRange = rangeToSet?.toTextRange(textInput: self) ?? oldRange
}

var context: RichTextViewContext? {
delegate as? RichTextViewContext
}

init(frame: CGRect = .zero, context: RichTextViewContext, allowAutogrowing: Bool = false) {
let textContainer = TextContainer()
let layoutManager = LayoutManager()
Expand Down Expand Up @@ -498,6 +502,7 @@ class RichTextView: AutogrowingTextView {
}

func didTap(at location: CGPoint) {
context?.selectedTextView = self
let characterRange = rangeOfCharacter(at: location)
richTextViewDelegate?.richTextView(self, didTapAtLocation: location, characterRange: characterRange)
}
Expand Down
13 changes: 13 additions & 0 deletions Proton/Sources/Swift/Core/RichTextViewContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,19 @@ import UIKit
class RichTextViewContext: NSObject, UITextViewDelegate {
weak var activeTextView: RichTextView?

weak var selectedTextView: RichTextView?

func textView(_ textView: UITextView, shouldInteractWith textAttachment: NSTextAttachment, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
return interaction != .presentActions
}

func textViewDidChangeSelection(_ textView: UITextView) {
guard textView.delegate === self else { return }
if textView.selectedTextRange != nil {
selectedTextView = textView.asRichTextView
} else {
selectedTextView = nil
}

guard let richTextView = textView as? RichTextView else { return }
let range = textView.selectedRange
Expand Down Expand Up @@ -72,3 +79,9 @@ class RichTextViewContext: NSObject, UITextViewDelegate {
}
}
}

extension UITextView {
var asRichTextView: RichTextView? {
self as? RichTextView
}
}
8 changes: 8 additions & 0 deletions Proton/Sources/Swift/Editor/EditorViewContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ public class EditorViewContext {
return richTextViewContext.activeTextView?.editorView
}

/// `EditorView` for this context that is currently selected. An editor is selected when in any of the following states even if it is read-only:
/// * Gets focus
/// * Selected range is changed to non-nil value
/// * Is tapped on
public var selectedEditorView: EditorView? {
richTextViewContext.selectedTextView?.editorView
}

/// Initializes a new context
/// - Parameter name: Friendly name for the context.
public convenience init(name: String) {
Expand Down
64 changes: 64 additions & 0 deletions Proton/Tests/Core/RichTextViewContextTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -220,4 +220,68 @@ class RichTextViewContextTests: XCTestCase {

waitForExpectations(timeout: 1.0)
}

func testSetsSelectedEditorOnTextRangeChange() {
let testExpectation = expectation(description: #function)
let mockTextViewDelegate = MockRichTextViewDelegate()

let context = RichTextEditorContext.default
let textView = RichTextView(context: context)
textView.richTextViewDelegate = mockTextViewDelegate

textView.text = "Sample text"
textView.selectedRange = .zero

mockTextViewDelegate.onSelectionChanged = { _, _, _, _ in
XCTAssertEqual(context.selectedTextView, textView)
testExpectation.fulfill()
}

context.textViewDidChangeSelection(textView)

waitForExpectations(timeout: 1.0)
}

func testUnsetsSelectedEditorOnTextRangeNil() {
let testExpectation = expectation(description: #function)
let mockTextViewDelegate = MockRichTextViewDelegate()

let context = RichTextEditorContext.default
let textView = RichTextView(context: context)
textView.richTextViewDelegate = mockTextViewDelegate

textView.text = "Sample text"
textView.selectedTextRange = nil

mockTextViewDelegate.onSelectionChanged = { _, _, _, _ in
XCTAssertNil(context.selectedTextView)
testExpectation.fulfill()
}

context.textViewDidChangeSelection(textView)

waitForExpectations(timeout: 1.0)
}

func testSetsSelectedEditorOnTap() {
let testExpectation = expectation(description: #function)
let mockTextViewDelegate = MockRichTextViewDelegate()

let context = RichTextEditorContext.default
let textView = RichTextView(context: context)
textView.richTextViewDelegate = mockTextViewDelegate

textView.text = "Sample text"
textView.selectedTextRange = nil

mockTextViewDelegate.onDidTapAtLocation = { _, _, _ in
XCTAssertEqual(context.selectedTextView, textView)
testExpectation.fulfill()
}

textView.didTap(at: .zero)

waitForExpectations(timeout: 1.0)
}

}

0 comments on commit 6816cf4

Please sign in to comment.