mirror of
https://github.com/divkit/divkit.git
synced 2026-05-07 20:02:32 +00:00
Added download action handler
commit_hash:356512da68f2ed46479425dd365d06a9ca266514
This commit is contained in:
@@ -12665,6 +12665,7 @@
|
||||
"client/ios/DivKit/Actions/DivActionURLHandler.swift":"divkit/public/client/ios/DivKit/Actions/DivActionURLHandler.swift",
|
||||
"client/ios/DivKit/Actions/DivUrlHandler.swift":"divkit/public/client/ios/DivKit/Actions/DivUrlHandler.swift",
|
||||
"client/ios/DivKit/Actions/DivVideoAction.swift":"divkit/public/client/ios/DivKit/Actions/DivVideoAction.swift",
|
||||
"client/ios/DivKit/Actions/DownloadActionHandler.swift":"divkit/public/client/ios/DivKit/Actions/DownloadActionHandler.swift",
|
||||
"client/ios/DivKit/Actions/FocusElementActionHandler.swift":"divkit/public/client/ios/DivKit/Actions/FocusElementActionHandler.swift",
|
||||
"client/ios/DivKit/Actions/ScrollActionHandler.swift":"divkit/public/client/ios/DivKit/Actions/ScrollActionHandler.swift",
|
||||
"client/ios/DivKit/Actions/ScrollMode.swift":"divkit/public/client/ios/DivKit/Actions/ScrollMode.swift",
|
||||
|
||||
@@ -3,6 +3,6 @@ import Foundation
|
||||
final class ClearFocusActionHandler {
|
||||
func handle(context: DivActionHandlingContext) {
|
||||
context.blockStateStorage.clearFocus()
|
||||
context.updateCard(.state(context.path.cardId))
|
||||
context.updateCard(.state(context.cardId))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ public final class DivActionHandler {
|
||||
|
||||
typealias UpdateCardAction = (DivActionURLHandler.UpdateReason) -> Void
|
||||
|
||||
private let divActionURLHandler: DivActionURLHandler
|
||||
private let urlHandler: DivUrlHandler
|
||||
private let trackVisibility: TrackVisibility
|
||||
private let trackDisappear: TrackVisibility
|
||||
@@ -33,6 +32,7 @@ public final class DivActionHandler {
|
||||
private let clearFocusActionHandler = ClearFocusActionHandler()
|
||||
private let copyToClipboardActionHandler = CopyToClipboardActionHandler()
|
||||
private let dictSetValueActionHandler = DictSetValueActionHandler()
|
||||
private let downloadActionHandler: DownloadActionHandler
|
||||
private let focusElementActionHandler = FocusElementActionHandler()
|
||||
private let scrollActionHandler: ScrollActionHandler
|
||||
private let setStateActionHandler: SetStateActionHandler
|
||||
@@ -103,33 +103,6 @@ public final class DivActionHandler {
|
||||
animatorController: DivAnimatorController,
|
||||
flags: DivFlagsInfo
|
||||
) {
|
||||
let scrollActionHandler = ScrollActionHandler(
|
||||
blockStateStorage: blockStateStorage,
|
||||
updateCard: updateCard
|
||||
)
|
||||
self.scrollActionHandler = scrollActionHandler
|
||||
|
||||
let setStateActionHandler = SetStateActionHandler(stateUpdater: stateUpdater)
|
||||
self.setStateActionHandler = setStateActionHandler
|
||||
|
||||
let timerActionHandler = TimerActionHandler(performer: performTimerAction)
|
||||
self.timerActionHandler = timerActionHandler
|
||||
|
||||
let tooltipActionHandler = TooltipActionHandler(
|
||||
performer: tooltipActionPerformer,
|
||||
showTooltip: showTooltip
|
||||
)
|
||||
self.tooltipActionHandler = tooltipActionHandler
|
||||
|
||||
self.divActionURLHandler = DivActionURLHandler(
|
||||
patchProvider: patchProvider,
|
||||
updateCard: updateCard,
|
||||
persistentValuesStorage: persistentValuesStorage,
|
||||
scrollActionHandler: scrollActionHandler,
|
||||
setStateActionHandler: setStateActionHandler,
|
||||
timerActionHandler: timerActionHandler,
|
||||
tooltipActionHandler: tooltipActionHandler
|
||||
)
|
||||
self.urlHandler = urlHandler
|
||||
self.trackVisibility = trackVisibility
|
||||
self.trackDisappear = trackDisappear
|
||||
@@ -143,10 +116,24 @@ public final class DivActionHandler {
|
||||
self.flags = flags
|
||||
|
||||
animatorActionHandler = AnimatorActionHandler(animatorController: animatorController)
|
||||
downloadActionHandler = DownloadActionHandler(
|
||||
patchProvider: patchProvider,
|
||||
updateCard: updateCard
|
||||
)
|
||||
scrollActionHandler = ScrollActionHandler(
|
||||
blockStateStorage: blockStateStorage,
|
||||
updateCard: updateCard
|
||||
)
|
||||
setStateActionHandler = SetStateActionHandler(stateUpdater: stateUpdater)
|
||||
setStoredValueActionHandler = SetStoredValueActionHandler(
|
||||
persistentValuesStorage: persistentValuesStorage
|
||||
)
|
||||
submitActionHandler = SubmitActionHandler(submitter: submitter)
|
||||
timerActionHandler = TimerActionHandler(performer: performTimerAction)
|
||||
tooltipActionHandler = TooltipActionHandler(
|
||||
performer: tooltipActionPerformer,
|
||||
showTooltip: showTooltip
|
||||
)
|
||||
}
|
||||
|
||||
public func handle(
|
||||
@@ -204,8 +191,9 @@ public final class DivActionHandler {
|
||||
} else {
|
||||
path
|
||||
}
|
||||
let info = action.resolveInfo(expressionResolver, path: path, source: source)
|
||||
let context = DivActionHandlingContext(
|
||||
path: path,
|
||||
info: info,
|
||||
expressionResolver: expressionResolver,
|
||||
variablesStorage: variablesStorage,
|
||||
blockStateStorage: blockStateStorage,
|
||||
@@ -213,7 +201,6 @@ public final class DivActionHandler {
|
||||
updateCard: updateCard
|
||||
)
|
||||
|
||||
var isHandled = true
|
||||
switch action.typed {
|
||||
case let .divActionAnimatorStart(action):
|
||||
animatorActionHandler.handle(action, context: context)
|
||||
@@ -231,6 +218,8 @@ public final class DivActionHandler {
|
||||
copyToClipboardActionHandler.handle(action, context: context)
|
||||
case let .divActionDictSetValue(action):
|
||||
dictSetValueActionHandler.handle(action, context: context)
|
||||
case let .divActionDownload(action):
|
||||
downloadActionHandler.handle(action, context: context)
|
||||
case let .divActionFocusElement(action):
|
||||
focusElementActionHandler.handle(action, context: context)
|
||||
case let .divActionHideTooltip(action):
|
||||
@@ -253,88 +242,114 @@ public final class DivActionHandler {
|
||||
timerActionHandler.handle(action, context: context)
|
||||
case let .divActionVideo(action):
|
||||
videoActionHandler.handle(action, context: context)
|
||||
case .divActionDownload:
|
||||
break
|
||||
case .none:
|
||||
isHandled = false
|
||||
handleUrl(action, context: context, sender: sender)
|
||||
}
|
||||
|
||||
let logId = action.resolveLogId(expressionResolver) ?? ""
|
||||
let logUrl = action.resolveLogUrl(expressionResolver)
|
||||
let referer = action.resolveReferer(expressionResolver)
|
||||
|
||||
let divActionInfo = DivActionInfo(
|
||||
path: path,
|
||||
logId: logId,
|
||||
url: action.resolveUrl(expressionResolver),
|
||||
logUrl: logUrl,
|
||||
referer: referer,
|
||||
source: source,
|
||||
payload: action.payload
|
||||
)
|
||||
|
||||
if !isHandled {
|
||||
handleUrl(
|
||||
action,
|
||||
info: divActionInfo,
|
||||
context: context,
|
||||
sender: sender
|
||||
)
|
||||
}
|
||||
|
||||
reporter.reportAction(
|
||||
cardId: cardId,
|
||||
info: divActionInfo
|
||||
)
|
||||
reporter.reportAction(cardId: cardId, info: info)
|
||||
|
||||
if source == .visibility {
|
||||
trackVisibility(logId, cardId)
|
||||
trackVisibility(info.logId, cardId)
|
||||
} else if source == .disappear {
|
||||
trackDisappear(logId, cardId)
|
||||
trackDisappear(info.logId, cardId)
|
||||
}
|
||||
}
|
||||
|
||||
private func handleUrl(
|
||||
_ action: DivActionBase,
|
||||
info: DivActionInfo,
|
||||
context: DivActionHandlingContext,
|
||||
sender: AnyObject?
|
||||
) {
|
||||
guard let url = info.url else {
|
||||
guard let url = context.info.url else {
|
||||
return
|
||||
}
|
||||
|
||||
let isDivActionURLHandled = divActionURLHandler.handleURL(
|
||||
url,
|
||||
info: info,
|
||||
context: context,
|
||||
completion: { [weak self] result in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let callbackActions: [DivAction] = switch result {
|
||||
case .success:
|
||||
action.downloadCallbacks?.onSuccessActions ?? []
|
||||
case .failure:
|
||||
action.downloadCallbacks?.onFailActions ?? []
|
||||
}
|
||||
for action in callbackActions {
|
||||
self.handle(
|
||||
action,
|
||||
path: info.path,
|
||||
source: info.source,
|
||||
sender: sender
|
||||
if let intent = DivActionIntent(url: url) {
|
||||
let cardId = context.cardId
|
||||
switch intent {
|
||||
case let .showTooltip(id, multiple):
|
||||
let tooltipInfo = TooltipInfo(id: id, showsOnStart: false, multiple: multiple)
|
||||
tooltipActionHandler.showTooltip(tooltipInfo)
|
||||
case let .hideTooltip(id):
|
||||
tooltipActionHandler.hideTooltip(id: id)
|
||||
case let .download(patchUrl):
|
||||
downloadActionHandler.handle(
|
||||
url: patchUrl,
|
||||
context: context,
|
||||
onSuccessActions: action.downloadCallbacks?.onSuccessActions,
|
||||
onFailActions: action.downloadCallbacks?.onFailActions
|
||||
)
|
||||
case let .setState(divStatePath, lifetime):
|
||||
setStateActionHandler.handle(
|
||||
divStatePath: divStatePath,
|
||||
lifetime: lifetime,
|
||||
context: context
|
||||
)
|
||||
case let .setVariable(name, value):
|
||||
context.variablesStorage.update(
|
||||
path: context.path,
|
||||
name: DivVariableName(rawValue: name),
|
||||
value: value
|
||||
)
|
||||
case let .setCurrentItem(id, index):
|
||||
scrollActionHandler.scrollToItem(cardId: cardId, id: id, index: index)
|
||||
case let .setNextItem(id, step, overflow):
|
||||
scrollActionHandler.scrollToNextItem(
|
||||
cardId: cardId,
|
||||
id: id,
|
||||
step: step,
|
||||
overflow: overflow
|
||||
)
|
||||
case let .setPreviousItem(id, step, overflow):
|
||||
scrollActionHandler.scrollToNextItem(
|
||||
cardId: cardId,
|
||||
id: id,
|
||||
step: -step,
|
||||
overflow: overflow
|
||||
)
|
||||
case let .scroll(id, mode):
|
||||
switch mode {
|
||||
case .start:
|
||||
scrollActionHandler.scrollToStart(cardId: cardId, id: id)
|
||||
case .end:
|
||||
scrollActionHandler.scrollToEnd(cardId: cardId, id: id)
|
||||
case let .forward(offset, overflow):
|
||||
scrollActionHandler.scrollToOffset(
|
||||
cardId: cardId,
|
||||
id: id,
|
||||
offset: offset,
|
||||
isRelative: true,
|
||||
overflow: overflow
|
||||
)
|
||||
case let .backward(offset, overflow):
|
||||
scrollActionHandler.scrollToOffset(
|
||||
cardId: cardId,
|
||||
id: id,
|
||||
offset: -offset,
|
||||
isRelative: true,
|
||||
overflow: overflow
|
||||
)
|
||||
case let .position(position):
|
||||
scrollActionHandler.scrollToOffset(cardId: cardId, id: id, offset: position)
|
||||
}
|
||||
case let .video(id: id, action: action):
|
||||
context.blockStateStorage.setState(
|
||||
id: id,
|
||||
cardId: cardId,
|
||||
state: VideoBlockViewState(state: action == .play ? .playing : .paused)
|
||||
)
|
||||
context.updateCard(.state(cardId))
|
||||
case let .timer(timerId, action):
|
||||
timerActionHandler.handle(cardId: cardId, timerId: timerId, action: action)
|
||||
case let .setStoredValue(storedValue):
|
||||
persistentValuesStorage.set(value: storedValue)
|
||||
}
|
||||
)
|
||||
|
||||
if isDivActionURLHandled {
|
||||
return
|
||||
}
|
||||
|
||||
let info = context.info
|
||||
if !flags.useUrlHandlerForVisibilityActions,
|
||||
(info.source == .visibility || info.source == .disappear) {
|
||||
info.source == .visibility || info.source == .disappear {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
import LayoutKit
|
||||
|
||||
struct DivActionHandlingContext {
|
||||
let path: UIElementPath
|
||||
let info: DivActionInfo
|
||||
let expressionResolver: ExpressionResolver
|
||||
let variablesStorage: DivVariablesStorage
|
||||
let blockStateStorage: DivBlockStateStorage
|
||||
let actionHandler: DivActionHandler
|
||||
let updateCard: DivActionHandler.UpdateCardAction
|
||||
|
||||
var cardId: DivCardID {
|
||||
info.cardId
|
||||
}
|
||||
|
||||
var path: UIElementPath {
|
||||
info.path
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import CoreGraphics
|
||||
import Foundation
|
||||
import LayoutKit
|
||||
import VGSL
|
||||
|
||||
/// Deprecated. Use `DivActionHandler`.
|
||||
public final class DivActionURLHandler {
|
||||
public enum DivActionURLHandler {
|
||||
@frozen
|
||||
public enum UpdateReason {
|
||||
case patch(DivCardID, DivPatch)
|
||||
@@ -13,138 +11,4 @@ public final class DivActionURLHandler {
|
||||
case variable([DivCardID: Set<DivVariableName>])
|
||||
case external
|
||||
}
|
||||
|
||||
private let patchProvider: DivPatchProvider
|
||||
private let updateCard: DivActionHandler.UpdateCardAction
|
||||
private let persistentValuesStorage: DivPersistentValuesStorage
|
||||
private let setStateActionHandler: SetStateActionHandler
|
||||
private let scrollActionHandler: ScrollActionHandler
|
||||
private let timerActionHandler: TimerActionHandler
|
||||
private let tooltipActionHandler: TooltipActionHandler
|
||||
|
||||
init(
|
||||
patchProvider: DivPatchProvider,
|
||||
updateCard: @escaping DivActionHandler.UpdateCardAction,
|
||||
persistentValuesStorage: DivPersistentValuesStorage,
|
||||
scrollActionHandler: ScrollActionHandler,
|
||||
setStateActionHandler: SetStateActionHandler,
|
||||
timerActionHandler: TimerActionHandler,
|
||||
tooltipActionHandler: TooltipActionHandler
|
||||
) {
|
||||
self.patchProvider = patchProvider
|
||||
self.updateCard = updateCard
|
||||
self.persistentValuesStorage = persistentValuesStorage
|
||||
self.setStateActionHandler = setStateActionHandler
|
||||
self.scrollActionHandler = scrollActionHandler
|
||||
self.timerActionHandler = timerActionHandler
|
||||
self.tooltipActionHandler = tooltipActionHandler
|
||||
}
|
||||
|
||||
func handleURL(
|
||||
_ url: URL,
|
||||
info: DivActionInfo,
|
||||
context: DivActionHandlingContext,
|
||||
completion: @escaping (Result<Void, Error>) -> Void = { _ in }
|
||||
) -> Bool {
|
||||
guard let intent = DivActionIntent(url: url) else {
|
||||
return false
|
||||
}
|
||||
|
||||
let cardId = info.path.cardId
|
||||
switch intent {
|
||||
case let .showTooltip(id, multiple):
|
||||
let tooltipInfo = TooltipInfo(id: id, showsOnStart: false, multiple: multiple)
|
||||
tooltipActionHandler.showTooltip(tooltipInfo)
|
||||
case let .hideTooltip(id):
|
||||
tooltipActionHandler.hideTooltip(id: id)
|
||||
case let .download(patchUrl):
|
||||
patchProvider.getPatch(
|
||||
url: patchUrl,
|
||||
info: info,
|
||||
completion: { [unowned self] in
|
||||
self.applyPatch(cardId: cardId, result: $0, completion: completion)
|
||||
}
|
||||
)
|
||||
case let .setState(divStatePath, lifetime):
|
||||
setStateActionHandler.handle(
|
||||
divStatePath: divStatePath,
|
||||
lifetime: lifetime,
|
||||
context: context
|
||||
)
|
||||
case let .setVariable(name, value):
|
||||
context.variablesStorage.update(
|
||||
path: info.path,
|
||||
name: DivVariableName(rawValue: name),
|
||||
value: value
|
||||
)
|
||||
case let .setCurrentItem(id, index):
|
||||
scrollActionHandler.scrollToItem(cardId: cardId, id: id, index: index)
|
||||
case let .setNextItem(id, step, overflow):
|
||||
scrollActionHandler.scrollToNextItem(
|
||||
cardId: cardId,
|
||||
id: id,
|
||||
step: step,
|
||||
overflow: overflow
|
||||
)
|
||||
case let .setPreviousItem(id, step, overflow):
|
||||
scrollActionHandler.scrollToNextItem(
|
||||
cardId: cardId,
|
||||
id: id,
|
||||
step: -step,
|
||||
overflow: overflow
|
||||
)
|
||||
case let .scroll(id, mode):
|
||||
switch mode {
|
||||
case .start:
|
||||
scrollActionHandler.scrollToStart(cardId: cardId, id: id)
|
||||
case .end:
|
||||
scrollActionHandler.scrollToEnd(cardId: cardId, id: id)
|
||||
case let .forward(offset, overflow):
|
||||
scrollActionHandler.scrollToOffset(
|
||||
cardId: cardId,
|
||||
id: id,
|
||||
offset: offset,
|
||||
isRelative: true,
|
||||
overflow: overflow
|
||||
)
|
||||
case let .backward(offset, overflow):
|
||||
scrollActionHandler.scrollToOffset(
|
||||
cardId: cardId,
|
||||
id: id,
|
||||
offset: -offset,
|
||||
isRelative: true,
|
||||
overflow: overflow
|
||||
)
|
||||
case let .position(position):
|
||||
scrollActionHandler.scrollToOffset(cardId: cardId, id: id, offset: position)
|
||||
}
|
||||
case let .video(id: id, action: action):
|
||||
context.blockStateStorage.setState(
|
||||
id: id,
|
||||
cardId: cardId,
|
||||
state: VideoBlockViewState(state: action == .play ? .playing : .paused)
|
||||
)
|
||||
context.updateCard(.state(cardId))
|
||||
case let .timer(timerId, action):
|
||||
timerActionHandler.handle(cardId: cardId, timerId: timerId, action: action)
|
||||
case let .setStoredValue(storedValue):
|
||||
persistentValuesStorage.set(value: storedValue)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private func applyPatch(
|
||||
cardId: DivCardID,
|
||||
result: Result<DivPatch, Error>,
|
||||
completion: @escaping (Result<Void, Error>) -> Void
|
||||
) {
|
||||
switch result {
|
||||
case let .success(patch):
|
||||
updateCard(.patch(cardId, patch))
|
||||
completion(.success(()))
|
||||
case let .failure(error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import Foundation
|
||||
import VGSL
|
||||
|
||||
final class DownloadActionHandler {
|
||||
private let patchProvider: DivPatchProvider
|
||||
private let updateCard: DivActionHandler.UpdateCardAction
|
||||
|
||||
init(
|
||||
patchProvider: DivPatchProvider,
|
||||
updateCard: @escaping DivActionHandler.UpdateCardAction
|
||||
) {
|
||||
self.patchProvider = patchProvider
|
||||
self.updateCard = updateCard
|
||||
}
|
||||
|
||||
func handle(_ action: DivActionDownload, context: DivActionHandlingContext) {
|
||||
guard let urlString = action.resolveUrl(context.expressionResolver),
|
||||
let url = URL(string: urlString) else {
|
||||
return
|
||||
}
|
||||
|
||||
handle(
|
||||
url: url,
|
||||
context: context,
|
||||
onSuccessActions: action.onSuccessActions,
|
||||
onFailActions: action.onFailActions
|
||||
)
|
||||
}
|
||||
|
||||
func handle(
|
||||
url: URL,
|
||||
context: DivActionHandlingContext,
|
||||
onSuccessActions: [DivAction]?,
|
||||
onFailActions: [DivAction]?
|
||||
) {
|
||||
let info = context.info
|
||||
patchProvider.getPatch(
|
||||
url: url,
|
||||
info: info,
|
||||
completion: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let callbackActions: [DivAction]
|
||||
switch $0 {
|
||||
case let .success(patch):
|
||||
updateCard(.patch(info.cardId, patch))
|
||||
callbackActions = onSuccessActions ?? []
|
||||
case .failure:
|
||||
callbackActions = onFailActions ?? []
|
||||
}
|
||||
for action in callbackActions {
|
||||
context.actionHandler.handle(
|
||||
action,
|
||||
path: info.path,
|
||||
source: .callback,
|
||||
sender: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -5,18 +5,16 @@ final class FocusElementActionHandler {
|
||||
guard let elementId = action.resolveElementId(context.expressionResolver) else {
|
||||
return
|
||||
}
|
||||
let cardId = context.path.cardId
|
||||
|
||||
let cardId = context.cardId
|
||||
if let previousCard = context.blockStateStorage.getFocusedElement()?.cardId,
|
||||
previousCard != cardId {
|
||||
context.updateCard(.state(previousCard))
|
||||
}
|
||||
|
||||
let element = IdAndCardId(id: elementId, cardId: cardId)
|
||||
|
||||
context.blockStateStorage.setFocused(
|
||||
isFocused: true,
|
||||
element: element
|
||||
element: IdAndCardId(id: elementId, cardId: cardId)
|
||||
)
|
||||
context.updateCard(.state(cardId))
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ final class ScrollActionHandler {
|
||||
}
|
||||
|
||||
let itemCount = action.resolveItemCount(expressionResolver)
|
||||
let cardId = context.path.cardId
|
||||
let cardId = context.cardId
|
||||
if itemCount == 0 {
|
||||
let offset = action.resolveOffset(expressionResolver)
|
||||
scrollToOffset(
|
||||
@@ -47,7 +47,7 @@ final class ScrollActionHandler {
|
||||
return
|
||||
}
|
||||
|
||||
let cardId = context.path.cardId
|
||||
let cardId = context.cardId
|
||||
switch action.destination {
|
||||
case let .indexDestination(destination):
|
||||
if let index = destination.resolveValue(expressionResolver) {
|
||||
|
||||
@@ -26,7 +26,7 @@ final class SetStateActionHandler {
|
||||
lifetime: DivStateLifetime,
|
||||
context: DivActionHandlingContext
|
||||
) {
|
||||
let cardId = context.path.cardId
|
||||
let cardId = context.cardId
|
||||
let fullStatePath: DivStatePath = if let tooltipId = context.path.tooltipId,
|
||||
divStatePath.isLocal {
|
||||
DivStatePath.makeDivStatePath(
|
||||
|
||||
@@ -20,7 +20,7 @@ final class SubmitActionHandler {
|
||||
}
|
||||
|
||||
let containerData = context.variablesStorage.getVariables(
|
||||
cardId: context.path.cardId,
|
||||
cardId: context.cardId,
|
||||
elementId: containerId
|
||||
).map(
|
||||
key: { $0.rawValue },
|
||||
|
||||
@@ -19,7 +19,7 @@ final class TimerActionHandler {
|
||||
return
|
||||
}
|
||||
|
||||
handle(cardId: context.path.cardId, timerId: id, action: command.toDivTimerAction())
|
||||
handle(cardId: context.cardId, timerId: id, action: command.toDivTimerAction())
|
||||
}
|
||||
|
||||
func handle(cardId: DivCardID, timerId: String, action: DivTimerAction) {
|
||||
|
||||
@@ -8,20 +8,17 @@ final class VideoActionHandler {
|
||||
context: DivActionHandlingContext
|
||||
) {
|
||||
let expressionResolver = context.expressionResolver
|
||||
|
||||
guard let id = action.resolveId(expressionResolver),
|
||||
let command = action.resolveAction(expressionResolver) else {
|
||||
return
|
||||
}
|
||||
|
||||
let cardId = context.path.cardId
|
||||
|
||||
let cardId = context.cardId
|
||||
context.blockStateStorage.setState(
|
||||
id: id,
|
||||
cardId: cardId,
|
||||
state: VideoBlockViewState(state: command == .start ? .playing : .paused)
|
||||
)
|
||||
|
||||
context.updateCard(.state(cardId))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,22 @@ public protocol DivActionBase: Serializable {
|
||||
}
|
||||
|
||||
extension DivActionBase {
|
||||
func resolveInfo(
|
||||
_ expressionResolver: ExpressionResolver,
|
||||
path: UIElementPath,
|
||||
source: UserInterfaceAction.DivActionSource
|
||||
) -> DivActionInfo {
|
||||
DivActionInfo(
|
||||
path: path,
|
||||
logId: resolveLogId(expressionResolver) ?? "",
|
||||
url: resolveUrl(expressionResolver),
|
||||
logUrl: resolveLogUrl(expressionResolver),
|
||||
referer: resolveReferer(expressionResolver),
|
||||
source: source,
|
||||
payload: payload
|
||||
)
|
||||
}
|
||||
|
||||
func makeDivActionPayload(
|
||||
path: UIElementPath,
|
||||
source: UserInterfaceAction.DivActionSource,
|
||||
|
||||
@@ -4,6 +4,7 @@ import XCTest
|
||||
|
||||
final class DivActionHandlerTests: XCTestCase {
|
||||
private var flags: DivFlagsInfo = .default
|
||||
private var patchProvider = MockPatchProvider()
|
||||
private let reporter = MockReporter()
|
||||
private let stateManagement = DefaultDivStateManagement()
|
||||
private let variablesStorage = DivVariablesStorage()
|
||||
@@ -14,8 +15,10 @@ final class DivActionHandlerTests: XCTestCase {
|
||||
return DivActionHandler(
|
||||
flags: flags,
|
||||
idToPath: idToPath,
|
||||
patchProvider: patchProvider,
|
||||
reporter: reporter,
|
||||
stateManagement: stateManagement,
|
||||
updateCard: { self.lastUpdateReason = $0 },
|
||||
urlHandler: DivUrlHandlerDelegate { url, _ in
|
||||
self.handledUrl = url
|
||||
},
|
||||
@@ -24,13 +27,11 @@ final class DivActionHandlerTests: XCTestCase {
|
||||
}()
|
||||
|
||||
private var handledUrl: URL?
|
||||
private var lastUpdateReason: DivActionURLHandler.UpdateReason?
|
||||
|
||||
func test_UrlPassedToUrlHandler() {
|
||||
handle(
|
||||
divAction(
|
||||
logId: "test_log_id",
|
||||
url: "https://some.url"
|
||||
)
|
||||
divAction(url: "https://some.url")
|
||||
)
|
||||
|
||||
XCTAssertEqual(url("https://some.url"), handledUrl)
|
||||
@@ -38,10 +39,7 @@ final class DivActionHandlerTests: XCTestCase {
|
||||
|
||||
func test_UrlNotPassedToUrlHandler_VisibilityAction() {
|
||||
handle(
|
||||
divAction(
|
||||
logId: "test_log_id",
|
||||
url: "https://some.url"
|
||||
),
|
||||
divAction(url: "https://some.url"),
|
||||
source: .visibility
|
||||
)
|
||||
|
||||
@@ -50,10 +48,7 @@ final class DivActionHandlerTests: XCTestCase {
|
||||
|
||||
func test_UrlNotPassedToUrlHandler_DisappearAction() {
|
||||
handle(
|
||||
divAction(
|
||||
logId: "test_log_id",
|
||||
url: "https://some.url"
|
||||
),
|
||||
divAction(url: "https://some.url"),
|
||||
source: .disappear
|
||||
)
|
||||
|
||||
@@ -64,10 +59,7 @@ final class DivActionHandlerTests: XCTestCase {
|
||||
flags = DivFlagsInfo(useUrlHandlerForVisibilityActions: true)
|
||||
|
||||
handle(
|
||||
divAction(
|
||||
logId: "test_log_id",
|
||||
url: "https://some.url"
|
||||
),
|
||||
divAction(url: "https://some.url"),
|
||||
source: .visibility
|
||||
)
|
||||
|
||||
@@ -77,7 +69,6 @@ final class DivActionHandlerTests: XCTestCase {
|
||||
func test_UrlNotPassedToUrlHandler_IfTypedActionHandled() {
|
||||
handle(
|
||||
divAction(
|
||||
logId: "test_log_id",
|
||||
typed: .divActionSetVariable(
|
||||
DivActionSetVariable(
|
||||
value: stringValue("new value"),
|
||||
@@ -95,10 +86,7 @@ final class DivActionHandlerTests: XCTestCase {
|
||||
variablesStorage.set(cardId: cardId, variables: ["host": .string("test.url")])
|
||||
|
||||
handle(
|
||||
divAction(
|
||||
logId: "test_log_id",
|
||||
urlExpression: "https://@{host}"
|
||||
)
|
||||
divAction(urlExpression: "https://@{host}")
|
||||
)
|
||||
|
||||
XCTAssertEqual(url("https://test.url"), handledUrl)
|
||||
@@ -108,10 +96,7 @@ final class DivActionHandlerTests: XCTestCase {
|
||||
variablesStorage.set(cardId: cardId, variables: ["host": .string("test.url")])
|
||||
|
||||
handle(
|
||||
divAction(
|
||||
logId: "test_log_id",
|
||||
urlExpression: "https://@{host}"
|
||||
),
|
||||
divAction(urlExpression: "https://@{host}"),
|
||||
localValues: ["host": "localhost"]
|
||||
)
|
||||
|
||||
@@ -304,7 +289,6 @@ final class DivActionHandlerTests: XCTestCase {
|
||||
|
||||
handle(
|
||||
divAction(
|
||||
logId: "log_id",
|
||||
typed: .divActionDictSetValue(DivActionDictSetValue(
|
||||
key: .value("key"),
|
||||
value: .dictValue(DictValue(value: ["new_key": "new value"])),
|
||||
@@ -347,10 +331,71 @@ final class DivActionHandlerTests: XCTestCase {
|
||||
XCTAssertEqual(["one", "two"], getVariableValue("array_var"))
|
||||
}
|
||||
|
||||
func test_DownloadAction_updateCardIsCalled() {
|
||||
let expectedPatch = DivPatch(
|
||||
changes: [
|
||||
DivPatch.Change(id: "id", items: [ divText() ])
|
||||
]
|
||||
)
|
||||
patchProvider = MockPatchProvider {
|
||||
$0(.success(expectedPatch))
|
||||
}
|
||||
|
||||
handle(.divActionDownload(
|
||||
DivActionDownload(
|
||||
onSuccessActions: [
|
||||
divAction(url: "result://success"),
|
||||
],
|
||||
url: .value("https://download.url")
|
||||
)
|
||||
))
|
||||
|
||||
switch lastUpdateReason {
|
||||
case let .patch(cardId, patch):
|
||||
XCTAssertEqual("test_card", cardId)
|
||||
XCTAssertEqual(expectedPatch, patch)
|
||||
default:
|
||||
XCTFail("UpdateReason.patch expected")
|
||||
}
|
||||
}
|
||||
|
||||
func test_DownloadAction_onSuccessActionIsCalled() {
|
||||
patchProvider = MockPatchProvider {
|
||||
$0(.success(DivPatch(changes: [])))
|
||||
}
|
||||
|
||||
handle(.divActionDownload(
|
||||
DivActionDownload(
|
||||
onSuccessActions: [
|
||||
divAction(url: "result://success"),
|
||||
],
|
||||
url: .value("https://download.url")
|
||||
)
|
||||
))
|
||||
|
||||
XCTAssertEqual(url("result://success"), handledUrl)
|
||||
}
|
||||
|
||||
func test_DownloadAction_onFailActionIsCalled() {
|
||||
patchProvider = MockPatchProvider {
|
||||
$0(.failure(ExpressionError("Error")))
|
||||
}
|
||||
|
||||
handle(.divActionDownload(
|
||||
DivActionDownload(
|
||||
onFailActions: [
|
||||
divAction(url: "result://error"),
|
||||
],
|
||||
url: .value("https://download.url")
|
||||
)
|
||||
))
|
||||
|
||||
XCTAssertEqual(url("result://error"), handledUrl)
|
||||
}
|
||||
|
||||
func test_SetStateAction_SetsState() {
|
||||
handle(
|
||||
divAction(
|
||||
logId: "log_id",
|
||||
typed: .divActionSetState(DivActionSetState(
|
||||
stateId: .value("0/div_state/state1")
|
||||
))
|
||||
@@ -366,7 +411,6 @@ final class DivActionHandlerTests: XCTestCase {
|
||||
func test_SetStateAction_InTooltip_SetsMainCardState() {
|
||||
handle(
|
||||
divAction(
|
||||
logId: "log_id",
|
||||
typed: .divActionSetState(DivActionSetState(
|
||||
stateId: .value("0/div_state/state1")
|
||||
))
|
||||
@@ -383,7 +427,6 @@ final class DivActionHandlerTests: XCTestCase {
|
||||
func test_SetStateAction_InTooltip_SetsTooltipState() {
|
||||
handle(
|
||||
divAction(
|
||||
logId: "log_id",
|
||||
typed: .divActionSetState(DivActionSetState(
|
||||
stateId: .value("div_state_in_tooltip/state1")
|
||||
))
|
||||
@@ -450,7 +493,6 @@ final class DivActionHandlerTests: XCTestCase {
|
||||
|
||||
handle(
|
||||
divAction(
|
||||
logId: "log_id",
|
||||
typed: .divActionSetVariable(DivActionSetVariable(
|
||||
value: stringValue("new value"),
|
||||
variableName: .value("local_var")
|
||||
@@ -474,7 +516,6 @@ final class DivActionHandlerTests: XCTestCase {
|
||||
|
||||
handle(
|
||||
divAction(
|
||||
logId: "log_id",
|
||||
scopeId: "element_id",
|
||||
typed: .divActionSetVariable(DivActionSetVariable(
|
||||
value: stringValue("new value"),
|
||||
@@ -525,7 +566,7 @@ final class DivActionHandlerTests: XCTestCase {
|
||||
|
||||
private func handle(_ action: DivActionTyped) {
|
||||
actionHandler.handle(
|
||||
divAction(logId: "log_id", typed: action),
|
||||
divAction(typed: action),
|
||||
path: cardId.path,
|
||||
source: .tap,
|
||||
sender: nil
|
||||
|
||||
@@ -8,6 +8,7 @@ extension DivActionHandler {
|
||||
blockStateStorage: DivBlockStateStorage = DivBlockStateStorage(),
|
||||
flags: DivFlagsInfo = .default,
|
||||
idToPath: IdToPath = IdToPath(),
|
||||
patchProvider: DivPatchProvider = MockPatchProvider(),
|
||||
persistentValuesStorage: DivPersistentValuesStorage = DivPersistentValuesStorage(),
|
||||
reporter: DivReporter = DefaultDivReporter(),
|
||||
stateManagement: DivStateManagement = DefaultDivStateManagement(),
|
||||
@@ -18,7 +19,7 @@ extension DivActionHandler {
|
||||
self.init(
|
||||
stateUpdater: stateManagement,
|
||||
blockStateStorage: blockStateStorage,
|
||||
patchProvider: MockPatchProvider(),
|
||||
patchProvider: patchProvider,
|
||||
submitter: MockSubmitter(),
|
||||
variablesStorage: variablesStorage,
|
||||
functionsStorage: nil,
|
||||
@@ -55,7 +56,17 @@ private final class MockSubmitter: DivSubmitter {
|
||||
}
|
||||
|
||||
final class MockPatchProvider: DivPatchProvider {
|
||||
func getPatch(url _: URL, completion _: @escaping DivPatchProviderCompletion) {}
|
||||
private let delegate: (DivPatchProviderCompletion) -> Void
|
||||
|
||||
init(
|
||||
delegate: @escaping (DivPatchProviderCompletion) -> Void = { _ in }
|
||||
) {
|
||||
self.delegate = delegate
|
||||
}
|
||||
|
||||
func getPatch(url _: URL, completion: @escaping DivPatchProviderCompletion) {
|
||||
delegate(completion)
|
||||
}
|
||||
|
||||
func cancelRequests() {}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import VGSL
|
||||
|
||||
func divAction(
|
||||
isEnabled: Bool = true,
|
||||
logId: String,
|
||||
logId: String = "test",
|
||||
payload: [String: Any]? = nil,
|
||||
scopeId: String? = nil,
|
||||
typed: DivActionTyped? = nil,
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
},
|
||||
"platforms": [
|
||||
"android",
|
||||
"ios",
|
||||
"web"
|
||||
],
|
||||
"required": [
|
||||
|
||||
Reference in New Issue
Block a user