mirror of
https://github.com/divkit/divkit.git
synced 2026-06-06 20:07:59 +00:00
235 lines
7.7 KiB
Swift
235 lines
7.7 KiB
Swift
import Foundation
|
|
|
|
import BasePublic
|
|
import BaseUIPublic
|
|
import LayoutKit
|
|
import NetworkingPublic
|
|
import Serialization
|
|
|
|
public final class DivKitComponents {
|
|
public typealias UpdateCardAction = (NonEmptyArray<DivActionURLHandler.UpdateReason>) -> Void
|
|
|
|
public let actionHandler: DivActionHandler
|
|
public let blockStateStorage = DivBlockStateStorage()
|
|
public let divCustomBlockFactory: DivCustomBlockFactory
|
|
public var extensionHandlers: [DivExtensionHandler]
|
|
public let flagsInfo: DivFlagsInfo
|
|
public let fontProvider: DivFontProvider
|
|
public let imageHolderFactory: ImageHolderFactory
|
|
public let patchProvider: DivPatchProvider
|
|
public let playerFactory: PlayerFactory?
|
|
public let safeAreaManager: DivSafeAreaManager
|
|
public let showToolip: DivActionURLHandler.ShowTooltipAction
|
|
public let stateManagement: DivStateManagement
|
|
public let triggersStorage: DivTriggersStorage
|
|
public let urlOpener: UrlOpener
|
|
public let variablesStorage: DivVariablesStorage
|
|
public let visibilityCounter = DivVisibilityCounter()
|
|
|
|
private let timerStorage: DivTimerStorage
|
|
private let updateAggregator: RunLoopCardUpdateAggregator
|
|
private let disposePool = AutodisposePool()
|
|
|
|
public init(
|
|
divCustomBlockFactory: DivCustomBlockFactory = EmptyDivCustomBlockFactory(),
|
|
extensionHandlers: [DivExtensionHandler] = [],
|
|
flagsInfo: DivFlagsInfo = .default,
|
|
fontProvider: DivFontProvider? = nil,
|
|
imageHolderFactory: ImageHolderFactory? = nil,
|
|
patchProvider: DivPatchProvider? = nil,
|
|
requestPerformer: URLRequestPerforming? = nil,
|
|
showTooltip: @escaping DivActionURLHandler.ShowTooltipAction = { _ in },
|
|
stateManagement: DivStateManagement = DefaultDivStateManagement(),
|
|
trackVisibility: @escaping DivActionHandler.TrackVisibility = { _, _ in },
|
|
trackDisappear: @escaping DivActionHandler.TrackVisibility = { _, _ in },
|
|
updateCardAction: UpdateCardAction?,
|
|
playerFactory: PlayerFactory? = nil,
|
|
urlOpener: @escaping UrlOpener,
|
|
variablesStorage: DivVariablesStorage = DivVariablesStorage()
|
|
) {
|
|
self.divCustomBlockFactory = divCustomBlockFactory
|
|
self.extensionHandlers = extensionHandlers
|
|
self.flagsInfo = flagsInfo
|
|
self.fontProvider = fontProvider ?? DefaultFontProvider()
|
|
self.playerFactory = playerFactory ?? defaultPlayerFactory
|
|
self.showToolip = showTooltip
|
|
self.stateManagement = stateManagement
|
|
self.urlOpener = urlOpener
|
|
self.variablesStorage = variablesStorage
|
|
|
|
safeAreaManager = DivSafeAreaManager(storage: variablesStorage)
|
|
|
|
let requestPerformer = requestPerformer ?? URLRequestPerformer(urlTransform: nil)
|
|
|
|
self.imageHolderFactory = imageHolderFactory
|
|
?? makeImageHolderFactory(requestPerformer: requestPerformer)
|
|
|
|
self.patchProvider = patchProvider
|
|
?? DivPatchDownloader(requestPerformer: requestPerformer)
|
|
|
|
let updateAggregator = RunLoopCardUpdateAggregator(updateCardAction: updateCardAction ?? { _ in
|
|
})
|
|
self.updateAggregator = updateAggregator
|
|
let updateCard: DivActionURLHandler.UpdateCardAction = updateAggregator.aggregate(_:)
|
|
|
|
weak var weakTimerStorage: DivTimerStorage?
|
|
|
|
actionHandler = DivActionHandler(
|
|
stateUpdater: stateManagement,
|
|
blockStateStorage: blockStateStorage,
|
|
patchProvider: self.patchProvider,
|
|
variablesStorage: variablesStorage,
|
|
updateCard: updateCard,
|
|
showTooltip: showTooltip,
|
|
logger: DefaultDivActionLogger(
|
|
requestPerformer: requestPerformer
|
|
),
|
|
trackVisibility: trackVisibility,
|
|
trackDisappear: trackDisappear,
|
|
performTimerAction: { weakTimerStorage?.perform($0, $1, $2) }
|
|
)
|
|
|
|
triggersStorage = DivTriggersStorage(
|
|
variablesStorage: variablesStorage,
|
|
actionHandler: actionHandler,
|
|
urlOpener: urlOpener
|
|
)
|
|
|
|
timerStorage = DivTimerStorage(
|
|
variablesStorage: variablesStorage,
|
|
actionHandler: actionHandler,
|
|
urlOpener: urlOpener,
|
|
updateCard: updateCard
|
|
)
|
|
weakTimerStorage = timerStorage
|
|
variablesStorage.changeEvents.addObserver { change in
|
|
switch change.kind {
|
|
case .global:
|
|
updateCard(.variable(.all))
|
|
case let .local(cardId, _):
|
|
updateCard(.variable(.specific([cardId])))
|
|
}
|
|
}.dispose(in: disposePool)
|
|
}
|
|
|
|
public func reset() {
|
|
patchProvider.cancelRequests()
|
|
|
|
blockStateStorage.reset()
|
|
stateManagement.reset()
|
|
variablesStorage.reset()
|
|
visibilityCounter.reset()
|
|
timerStorage.reset()
|
|
}
|
|
|
|
public func parseDivData(
|
|
_ jsonDict: [String: Any],
|
|
cardId: DivCardID
|
|
) throws -> DeserializationResult<DivData> {
|
|
try parseDivDataWithTemplates(["card": jsonDict], cardId: cardId)
|
|
}
|
|
|
|
/// Parses DivData from JSON in following format:
|
|
/// {
|
|
/// "card": { ... },
|
|
/// "templates": { ... }
|
|
/// }
|
|
public func parseDivDataWithTemplates(
|
|
_ jsonDict: [String: Any],
|
|
cardId: DivCardID
|
|
) throws -> DeserializationResult<DivData> {
|
|
let rawDivData = try RawDivData(dictionary: jsonDict)
|
|
let result = DivData.resolve(
|
|
card: rawDivData.card,
|
|
templates: rawDivData.templates
|
|
)
|
|
if let divData = result.value {
|
|
setVariablesAndTriggers(divData: divData, cardId: cardId)
|
|
setTimers(divData: divData, cardId: cardId)
|
|
}
|
|
return result
|
|
}
|
|
|
|
/// Parses DivData from JSON in following format:
|
|
/// {
|
|
/// "card": { ... },
|
|
/// "templates": { ... }
|
|
/// }
|
|
public func parseDivDataWithTemplates(
|
|
_ jsonData: Data,
|
|
cardId: DivCardID
|
|
) throws -> DeserializationResult<DivData> {
|
|
guard let jsonObj = try? JSONSerialization.jsonObject(with: jsonData),
|
|
let jsonDict = jsonObj as? [String: Any] else {
|
|
throw DeserializationError.invalidJSONData(data: jsonData)
|
|
}
|
|
return try parseDivDataWithTemplates(jsonDict, cardId: cardId)
|
|
}
|
|
|
|
public func makeContext(
|
|
cardId: DivCardID,
|
|
cachedImageHolders: [ImageHolder],
|
|
debugParams: DebugParams = DebugParams(),
|
|
parentScrollView: ScrollView? = nil
|
|
) -> DivBlockModelingContext {
|
|
DivBlockModelingContext(
|
|
cardId: cardId,
|
|
stateManager: stateManagement.getStateManagerForCard(cardId: cardId),
|
|
blockStateStorage: blockStateStorage,
|
|
visibilityCounter: visibilityCounter,
|
|
imageHolderFactory: imageHolderFactory
|
|
.withInMemoryCache(cachedImageHolders: cachedImageHolders),
|
|
divCustomBlockFactory: divCustomBlockFactory,
|
|
fontProvider: fontProvider,
|
|
flagsInfo: flagsInfo,
|
|
extensionHandlers: extensionHandlers,
|
|
variables: variablesStorage.makeVariables(for: cardId),
|
|
playerFactory: playerFactory,
|
|
debugParams: debugParams,
|
|
parentScrollView: parentScrollView
|
|
)
|
|
}
|
|
|
|
public func handleActions(params: UserInterfaceAction.DivActionParams) {
|
|
actionHandler.handle(params: params, urlOpener: urlOpener)
|
|
}
|
|
|
|
public func setVariablesAndTriggers(divData: DivData, cardId: DivCardID) {
|
|
updateAggregator.performWithNoUpdates {
|
|
let divDataVariables = divData.variables?.extractDivVariableValues() ?? [:]
|
|
variablesStorage.append(
|
|
variables: divDataVariables,
|
|
for: cardId,
|
|
replaceExisting: false
|
|
)
|
|
|
|
triggersStorage.set(
|
|
cardId: cardId,
|
|
triggers: divData.variableTriggers ?? []
|
|
)
|
|
}
|
|
}
|
|
|
|
public func setTimers(divData: DivData, cardId: DivCardID) {
|
|
timerStorage.set(cardId: cardId, timers: divData.timers ?? [])
|
|
}
|
|
}
|
|
|
|
func makeImageHolderFactory(requestPerformer: URLRequestPerforming) -> ImageHolderFactory {
|
|
ImageHolderFactory(
|
|
requester: NetworkURLResourceRequester(
|
|
performer: requestPerformer
|
|
),
|
|
imageProcessingQueue: OperationQueue(
|
|
name: "tech.divkit.image-processing",
|
|
qos: .userInitiated
|
|
)
|
|
)
|
|
}
|
|
|
|
#if os(iOS)
|
|
let defaultPlayerFactory: PlayerFactory? = DefaultPlayerFactory()
|
|
#else
|
|
let defaultPlayerFactory: PlayerFactory? = nil
|
|
#endif
|