Skip to content

Commit

Permalink
Added option to provide custom editor initializer at gridview level (#…
Browse files Browse the repository at this point in the history
…256)

* Added option to provide custom editor initializer at gridview level

* Fixed Sample app
  • Loading branch information
rajdeep authored Nov 28, 2023
1 parent d306fb1 commit bfbb7c4
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 60 deletions.
2 changes: 1 addition & 1 deletion ExampleApp/ExampleApp/Commands/CreateGridViewCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public class CreateGridViewCommand: EditorCommand {
editor.attributedText = NSAttributedString(string: "Table \(id) {\(row), \(col)} Text in cell")
return editor
}
let cell = GridCell(editorInitializer: editorInit, rowSpan: [row], columnSpan: [col], initialHeight: 20)
let cell = GridCell(rowSpan: [row], columnSpan: [col], initialHeight: 20, editorInitializer: editorInit)
cells.append(cell)
}
}
Expand Down
15 changes: 11 additions & 4 deletions Proton/Sources/Swift/Grid/Core/Grid.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,13 @@ class Grid {

private let config: GridConfiguration
private let cellStore: GridCellStore
private let editorInitializer: GridCell.EditorInitializer?

var rowHeights = [GridRowDimension]()
var columnWidths = [GridColumnDimension]()
weak var delegate: GridDelegate?


var currentRowHeights: [CGFloat] {
rowHeights.map { $0.calculatedHeight }
}
Expand All @@ -70,8 +72,9 @@ class Grid {
rowHeights.count
}

init(config: GridConfiguration, cells: [GridCell]) {
init(config: GridConfiguration, cells: [GridCell], editorInitializer: GridCell.EditorInitializer? = nil) {
self.config = config
self.editorInitializer = editorInitializer

for column in config.columnsConfiguration {
self.columnWidths.append(GridColumnDimension(width: column.width, collapsedWidth: config.collapsedColumnWidth))
Expand Down Expand Up @@ -216,7 +219,8 @@ class Grid {
rowSpan: [row],
columnSpan: [col],
initialHeight: cell.initialHeight,
ignoresOptimizedInit: true
ignoresOptimizedInit: true,
editorInitializer: editorInitializer
)
c.delegate = cell.delegate
newCells.append(c)
Expand Down Expand Up @@ -256,7 +260,8 @@ class Grid {
rowSpan: [sanitizedIndex],
columnSpan: [c],
initialHeight: config.initialHeight,
style: config.style)
style: config.style,
editorInitializer: editorInitializer)

if cellAt(rowIndex: sanitizedIndex, columnIndex: c) != nil {
continue
Expand Down Expand Up @@ -293,7 +298,9 @@ class Grid {
rowSpan: [r],
columnSpan: [sanitizedIndex],
initialHeight: rowHeights[r].rowConfiguration.initialHeight,
style: config.style)
style: config.style,
editorInitializer: editorInitializer
)

if cellAt(rowIndex: r, columnIndex: sanitizedIndex) != nil {
continue
Expand Down
28 changes: 5 additions & 23 deletions Proton/Sources/Swift/Grid/View/GridCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -182,29 +182,28 @@ open class GridCell {

let initialHeight: CGFloat


/// Initializes the cell
/// - Parameters:
/// - editorInitializer: Closure for setting up the `EditorView` within the cell. I
/// - rowSpan: Array of row indexes the cells spans. For e.g. a cell with first two rows as merged, will have a value of [0, 1] denoting 0th and 1st index.
/// - columnSpan: Array of column indexes the cells spans. For e.g. a cell with first two columns as merged, will have a value of [0, 1] denoting 0th and 1st index.
/// - initialHeight: Initial height of the cell. This will be updated based on size of editor content on load,
/// - style: Visual style of the cell
/// - gridStyle: Visual style for grid containing cell border color and width
/// - ignoresOptimizedInit: Ignores optimization to initialize editor within the cell. With optimization, the editor is not initialized until the cell is ready to be rendered on the UI thereby not incurring any overheads when creating
/// attributedText containing a `GridView` in an attachment. Defaults to `false`.
/// - editorInitializer: Closure for setting up the `EditorView` within the cell.
/// - Important:
/// Creating a `GridView` with 100s of cells can result in slow performance when creating an attributed string containing the GridView attachment. Using the closure defers the creation until the view is ready to be rendered in the UI.
/// It is recommended to setup all the parts of editor in closure where possible, or wait until after the GridView is rendered. In case, editor must be initialized before the rendering is complete and it is not possible to configure an aspect within the closure itself,
/// `setupEditor()` may be invoked. Use of `setupEditor()` is discouraged.
public init(editorInitializer: @escaping EditorInitializer,
rowSpan: [Int],
public init(rowSpan: [Int],
columnSpan: [Int],
initialHeight: CGFloat = 40,
style: GridCellStyle = .init(),
gridStyle: GridStyle = .default,
ignoresOptimizedInit: Bool = false) {
self.editorInitializer = editorInitializer
ignoresOptimizedInit: Bool = false,
editorInitializer: EditorInitializer? = nil) {
self.editorInitializer = editorInitializer ?? { EditorView(allowAutogrowing: false) }
self.rowSpan = rowSpan
self.columnSpan = columnSpan
self.gridStyle = gridStyle
Expand All @@ -228,23 +227,6 @@ open class GridCell {
setup()
}

public convenience init(rowSpan: [Int],
columnSpan: [Int],
initialHeight: CGFloat = 40,
style: GridCellStyle = .init(),
gridStyle: GridStyle = .default,
ignoresOptimizedInit: Bool = true) {
self.init(
editorInitializer: { EditorView(allowAutogrowing: false) },
rowSpan: rowSpan,
columnSpan: columnSpan,
initialHeight: initialHeight,
style: style,
gridStyle: gridStyle,
ignoresOptimizedInit: ignoresOptimizedInit
)
}

/// Sets the focus in the `Editor` within the cell.
public func setFocus() {
editor.setFocus()
Expand Down
18 changes: 11 additions & 7 deletions Proton/Sources/Swift/Grid/View/GridContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,16 @@ class GridContentView: UIScrollView {
grid.columnWidths
}

init(config: GridConfiguration, cells: [GridCell]) {
init(config: GridConfiguration, cells: [GridCell], editorInitializer: GridCell.EditorInitializer?) {
self.config = config
grid = Grid(config: config, cells: cells)
grid = Grid(config: config, cells: cells, editorInitializer: editorInitializer)
super.init(frame: .zero)
grid.delegate = self
}

convenience init(config: GridConfiguration) {
let cells = Self.generateCells(config: config)
self.init(config: config, cells: cells)
convenience init(config: GridConfiguration, editorInitializer: GridCell.EditorInitializer?) {
let cells = Self.generateCells(config: config, editorInitializer: editorInitializer)
self.init(config: config, cells: cells, editorInitializer: editorInitializer)
}

required init?(coder: NSCoder) {
Expand Down Expand Up @@ -374,7 +374,10 @@ class GridContentView: UIScrollView {
}
}

private static func generateCells(config: GridConfiguration) -> [GridCell] {
private static func generateCells(
config: GridConfiguration,
editorInitializer: GridCell.EditorInitializer?
) -> [GridCell] {
var cells = [GridCell]()
for row in 0..<config.numberOfRows {
let rowStyle = config.rowsConfiguration[row].style
Expand All @@ -389,7 +392,8 @@ class GridContentView: UIScrollView {
initialHeight: initialHeight,
style: mergedStyle,
gridStyle: config.style,
ignoresOptimizedInit: config.ignoresOptimizedInit
ignoresOptimizedInit: config.ignoresOptimizedInit,
editorInitializer: editorInitializer
)
cells.append(cell)
}
Expand Down
21 changes: 16 additions & 5 deletions Proton/Sources/Swift/Grid/View/GridView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -209,14 +209,25 @@ public class GridView: UIView {
}

/// Initializes `GridView` using the provided configuration.
/// - Parameter config: Configuration for `GridView`
public convenience init(config: GridConfiguration) {
let gridView = GridContentView(config: config)
/// - Parameter
/// - config: Configuration for `GridView`
/// - cellEditorInitializer: Custom initializer for `EditorView` within `GridCell`. This will also be used when creating new cells as a
/// return of adding new row or column, or cells being split.
public convenience init(config: GridConfiguration, cellEditorInitializer: GridCell.EditorInitializer? = nil) {
let gridView = GridContentView(config: config, editorInitializer: cellEditorInitializer)
self.init(config: config, gridView: gridView)
}

public convenience init(config: GridConfiguration, cells: [GridCell]) {
let gridView = GridContentView(config: config, cells: cells)
/// Initializes `GridView` using the provided configuration.
/// - Parameters:
/// - config: Configuration for `GridView`
/// - cells: Cells contained within `GridView`
/// - cellEditorInitializer: Custom initializer for `EditorView` within `GridCell`. This will also be used when creating new cells as a
/// return of adding new row or column, or cells being split.
/// - Important:
/// Care must be taken that the number of cells are correct per the configuration provided, failing which the `GridView` rendering may be broken.
public convenience init(config: GridConfiguration, cells: [GridCell], cellEditorInitializer: GridCell.EditorInitializer? = nil) {
let gridView = GridContentView(config: config, cells: cells, editorInitializer: cellEditorInitializer)
self.init(config: config, gridView: gridView)
}

Expand Down
82 changes: 62 additions & 20 deletions Proton/Tests/Grid/GridTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,26 +51,6 @@ class GridTests: XCTestCase {
}
}

func testSome() throws {
let config = GridConfiguration(
columnsConfiguration: [
GridColumnConfiguration(width: .fixed(100)),
GridColumnConfiguration(width: .fixed(100)),
],
rowsConfiguration: [
GridRowConfiguration(initialHeight: 50),
GridRowConfiguration(initialHeight: 50),
GridRowConfiguration(initialHeight: 50),
])

let grid = Grid(config: config, cells: generateCells(config: config))
let cell00 = try XCTUnwrap(grid.cellAt(rowIndex: 0, columnIndex: 0))
let cell01 = try XCTUnwrap(grid.cellAt(rowIndex: 1, columnIndex: 0))

print(grid.frameForCell(cell00, basedOn: CGSize(width: 300, height: 300)))
print(grid.frameForCell(cell01, basedOn: CGSize(width: 300, height: 300)))
}

func testGetsFrameForCell() {
let config = GridConfiguration(
columnsConfiguration: [
Expand Down Expand Up @@ -237,6 +217,36 @@ class GridTests: XCTestCase {
waitForExpectations(timeout: 1.0)
}

func testInsertRowUsesCustomEditorInit() {
let expectation = functionExpectation()

let config = GridConfiguration(
columnsConfiguration: [
GridColumnConfiguration(width: .fractional(0.25)),
GridColumnConfiguration(width: .fixed(100.0)),
GridColumnConfiguration(width: .fractional(0.50)),
],
rowsConfiguration: [
GridRowConfiguration(initialHeight: 50),
GridRowConfiguration(initialHeight: 50),
GridRowConfiguration(initialHeight: 50),
])

expectation.expectedFulfillmentCount = config.numberOfColumns

let editorInit = {
expectation.fulfill()
return EditorView(frame: .zero)
}

let grid = Grid(config: config, cells: generateCells(config: config), editorInitializer: editorInit)
grid.insertRow(at: 1, frozenRowMaxIndex: nil, config: GridRowConfiguration(initialHeight: 20), cellDelegate: nil)
let newCells = grid.cells.filter { $0.rowSpan.contains(1) }
newCells.forEach { _ = $0.editor }

waitForExpectations(timeout: 1.0)
}

func testInsertColumn() {
let expectation = functionExpectation()
expectation.expectedFulfillmentCount = 3
Expand Down Expand Up @@ -276,6 +286,38 @@ class GridTests: XCTestCase {
waitForExpectations(timeout: 1.0)
}

func testInsertColumnUsesCustomEditorInit() {
let expectation = functionExpectation()
expectation.expectedFulfillmentCount = 3

let config = GridConfiguration(
columnsConfiguration: [
GridColumnConfiguration(width: .fractional(0.25)),
GridColumnConfiguration(width: .fixed(100.0)),
GridColumnConfiguration(width: .fractional(0.50)),
],
rowsConfiguration: [
GridRowConfiguration(initialHeight: 30),
GridRowConfiguration(initialHeight: 40),
GridRowConfiguration(initialHeight: 50),
])

expectation.expectedFulfillmentCount = config.numberOfColumns

let editorInit = {
expectation.fulfill()
return EditorView(frame: .zero)
}

let grid = Grid(config: config, cells: generateCells(config: config), editorInitializer: editorInit)
grid.insertColumn(at: 1, frozenColumnMaxIndex: nil, config: GridColumnConfiguration(width: .fractional(0.30)), cellDelegate: nil)
XCTAssertEqual(grid.numberOfColumns, 4)
let newCells = grid.cells.filter { $0.columnSpan.contains(1) }
newCells.forEach { _ = $0.editor }

waitForExpectations(timeout: 1.0)
}

func testDeletesRow() {
let expectation = functionExpectation()
expectation.expectedFulfillmentCount = 3
Expand Down
16 changes: 16 additions & 0 deletions Proton/Tests/Grid/GridViewTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -181,4 +181,20 @@ class GridViewTests: XCTestCase {
XCTAssertEqual(cell, cellToQuery)
}

func testUsesCustomEditorInit() {
let expectation = functionExpectation()
expectation.expectedFulfillmentCount = config.numberOfColumns * config.numberOfRows

let editorInit = {
expectation.fulfill()
return EditorView(frame: .zero)
}

let gridView = GridView(config: config, cellEditorInitializer: editorInit)
let delegate = MockGridViewDelegate()
gridView.delegate = delegate
gridView.gridView.willMove(toWindow: UIWindow())

waitForExpectations(timeout: 1.0)
}
}

0 comments on commit bfbb7c4

Please sign in to comment.