mirror of
https://github.com/divkit/divkit.git
synced 2026-06-06 20:07:59 +00:00
added cardId to statesById in DivBlockStateStorage
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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<T: ElementState>(_ id: String) -> T? {
|
||||
getStateUntyped(id) as? T
|
||||
public func getState<T: ElementState>(_ 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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,20 +12,6 @@ public typealias DivStatePath = Tagged<DivStatePathTag, UIElementPath>
|
||||
public enum DivBlockPathTag {}
|
||||
public typealias DivBlockPath = Tagged<DivBlockPathTag, UIElementPath>
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user