From 92f040bb6615f8f7fb76cdf7e4b313f444abb374 Mon Sep 17 00:00:00 2001 From: chris-benua Date: Wed, 19 Jul 2023 20:04:57 +0300 Subject: [PATCH] added cardId to statesById in DivBlockStateStorage --- .../DivKit/Actions/DivActionURLHandler.swift | 37 +++++++++----- client/ios/DivKit/DivBlockStateStorage.swift | 35 +++++++++---- client/ios/DivKit/DivStatePath.swift | 28 +++++------ .../Extensions/DivIndicatorExtensions.swift | 4 +- .../DivBlockStateStorageTests.swift | 50 ++++++++++--------- .../Blocks/BlocksStateExtensions.swift | 21 +------- .../LayoutKit/Blocks/PagerBlock.swift | 17 +++++++ 7 files changed, 114 insertions(+), 78 deletions(-) diff --git a/client/ios/DivKit/Actions/DivActionURLHandler.swift b/client/ios/DivKit/Actions/DivActionURLHandler.swift index 2defbac6f..6427a234a 100644 --- a/client/ios/DivKit/Actions/DivActionURLHandler.swift +++ b/client/ios/DivKit/Actions/DivActionURLHandler.swift @@ -102,17 +102,18 @@ public final class DivActionURLHandler { value: value ) case let .setCurrentItem(id, index): - setCurrentItem(id: id, index: index) + setCurrentItem(id: id, cardId: cardId, index: index) updateCard(.state(cardId)) case let .setNextItem(id, overflow): - setNextItem(id: id, overflow: overflow) + setNextItem(id: id, cardId: cardId, overflow: overflow) updateCard(.state(cardId)) case let .setPreviousItem(id, overflow): - setPreviousItem(id: id, overflow: overflow) + setPreviousItem(id: id, cardId: cardId, overflow: overflow) updateCard(.state(cardId)) case let .video(id: id, action: action): blockStateStorage.setState( id: id, + cardId: cardId, state: VideoBlockViewState(state: action == .play ? .playing : .paused) ) updateCard(.state(cardId)) @@ -137,29 +138,31 @@ public final class DivActionURLHandler { } } - private func setCurrentItem(id: String, index: Int) { - switch blockStateStorage.getStateUntyped(id) { + private func setCurrentItem(id: String, cardId: DivCardID, index: Int) { + switch blockStateStorage.getStateUntyped(id, cardId: cardId) { case let galleryState as GalleryViewState: setGalleryCurrentItem( id: id, + cardId: cardId, index: index, itemsCount: galleryState.itemsCount ) case let pagerState as PagerViewState: setPagerCurrentItem( id: id, + cardId: cardId, index: index, numberOfPages: pagerState.numberOfPages ) case let tabsState as TabViewState: - setTabsCurrentItem(id: id, index: index, countOfPages: tabsState.countOfPages) + setTabsCurrentItem(id: id, cardId: cardId, index: index, countOfPages: tabsState.countOfPages) default: return } } - private func setNextItem(id: String, overflow: OverflowMode) { - switch blockStateStorage.getStateUntyped(id) { + private func setNextItem(id: String, cardId: DivCardID, overflow: OverflowMode) { + switch blockStateStorage.getStateUntyped(id, cardId: cardId) { case let galleryState as GalleryViewState: let index = getNextIndex( current: galleryState.currentItemIndex, @@ -168,6 +171,7 @@ public final class DivActionURLHandler { ) setGalleryCurrentItem( id: id, + cardId: cardId, index: index, itemsCount: galleryState.itemsCount ) @@ -179,6 +183,7 @@ public final class DivActionURLHandler { ) setPagerCurrentItem( id: id, + cardId: cardId, index: nextIndex, numberOfPages: pagerState.numberOfPages ) @@ -190,6 +195,7 @@ public final class DivActionURLHandler { ) setTabsCurrentItem( id: id, + cardId: cardId, index: nextIndex, countOfPages: tabsState.countOfPages ) @@ -211,8 +217,8 @@ public final class DivActionURLHandler { } } - private func setPreviousItem(id: String, overflow: OverflowMode) { - switch blockStateStorage.getStateUntyped(id) { + private func setPreviousItem(id: String, cardId: DivCardID, overflow: OverflowMode) { + switch blockStateStorage.getStateUntyped(id, cardId: cardId) { case let galleryState as GalleryViewState: let index = getPreviousIndex( current: galleryState.currentItemIndex, @@ -221,6 +227,7 @@ public final class DivActionURLHandler { ) setGalleryCurrentItem( id: id, + cardId: cardId, index: index, itemsCount: galleryState.itemsCount ) @@ -232,6 +239,7 @@ public final class DivActionURLHandler { ) setPagerCurrentItem( id: id, + cardId: cardId, index: prevIndex, numberOfPages: pagerState.numberOfPages ) @@ -243,6 +251,7 @@ public final class DivActionURLHandler { ) setTabsCurrentItem( id: id, + cardId: cardId, index: prevIndex, countOfPages: tabsState.countOfPages ) @@ -266,11 +275,13 @@ public final class DivActionURLHandler { private func setGalleryCurrentItem( id: String, + cardId: DivCardID, index: Int, itemsCount: Int ) { blockStateStorage.setState( id: id, + cardId: cardId, state: GalleryViewState( contentPageIndex: CGFloat(max(0, index)), itemsCount: itemsCount @@ -278,7 +289,7 @@ public final class DivActionURLHandler { ) } - private func setPagerCurrentItem(id: String, index: Int, numberOfPages: Int) { + private func setPagerCurrentItem(id: String, cardId: DivCardID, index: Int, numberOfPages: Int) { let clampedIndex = clamp(index, min: 0, max: numberOfPages - 1) guard clampedIndex == index else { return @@ -286,6 +297,7 @@ public final class DivActionURLHandler { blockStateStorage.setState( id: id, + cardId: cardId, state: PagerViewState( numberOfPages: numberOfPages, currentPage: clampedIndex @@ -293,9 +305,10 @@ public final class DivActionURLHandler { ) } - private func setTabsCurrentItem(id: String, index: Int, countOfPages: Int) { + private func setTabsCurrentItem(id: String, cardId: DivCardID, index: Int, countOfPages: Int) { blockStateStorage.setState( id: id, + cardId: cardId, state: TabViewState( selectedPageIndex: CGFloat(max(0, index)), countOfPages: countOfPages diff --git a/client/ios/DivKit/DivBlockStateStorage.swift b/client/ios/DivKit/DivBlockStateStorage.swift index a7ec172be..62fcbea3d 100644 --- a/client/ios/DivKit/DivBlockStateStorage.swift +++ b/client/ios/DivKit/DivBlockStateStorage.swift @@ -1,10 +1,11 @@ import Foundation import LayoutKit +import BaseTinyPublic public final class DivBlockStateStorage { public private(set) var states: BlocksState - private var statesById: [String: ElementState] = [:] + private var statesById: [IdAndCardId: ElementState] = [:] public init(states: BlocksState = [:]) { self.states = states @@ -16,25 +17,26 @@ public final class DivBlockStateStorage { } public func getStateUntyped(_ path: UIElementPath) -> ElementState? { - statesById[path.leaf] ?? states[path] + statesById[IdAndCardId(path: path)] ?? states[path] } @inlinable - public func getState(_ id: String) -> T? { - getStateUntyped(id) as? T + public func getState(_ id: String, cardId: DivCardID) -> T? { + getStateUntyped(id, cardId: cardId) as? T } - public func getStateUntyped(_ id: String) -> ElementState? { - statesById[id] ?? states.first { $0.key.leaf == id }?.value + public func getStateUntyped(_ id: String, cardId: DivCardID) -> ElementState? { + let idKey = IdAndCardId(id: id, cardId: cardId) + return statesById[idKey] ?? states.first { IdAndCardId(path: $0.key) == idKey }?.value } public func setState(path: UIElementPath, state: ElementState) { - statesById[path.leaf] = nil + statesById[IdAndCardId(path: path)] = nil states[path] = state } - public func setState(id: String, state: ElementState) { - statesById[id] = state + public func setState(id: String, cardId: DivCardID, state: ElementState) { + statesById[IdAndCardId(id: id, cardId: cardId)] = state } public func reset() { @@ -52,3 +54,18 @@ extension DivBlockStateStorage: ElementStateObserver { getStateUntyped(path) } } + +private struct IdAndCardId: Hashable { + let id: String + let cardId: DivCardID + + init(id: String, cardId: DivCardID) { + self.id = id + self.cardId = cardId + } + + init(path: UIElementPath) { + id = path.leaf + cardId = DivCardID(rawValue: path.root) + } +} diff --git a/client/ios/DivKit/DivStatePath.swift b/client/ios/DivKit/DivStatePath.swift index 69c34037d..3a0303358 100644 --- a/client/ios/DivKit/DivStatePath.swift +++ b/client/ios/DivKit/DivStatePath.swift @@ -12,20 +12,6 @@ public typealias DivStatePath = Tagged public enum DivBlockPathTag {} public typealias DivBlockPath = Tagged -extension UIElementPath { - public static func parseDivPath(_ string: String) -> Self? { - let split = string.split(separator: "/") - guard - let first = split.first, - Int(first) != nil - else { - return nil - } - - return UIElementPath(String(first)) + split.dropFirst().map(String.init) - } -} - extension Tagged where Tag == DivStatePathTag, RawValue == UIElementPath { public static func makeDivStatePath(from string: String) -> Self? { guard let path = UIElementPath.parseDivPath(string) else { @@ -91,3 +77,17 @@ extension Tagged where Tag == DivBlockPathTag, RawValue == UIElementPath { return DivStatePath(rawValue: parent) } } + +extension UIElementPath { + fileprivate static func parseDivPath(_ string: String) -> Self? { + let split = string.split(separator: "/") + guard + let first = split.first, + Int(first) != nil + else { + return nil + } + + return UIElementPath(String(first)) + split.dropFirst().map(String.init) + } +} diff --git a/client/ios/DivKit/Extensions/DivIndicatorExtensions.swift b/client/ios/DivKit/Extensions/DivIndicatorExtensions.swift index 8fb858a41..3499a8035 100644 --- a/client/ios/DivKit/Extensions/DivIndicatorExtensions.swift +++ b/client/ios/DivKit/Extensions/DivIndicatorExtensions.swift @@ -65,7 +65,9 @@ extension DivIndicator: DivBlockModeling { pagerId: $0 ) } - let state = context.blockStateStorage.states.pagerViewState(for: pagerPath) ?? .default + let state: PagerViewState = pagerPath.flatMap { + context.blockStateStorage.getState($0.pagerId, cardId: context.cardId) + } ?? .default let spaceBetweenCenters = CGFloat(spaceBetweenCenters.resolveValue(expressionResolver) ?? 0) let configuration = PageIndicatorConfiguration( diff --git a/client/ios/DivKitTests/DivBlockStateStorageTests.swift b/client/ios/DivKitTests/DivBlockStateStorageTests.swift index 8bb41d785..c2c9ff097 100644 --- a/client/ios/DivKitTests/DivBlockStateStorageTests.swift +++ b/client/ios/DivKitTests/DivBlockStateStorageTests.swift @@ -14,7 +14,7 @@ final class DivBlockStateStorageTests: XCTestCase { } func test_GetState_ByPath_NotExists() { - XCTAssertNil(storage.getStateUntyped(path("0/id"))) + XCTAssertNil(storage.getStateUntyped(divStatePath("0/id"))) } func test_GetState_ById_NotExists() { @@ -22,47 +22,47 @@ final class DivBlockStateStorageTests: XCTestCase { } func test_SetState_WithPath_GetState_ByPath() { - storage.setState(path: path("0/id"), state: state1) - XCTAssertEqual(storage.getState(path("0/id")), state1) + storage.setState(path: divStatePath("0/id"), state: state1) + XCTAssertEqual(storage.getState(divStatePath("0/id")), state1) } func test_SetState_WithPath_GetState_ById() { - storage.setState(path: path("0/id"), state: state1) - XCTAssertEqual(storage.getState("id"), state1) + storage.setState(path: path(cardId: "card_id", path: "0/id"), state: state1) + XCTAssertEqual(storage.getState("id", cardId: "card_id"), state1) } - func test_SetState_WithId_GetState_ByPath() { - storage.setState(id: "id", state: state1) - XCTAssertEqual(storage.getState(path("0/div_state/state1/id")), state1) + func test_SetState_WithIdAndCardId_GetState_ByPath() { + storage.setState(id: "id", cardId: "card_id", state: state1) + XCTAssertEqual(storage.getState(path(cardId: "card_id", path: "0/div_state/state1/id")), state1) } - func test_SetState_WithId_GetState_ById() { - storage.setState(id: "id", state: state1) - XCTAssertEqual(storage.getState("id"), state1) + func test_SetState_WithIdAndCardId_GetState_ByIdAndCardId() { + storage.setState(id: "id", cardId: "card_id", state: state1) + XCTAssertEqual(storage.getState("id", cardId: "card_id"), state1) } func test_SetState_WithPath_OverridesWithId() { - storage.setState(id: "id", state: state1) - storage.setState(path: path("0/id"), state: state2) - XCTAssertEqual(storage.getState(path("0/id")), state2) + storage.setState(id: "id", cardId: "card_id", state: state1) + storage.setState(path: path(cardId: "card_id", path: "0/id"), state: state2) + XCTAssertEqual(storage.getState(path(cardId: "card_id", path: "0/id")), state2) } func test_SetState_WithId_OverridesWithPath() { - storage.setState(path: path("0/id"), state: state1) - storage.setState(id: "id", state: state2) - XCTAssertEqual(storage.getState(path("0/id")), state2) + storage.setState(path: path(cardId: "card_id", path: "0/id"), state: state1) + storage.setState(id: "id", cardId: "card_id", state: state2) + XCTAssertEqual(storage.getState(path(cardId: "card_id", path: "0/id")), state2) } func test_Reset_ResetsPaths() { - storage.setState(path: path("0/id"), state: state1) + storage.setState(path: divStatePath("0/id"), state: state1) storage.reset() - XCTAssertNil(storage.getStateUntyped(path("0/id"))) + XCTAssertNil(storage.getStateUntyped(divStatePath("0/id"))) } func test_Reset_ResetsIds() { - storage.setState(id: "id", state: state1) + storage.setState(id: "id", cardId: "card_id", state: state1) storage.reset() - XCTAssertNil(storage.getStateUntyped("id")) + XCTAssertNil(storage.getStateUntyped("id", cardId: "card_id")) } } @@ -73,6 +73,10 @@ private struct State: ElementState, Equatable { public let name: String } -private func path(_ path: String) -> UIElementPath { - UIElementPath.parseDivPath(path)! +private func path(cardId: String, path: String) -> UIElementPath { + UIElementPath(cardId) + path.split(separator: "/").map(String.init) +} + +private func divStatePath(_ path: String) -> UIElementPath { + DivStatePath.makeDivStatePath(from: path)!.rawValue } diff --git a/client/ios/LayoutKit/LayoutKit/Blocks/BlocksStateExtensions.swift b/client/ios/LayoutKit/LayoutKit/Blocks/BlocksStateExtensions.swift index 3937ab176..dc5c4fe36 100644 --- a/client/ios/LayoutKit/LayoutKit/Blocks/BlocksStateExtensions.swift +++ b/client/ios/LayoutKit/LayoutKit/Blocks/BlocksStateExtensions.swift @@ -3,29 +3,12 @@ import Foundation import CommonCorePublic import LayoutKitInterface -extension BlocksState { - public func pagerViewState(for pagerPath: PagerPath?) -> PagerViewState? { - pagerPath.flatMap { pagerPath in - first(where: { pagerPath.matches($0.key) })?.value as? PagerViewState - } - } -} - public struct PagerPath: Equatable { - let cardId: String - let pagerId: String + public let cardId: String + public let pagerId: String public init(cardId: String, pagerId: String) { self.cardId = cardId self.pagerId = pagerId } } - -extension PagerPath { - fileprivate func matches(_ path: UIElementPath) -> Bool { - if path.root != cardId { - return false - } - return path.leaf == pagerId - } -} diff --git a/client/ios/LayoutKit/LayoutKit/Blocks/PagerBlock.swift b/client/ios/LayoutKit/LayoutKit/Blocks/PagerBlock.swift index 6fd24bd4a..5cdfdab66 100644 --- a/client/ios/LayoutKit/LayoutKit/Blocks/PagerBlock.swift +++ b/client/ios/LayoutKit/LayoutKit/Blocks/PagerBlock.swift @@ -146,3 +146,20 @@ extension Array where Element == GalleryViewModel.Item { } } } + +extension BlocksState { + public func pagerViewState(for pagerPath: PagerPath?) -> PagerViewState? { + pagerPath.flatMap { pagerPath in + first(where: { pagerPath.matches($0.key) })?.value as? PagerViewState + } + } +} + +extension PagerPath { + fileprivate func matches(_ path: UIElementPath) -> Bool { + if path.root != cardId { + return false + } + return path.leaf == pagerId + } +}