mirror of
https://github.com/divkit/divkit.git
synced 2026-06-06 20:07:59 +00:00
168 lines
5.7 KiB
Swift
168 lines
5.7 KiB
Swift
import CoreGraphics
|
|
import Foundation
|
|
import LayoutKit
|
|
import VGSL
|
|
|
|
extension DivIndicator: DivBlockModeling {
|
|
public func makeBlock(context: DivBlockModelingContext) throws -> Block {
|
|
let context = modifiedContextParentPath(context)
|
|
return try applyBaseProperties(
|
|
to: { try makeBaseBlock(context: context) },
|
|
context: context,
|
|
actionsHolder: nil
|
|
)
|
|
}
|
|
|
|
private func makeBaseBlock(context: DivBlockModelingContext) throws -> Block {
|
|
guard let rectangle = shape.rectangle else {
|
|
context.addError(message: "Unsupported shape type")
|
|
return EmptyBlock()
|
|
}
|
|
|
|
let expressionResolver = context.expressionResolver
|
|
let activeRect = makeRoundedRectangle(with: activeShape, resolver: expressionResolver)
|
|
let inactiveRect = makeRoundedRectangle(with: inactiveShape, resolver: expressionResolver)
|
|
let inactiveMinimumRect = makeRoundedRectangle(
|
|
with: inactiveMinimumShape,
|
|
resolver: expressionResolver
|
|
)
|
|
|
|
let pageSize = CGSize(
|
|
width: inactiveRect?.size
|
|
.width ?? CGFloat(rectangle.itemWidth.resolveValue(expressionResolver) ?? 0),
|
|
height: inactiveRect?.size
|
|
.height ?? CGFloat(rectangle.itemHeight.resolveValue(expressionResolver) ?? 0)
|
|
)
|
|
|
|
let hightightedScaleX: CGFloat
|
|
let hightightedScaleY: CGFloat
|
|
if let activeRect, let inactiveRect {
|
|
hightightedScaleX = activeRect.size.width / inactiveRect.size.width
|
|
hightightedScaleY = activeRect.size.height / inactiveRect.size.height
|
|
} else {
|
|
let scale = CGFloat(resolveActiveItemSize(expressionResolver))
|
|
hightightedScaleX = scale
|
|
hightightedScaleY = scale
|
|
}
|
|
|
|
let disappearingScaleX: CGFloat
|
|
let disappearingScaleY: CGFloat
|
|
if let inactiveRect, let inactiveMinimumRect {
|
|
disappearingScaleX = inactiveMinimumRect.size.width / inactiveRect.size.width
|
|
disappearingScaleY = inactiveMinimumRect.size.height / inactiveRect.size.height
|
|
} else {
|
|
let scale = CGFloat(resolveMinimumItemSize(expressionResolver))
|
|
disappearingScaleX = scale
|
|
disappearingScaleY = scale
|
|
}
|
|
|
|
let pagerPath = pagerId.map {
|
|
PagerPath(
|
|
cardId: context.cardId.rawValue,
|
|
pagerId: $0
|
|
)
|
|
}
|
|
let state: PagerViewState = pagerPath.flatMap {
|
|
context.blockStateStorage.getState($0.pagerId, cardId: context.cardId)
|
|
} ?? .default
|
|
let spaceBetweenCenters = CGFloat(spaceBetweenCenters.resolveValue(expressionResolver) ?? 0)
|
|
|
|
let configuration = PageIndicatorConfiguration(
|
|
highlightedColor: activeRect?.backgroundColor ?? resolveActiveItemColor(expressionResolver),
|
|
normalColor: inactiveRect?.backgroundColor ?? resolveInactiveItemColor(expressionResolver),
|
|
highlightedBorder: BlockBorder(
|
|
color: activeRect?.borderColor ?? .clear,
|
|
width: activeRect?.borderWidth ?? 0
|
|
),
|
|
normalBorder: BlockBorder(
|
|
color: inactiveRect?.borderColor ?? .clear,
|
|
width: inactiveRect?.borderWidth ?? 0
|
|
),
|
|
highlightedHeightScale: hightightedScaleY,
|
|
highlightedWidthScale: hightightedScaleX,
|
|
disappearingHeightScale: disappearingScaleY,
|
|
disappearingWidthScale: disappearingScaleX,
|
|
pageSize: pageSize,
|
|
highlightedPageCornerRadius: activeRect?.cornerRadius,
|
|
pageCornerRadius: inactiveRect?.cornerRadius
|
|
?? CGFloat(rectangle.cornerRadius.resolveValue(expressionResolver) ?? 0),
|
|
animation: resolveAnimation(expressionResolver).asBlockAnimation,
|
|
itemPlacement: itemsPlacement?.resolve(expressionResolver)
|
|
?? .fixed(spaceBetweenCenters: spaceBetweenCenters)
|
|
)
|
|
|
|
return PageControlBlock(
|
|
layoutDirection: context.layoutDirection,
|
|
pageControlPath: context.parentPath,
|
|
pagerPath: pagerPath,
|
|
widthTrait: resolveContentWidthTrait(context),
|
|
heightTrait: resolveContentHeightTrait(context),
|
|
configuration: configuration,
|
|
state: state
|
|
)
|
|
}
|
|
|
|
private func makeRoundedRectangle(
|
|
with shape: DivRoundedRectangleShape?,
|
|
resolver: ExpressionResolver
|
|
) -> PageIndicatorConfiguration.RoundedRectangleIndicator? {
|
|
guard let shape else {
|
|
return nil
|
|
}
|
|
return PageIndicatorConfiguration.RoundedRectangleIndicator(
|
|
size: CGSize(
|
|
width: shape.itemWidth.resolveValue(resolver) ?? 0,
|
|
height: shape.itemHeight.resolveValue(resolver) ?? 0
|
|
),
|
|
cornerRadius: CGFloat(shape.cornerRadius.resolveValue(resolver) ?? 0),
|
|
backgroundColor: shape.resolveBackgroundColor(resolver) ?? .clear,
|
|
borderWidth: CGFloat(shape.stroke?.resolveWidth(resolver) ?? 0),
|
|
borderColor: shape.stroke?.resolveColor(resolver) ?? .clear
|
|
)
|
|
}
|
|
}
|
|
|
|
extension DivShape {
|
|
fileprivate var rectangle: DivRoundedRectangleShape? {
|
|
switch self {
|
|
case let .divRoundedRectangleShape(rectangle):
|
|
rectangle
|
|
case .divCircleShape:
|
|
nil
|
|
}
|
|
}
|
|
}
|
|
|
|
extension DivIndicator.Animation {
|
|
fileprivate var asBlockAnimation: PageIndicatorConfiguration.Animation {
|
|
switch self {
|
|
case .scale:
|
|
.scale
|
|
case .worm:
|
|
.worm
|
|
case .slider:
|
|
.slider
|
|
}
|
|
}
|
|
}
|
|
|
|
extension DivIndicatorItemPlacement {
|
|
fileprivate func resolve(
|
|
_ expressionResolver: ExpressionResolver
|
|
) -> PageIndicatorConfiguration.ItemPlacement {
|
|
switch self {
|
|
case let .divDefaultIndicatorItemPlacement(placement):
|
|
.fixed(
|
|
spaceBetweenCenters: CGFloat(
|
|
placement.spaceBetweenCenters.resolveValue(expressionResolver) ?? 0
|
|
)
|
|
)
|
|
case let .divStretchIndicatorItemPlacement(placement):
|
|
.stretch(
|
|
spacing: CGFloat(placement.itemSpacing.resolveValue(expressionResolver) ?? 0),
|
|
maxVisibleItems: placement.resolveMaxVisibleItems(expressionResolver)
|
|
)
|
|
}
|
|
}
|
|
}
|