Files
divkit/client/ios/DivKit/Extensions/DivGallery/DivGalleryProtocol.swift
T
pkurchatov 0663870bf9 Swiftformat
commit_hash:52ce6e4a9f35a44ddef28565cec76ddaabdc2d08
2025-09-18 12:40:09 +03:00

144 lines
4.0 KiB
Swift

import CoreGraphics
import LayoutKit
import VGSL
protocol DivGalleryProtocol: DivBase {
var items: [Div]? { get }
var itemBuilder: DivCollectionItemBuilder? { get }
}
extension DivGalleryProtocol {
var nonNilItems: [Div] {
items ?? []
}
func makeGalleryModel(
context: DivBlockModelingContext,
direction: ScrollDirection,
alignment: Alignment,
spacing: CGFloat,
crossSpacing: CGFloat,
defaultCrossAlignment: Alignment,
scrollMode: GalleryViewModel.ScrollMode,
columnCount: Int? = nil,
infiniteScroll: Bool = false,
layoutMode: PagerBlock.LayoutMode? = nil,
scrollbar: GalleryViewModel.Scrollbar = .none,
transformation: ElementsTransformation? = nil
) throws -> GalleryViewModel {
let expressionResolver = context.expressionResolver
var children: [GalleryViewModel.Item]
let blockMapper: (Div, Block, DivBlockModelingContext) -> GalleryViewModel
.Item = { div, block, _ in
GalleryViewModel.Item(
crossAlignment: (
direction.isHorizontal
? div.value.resolveAlignmentVertical(expressionResolver)?.alignment
: div.value.resolveAlignmentHorizontal(expressionResolver)?
.alignment(isRTLLayout: context.layoutDirection == .rightToLeft)
) ?? defaultCrossAlignment,
content: block
)
}
children = if let itemBuilder {
itemBuilder.makeBlocks(context: context, mappedBy: blockMapper)
} else {
nonNilItems.makeBlocks(
context: context,
sizeModifier: DivGallerySizeModifier(
context: context,
gallery: self,
direction: direction
),
mappedBy: blockMapper
)
}
let itemsCount = children.count
let bufferSize = layoutMode.map { min($0.bufferSize(itemsCount: itemsCount), itemsCount) } ?? 1
if infiniteScroll {
let leadingBuffer = children[..<bufferSize]
let trailingBuffer = children[(children.count - bufferSize)...]
children = trailingBuffer + children + leadingBuffer
}
let metrics = try makeMetrics(
spacing: spacing,
crossSpacing: crossSpacing,
childrenCount: children.count,
direction: direction,
with: expressionResolver
)
return GalleryViewModel(
items: children,
layoutDirection: context.layoutDirection,
metrics: metrics,
scrollMode: scrollMode,
path: context.path,
alignment: alignment,
direction: direction,
bufferSize: bufferSize,
columnCount: columnCount ?? 1,
infiniteScroll: infiniteScroll,
scrollbar: scrollbar,
transformation: transformation
)
}
private func makeMetrics(
spacing: CGFloat,
crossSpacing: CGFloat,
childrenCount: Int,
direction: ScrollDirection,
with expressionResolver: ExpressionResolver
) throws -> GalleryViewMetrics {
let spacings = [CGFloat](
repeating: spacing,
times: UInt(max(0, childrenCount - 1))
)
let axialInsets: SideInsets
let crossInsets: SideInsets
let horizontalInsets = paddings.resolveHorizontalInsets(expressionResolver)
let verticalInsets = paddings.resolveVerticalInsets(expressionResolver)
switch direction {
case .horizontal:
axialInsets = horizontalInsets
crossInsets = verticalInsets
case .vertical:
axialInsets = verticalInsets
crossInsets = horizontalInsets
}
return GalleryViewMetrics(
axialInsetMode: .fixed(values: axialInsets),
crossInsetMode: .fixed(values: crossInsets),
spacings: spacings,
crossSpacing: crossSpacing
)
}
var typeName: String {
guard let typeName = String(describing: self).split(separator: ".").last else {
return "DivGallery"
}
return String(typeName)
}
}
extension PagerBlock.LayoutMode {
fileprivate func bufferSize(itemsCount: Int) -> Int {
switch self {
case let .pageSize(relativeValue):
Int(1 / relativeValue.rawValue) + 1
case .neighbourPageSize:
2
case .pageContentSize:
itemsCount
}
}
}