Files
divkit/client/ios/DivKit/Extensions/DivPagerExtensions.swift
T
2025-08-11 17:03:34 +03:00

150 lines
4.8 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 {
if let state: PagerViewState = context.blockStateStorage.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
)
}
}
}