Files
booster 7d5991e2f8 gallery scroll actions collision fix
commit_hash:e27066de5f833e93cf589451554c6f93d252f6be
2026-05-15 17:16:31 +03:00

157 lines
5.0 KiB
Swift

import CoreGraphics
import LayoutKit
import VGSL
extension DivPager: DivBlockModeling, DivGalleryProtocol {
public func makeBlock(context: DivBlockModelingContext) throws -> Block {
let context = modifiedContextParentPath(context)
return try modifyError({ DivBlockModelingError($0.message, path: context.path) }) {
try applyBaseProperties(
to: { try makeBaseBlock(context: context) },
context: context,
actionsHolder: nil,
applyPaddings: false
)
}
}
private func makeBaseBlock(context: DivBlockModelingContext) throws -> Block {
let expressionResolver = context.expressionResolver
let pagerPath = id.map {
PagerPath(
cardId: context.cardId.rawValue,
pagerId: $0
)
}
let items = nonNilItems
let scrollDirection = resolveOrientation(expressionResolver).direction
let alignment = resolveScrollAxisAlignment(expressionResolver).system
let crossAlignment = resolveCrossAxisAlignment(expressionResolver).system
let layoutMode = layoutMode.resolve(expressionResolver)
let gallery = try makeGalleryModel(
context: context,
direction: resolveOrientation(expressionResolver).direction,
alignment: alignment,
spacing: CGFloat(itemSpacing.resolveValue(expressionResolver) ?? 0),
crossSpacing: 0,
defaultCrossAlignment: crossAlignment,
scrollMode: .autoPaging(inertionEnabled: false),
infiniteScroll: resolveInfiniteScroll(expressionResolver),
layoutMode: layoutMode,
transformation: pageTransformation?.resolve(
expressionResolver,
scrollDirection: scrollDirection
)
)
return try PagerBlock(
pagerPath: pagerPath,
alignment: alignment,
layoutMode: layoutMode,
gallery: gallery,
selectedActions: items.map { $0.value.makeSelectedActions(context: context) },
state: getState(context: context, path: context.path, numberOfPages: items.count),
widthTrait: resolveWidthTrait(context),
heightTrait: resolveHeightTrait(context)
)
}
private func getState(
context: DivBlockModelingContext,
path: UIElementPath,
numberOfPages: Int
) -> PagerViewState {
let storage = context.blockStateStorage
if let pending = storage.takePendingState(path) as? PagerViewState {
storage.setState(path: path, state: pending)
return pending
}
if let state: PagerViewState = storage.getState(path) {
return state
}
let expressionResolver = context.expressionResolver
let defaultItem = resolveDefaultItem(expressionResolver)
return defaultItem == 0 ? .default : PagerViewState(
numberOfPages: numberOfPages,
currentPage: defaultItem,
animated: true,
isInfiniteScrollable: resolveInfiniteScroll(expressionResolver)
)
}
}
extension DivPager.Orientation {
var direction: ScrollDirection {
switch self {
case .horizontal: .horizontal
case .vertical: .vertical
}
}
}
extension DivPagerLayoutMode {
fileprivate func resolve(_ expressionResolver: ExpressionResolver) -> PagerBlock.LayoutMode {
switch self {
case let .divPageSize(pageSize):
return .pageSize(
RelativeValue(
double: (pageSize.pageWidth.resolveValue(expressionResolver) ?? 0) / 100.0
)
)
case let .divNeighbourPageSize(neighbourPageSize):
let size = neighbourPageSize.neighbourPageWidth.resolveValue(expressionResolver) ?? 0
return .neighbourPageSize(CGFloat(size))
case .divPageContentSize:
return .pageContentSize
}
}
}
extension DivPager.ItemAlignment {
fileprivate var system: Alignment {
switch self {
case .center: .center
case .start: .leading
case .end: .trailing
}
}
}
extension DivBase {
fileprivate func makeSelectedActions(
context: DivBlockModelingContext
) -> [UserInterfaceAction] {
selectedActions?.uiActions(context: context) ?? []
}
}
extension DivPageTransformation {
fileprivate func resolve(
_ resolver: ExpressionResolver,
scrollDirection: ScrollDirection
) -> ElementsTransformation {
switch self {
case let .divPageTransformationSlide(transformation):
.init(
nextElementAlpha: transformation.resolveNextPageAlpha(resolver),
previousElementAlpha: transformation.resolvePreviousPageAlpha(resolver),
nextElementScale: transformation.resolveNextPageScale(resolver),
previousElementScale: transformation.resolvePreviousPageScale(resolver),
style: .slide,
scrollDirection: scrollDirection
)
case let .divPageTransformationOverlap(transformation):
.init(
nextElementAlpha: transformation.resolveNextPageAlpha(resolver),
previousElementAlpha: transformation.resolvePreviousPageAlpha(resolver),
nextElementScale: transformation.resolveNextPageScale(resolver),
previousElementScale: transformation.resolvePreviousPageScale(resolver),
style: .overlap,
scrollDirection: scrollDirection
)
}
}
}