Skip to content

Commit

Permalink
Release 28.4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
robot-divkit committed Oct 2, 2023
1 parent 0144edd commit 497c332
Show file tree
Hide file tree
Showing 21 changed files with 527 additions and 221 deletions.
5 changes: 5 additions & 0 deletions .mapping.json
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,7 @@
"Specs/DivKit/28.1.0/DivKit.podspec":"divkit/public-ios/Specs/DivKit/28.1.0/DivKit.podspec",
"Specs/DivKit/28.2.0/DivKit.podspec":"divkit/public-ios/Specs/DivKit/28.2.0/DivKit.podspec",
"Specs/DivKit/28.3.0/DivKit.podspec":"divkit/public-ios/Specs/DivKit/28.3.0/DivKit.podspec",
"Specs/DivKit/28.4.0/DivKit.podspec":"divkit/public-ios/Specs/DivKit/28.4.0/DivKit.podspec",
"Specs/DivKitExtensions/24.3.0/DivKitExtensions.podspec":"divkit/public-ios/Specs/DivKitExtensions/24.3.0/DivKitExtensions.podspec",
"Specs/DivKitExtensions/25.0.0/DivKitExtensions.podspec":"divkit/public-ios/Specs/DivKitExtensions/25.0.0/DivKitExtensions.podspec",
"Specs/DivKitExtensions/25.1.0/DivKitExtensions.podspec":"divkit/public-ios/Specs/DivKitExtensions/25.1.0/DivKitExtensions.podspec",
Expand All @@ -828,18 +829,22 @@
"Specs/DivKitExtensions/28.1.0/DivKitExtensions.podspec":"divkit/public-ios/Specs/DivKitExtensions/28.1.0/DivKitExtensions.podspec",
"Specs/DivKitExtensions/28.2.0/DivKitExtensions.podspec":"divkit/public-ios/Specs/DivKitExtensions/28.2.0/DivKitExtensions.podspec",
"Specs/DivKitExtensions/28.3.0/DivKitExtensions.podspec":"divkit/public-ios/Specs/DivKitExtensions/28.3.0/DivKitExtensions.podspec",
"Specs/DivKitExtensions/28.4.0/DivKitExtensions.podspec":"divkit/public-ios/Specs/DivKitExtensions/28.4.0/DivKitExtensions.podspec",
"Specs/DivKit_LayoutKit/28.0.1/DivKit_LayoutKit.podspec":"divkit/public-ios/Specs/DivKit_LayoutKit/28.0.1/DivKit_LayoutKit.podspec",
"Specs/DivKit_LayoutKit/28.1.0/DivKit_LayoutKit.podspec":"divkit/public-ios/Specs/DivKit_LayoutKit/28.1.0/DivKit_LayoutKit.podspec",
"Specs/DivKit_LayoutKit/28.2.0/DivKit_LayoutKit.podspec":"divkit/public-ios/Specs/DivKit_LayoutKit/28.2.0/DivKit_LayoutKit.podspec",
"Specs/DivKit_LayoutKit/28.3.0/DivKit_LayoutKit.podspec":"divkit/public-ios/Specs/DivKit_LayoutKit/28.3.0/DivKit_LayoutKit.podspec",
"Specs/DivKit_LayoutKit/28.4.0/DivKit_LayoutKit.podspec":"divkit/public-ios/Specs/DivKit_LayoutKit/28.4.0/DivKit_LayoutKit.podspec",
"Specs/DivKit_LayoutKitInterface/28.0.1/DivKit_LayoutKitInterface.podspec":"divkit/public-ios/Specs/DivKit_LayoutKitInterface/28.0.1/DivKit_LayoutKitInterface.podspec",
"Specs/DivKit_LayoutKitInterface/28.1.0/DivKit_LayoutKitInterface.podspec":"divkit/public-ios/Specs/DivKit_LayoutKitInterface/28.1.0/DivKit_LayoutKitInterface.podspec",
"Specs/DivKit_LayoutKitInterface/28.2.0/DivKit_LayoutKitInterface.podspec":"divkit/public-ios/Specs/DivKit_LayoutKitInterface/28.2.0/DivKit_LayoutKitInterface.podspec",
"Specs/DivKit_LayoutKitInterface/28.3.0/DivKit_LayoutKitInterface.podspec":"divkit/public-ios/Specs/DivKit_LayoutKitInterface/28.3.0/DivKit_LayoutKitInterface.podspec",
"Specs/DivKit_LayoutKitInterface/28.4.0/DivKit_LayoutKitInterface.podspec":"divkit/public-ios/Specs/DivKit_LayoutKitInterface/28.4.0/DivKit_LayoutKitInterface.podspec",
"Specs/DivKit_Serialization/28.0.1/DivKit_Serialization.podspec":"divkit/public-ios/Specs/DivKit_Serialization/28.0.1/DivKit_Serialization.podspec",
"Specs/DivKit_Serialization/28.1.0/DivKit_Serialization.podspec":"divkit/public-ios/Specs/DivKit_Serialization/28.1.0/DivKit_Serialization.podspec",
"Specs/DivKit_Serialization/28.2.0/DivKit_Serialization.podspec":"divkit/public-ios/Specs/DivKit_Serialization/28.2.0/DivKit_Serialization.podspec",
"Specs/DivKit_Serialization/28.3.0/DivKit_Serialization.podspec":"divkit/public-ios/Specs/DivKit_Serialization/28.3.0/DivKit_Serialization.podspec",
"Specs/DivKit_Serialization/28.4.0/DivKit_Serialization.podspec":"divkit/public-ios/Specs/DivKit_Serialization/28.4.0/DivKit_Serialization.podspec",
"Specs/LayoutKit/24.3.0/LayoutKit.podspec":"divkit/public-ios/Specs/LayoutKit/24.3.0/LayoutKit.podspec",
"Specs/LayoutKit/25.0.0/LayoutKit.podspec":"divkit/public-ios/Specs/LayoutKit/25.0.0/LayoutKit.podspec",
"Specs/LayoutKit/25.1.0/LayoutKit.podspec":"divkit/public-ios/Specs/LayoutKit/25.1.0/LayoutKit.podspec",
Expand Down
2 changes: 1 addition & 1 deletion DivKit/DivBlockModelingContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ public struct DivBlockModelingContext {
return extensions.compactMap {
let id = $0.id
if !extensionHandlers.keys.contains(id) && !stateInterceptors.keys.contains(id) {
addError(message: "No DivExtensionHandler/DivStateInterceptor for: \(id)")
addError(message: "No DivExtensionHandler for: \(id)")
}
return extensionHandlers[id]
}
Expand Down
31 changes: 22 additions & 9 deletions DivKit/DivBlockStateStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import LayoutKit
public final class DivBlockStateStorage {
public private(set) var states: BlocksState
private var statesById: [IdAndCardId: ElementState] = [:]
private let lock = RWLock()

public init(states: BlocksState = [:]) {
self.states = states
Expand All @@ -17,7 +18,9 @@ public final class DivBlockStateStorage {
}

public func getStateUntyped(_ path: UIElementPath) -> ElementState? {
statesById[IdAndCardId(path: path)] ?? states[path]
lock.read {
statesById[IdAndCardId(path: path)] ?? states[path]
}
}

@inlinable
Expand All @@ -27,26 +30,36 @@ public final class DivBlockStateStorage {

public func getStateUntyped(_ id: String, cardId: DivCardID) -> ElementState? {
let idKey = IdAndCardId(id: id, cardId: cardId)
return statesById[idKey] ?? states.first { IdAndCardId(path: $0.key) == idKey }?.value
return lock.read {
statesById[idKey] ?? states.first { IdAndCardId(path: $0.key) == idKey }?.value
}
}

public func setState(path: UIElementPath, state: ElementState) {
statesById[IdAndCardId(path: path)] = nil
states[path] = state
lock.write {
statesById[IdAndCardId(path: path)] = nil
states[path] = state
}
}

public func setState(id: String, cardId: DivCardID, state: ElementState) {
statesById[IdAndCardId(id: id, cardId: cardId)] = state
lock.write {
statesById[IdAndCardId(id: id, cardId: cardId)] = state
}
}

public func reset() {
states = [:]
statesById = [:]
lock.write {
states = [:]
statesById = [:]
}
}

public func reset(cardId: DivCardID) {
states = states.filter { $0.key.root != cardId.rawValue }
statesById = statesById.filter { $0.key.cardId != cardId }
lock.write {
states = states.filter { $0.key.root != cardId.rawValue }
statesById = statesById.filter { $0.key.cardId != cardId }
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion DivKit/DivKitInfo.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
public enum DivKitInfo {
public static let version = "28.3.0"
public static let version = "28.4.0"
}
183 changes: 119 additions & 64 deletions DivKit/Extensions/DivSliderExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,42 @@ extension DivSlider: DivBlockModeling {

private func makeBaseBlock(context: DivBlockModelingContext) throws -> Block {
let expressionResolver = context.expressionResolver

let firstThumbValue: Binding<Int> = thumbValueVariable.flatMap {
context.makeBinding(variableName: $0, defaultValue: 0)
} ?? .zero
let firstThumb = SliderModel.ThumbModel(
block: makeThumbBlock(
thumb: thumbStyle
.makeBlock(context: context, corners: .all),
textBlock: thumbTextStyle?.makeThumbTextBlock(
context: context,
value: firstThumbValue.value
),
textOffset: thumbTextStyle.flatMap {
CGPoint(
x: $0.offset?.x.resolveValue(expressionResolver) ?? 0,
y: $0.offset?.y.resolveValue(expressionResolver) ?? 0
)
} ?? .zero
),
value: firstThumbValue,
size: CGSize(
width: thumbStyle.getWidth(context: context),
height: thumbStyle.getHeight(context: context)
),
offsetX: thumbTextStyle?.offset?.x.resolveValue(expressionResolver) ?? 0,
offsetY: thumbTextStyle?.offset?.y.resolveValue(expressionResolver) ?? 0
)
let secondThumb: SliderModel.ThumbModel?
if let thumbSecondaryStyle = thumbSecondaryStyle,
let thumbSecondaryValueVariable = thumbSecondaryValueVariable {
if let thumbSecondaryValueVariable = thumbSecondaryValueVariable {
let secondThumbValue = context.makeBinding(
variableName: thumbSecondaryValueVariable,
defaultValue: 0
)
secondThumb = SliderModel.ThumbModel(
block: makeThumbBlock(
thumb: thumbSecondaryStyle
thumb: thumbSecondaryStyle?.makeBlock(context: context, corners: .all) ?? thumbStyle
.makeBlock(context: context, corners: .all),
textBlock: (thumbSecondaryTextStyle ?? thumbTextStyle)?.makeThumbTextBlock(
context: context,
Expand All @@ -43,8 +69,10 @@ extension DivSlider: DivBlockModeling {
),
value: secondThumbValue,
size: CGSize(
width: thumbSecondaryStyle.getWidth(context: context),
height: thumbSecondaryStyle.getHeight(context: context)
width: thumbSecondaryStyle?.getWidth(context: context) ?? thumbStyle
.getWidth(context: context),
height: thumbSecondaryStyle?.getHeight(context: context) ?? thumbStyle
.getHeight(context: context)
),
offsetX: thumbSecondaryTextStyle?.offset?.x.resolveValue(expressionResolver) ?? 0,
offsetY: thumbSecondaryTextStyle?.offset?.y.resolveValue(expressionResolver) ?? 0
Expand All @@ -53,90 +81,117 @@ extension DivSlider: DivBlockModeling {
secondThumb = nil
}

let firstThumbValue: Binding<Int> = thumbValueVariable.flatMap {
context.makeBinding(variableName: $0, defaultValue: 0)
} ?? .zero

let activeMark = makeRoundedRectangle(with: tickMarkActiveStyle, resolver: expressionResolver)
let inactiveMark = makeRoundedRectangle(
with: tickMarkInactiveStyle,
resolver: expressionResolver
)

let minValue = resolveMinValue(expressionResolver)
let maxValue = resolveMaxValue(expressionResolver)

let marksConfiguration = MarksConfiguration(
minValue: CGFloat(resolveMinValue(expressionResolver)),
maxValue: CGFloat(resolveMaxValue(expressionResolver)),
minValue: CGFloat(minValue),
maxValue: CGFloat(maxValue),
activeMark: activeMark ?? .empty,
inactiveMark: inactiveMark ?? .empty,
layoutDirection: context.layoutDirection
)

let sliderRanges = makeRanges(ranges, with: context)

let sliderModel = SliderModel(
firstThumb: SliderModel.ThumbModel(
block: makeThumbBlock(
thumb: thumbStyle
.makeBlock(context: context, corners: .all),
textBlock: thumbTextStyle?.makeThumbTextBlock(
context: context,
value: firstThumbValue.value
),
textOffset: thumbTextStyle.flatMap {
CGPoint(
x: $0.offset?.x.resolveValue(expressionResolver) ?? 0,
y: $0.offset?.y.resolveValue(expressionResolver) ?? 0
)
} ?? .zero
),
value: firstThumbValue,
size: CGSize(
width: thumbStyle.getWidth(context: context),
height: thumbStyle.getHeight(context: context)
),
offsetX: thumbTextStyle?.offset?.x.resolveValue(expressionResolver) ?? 0,
offsetY: thumbTextStyle?.offset?.y.resolveValue(expressionResolver) ?? 0
),
firstThumb: firstThumb,
secondThumb: secondThumb,
activeMarkModel: tickMarkActiveStyle.flatMap {
SliderModel.MarkModel(
block: $0.makeBlock(context: context, corners: .all),
size: CGSize(
width: $0.getWidth(context: context),
height: $0.getHeight(context: context)
)
)
},
inactiveMarkModel: tickMarkInactiveStyle.flatMap {
SliderModel.MarkModel(
block: $0.makeBlock(context: context, corners: .all),
size: CGSize(
width: $0.getWidth(context: context),
height: $0.getHeight(context: context)
)
)
},
minValue: resolveMinValue(expressionResolver),
maxValue: resolveMaxValue(expressionResolver),
activeTrack: self.trackActiveStyle.makeBlock(
context: context,
widthTrait: .resizable,
corners: .all
),
inactiveTrack: self.trackInactiveStyle.makeBlock(
context: context,
widthTrait: .resizable,
corners: .all
),
minValue: minValue,
maxValue: maxValue,
marksConfiguration: marksConfiguration,
ranges: sliderRanges,
layoutDirection: context.layoutDirection
)

let width = context.override(width: width)
let height = context.override(height: height)

return SliderBlock(
sliderModel: sliderModel,
widthTrait: width.makeLayoutTrait(with: expressionResolver),
heightTrait: height.makeLayoutTrait(with: expressionResolver)
)
}

private func makeRanges(
_ ranges: [DivSlider.Range]?,
with context: DivBlockModelingContext
) -> [SliderModel.RangeModel] {
let expressionResolver = context.expressionResolver

let minValue = resolveMinValue(expressionResolver)
let maxValue = resolveMaxValue(expressionResolver)

var sliderRanges: [SliderModel.RangeModel] = (ranges ?? []).map { range in
SliderModel.RangeModel(
start: range.resolveStart(expressionResolver) ?? minValue,
end: range.resolveEnd(expressionResolver) ?? maxValue,
margins: range.margins.makeEdgeInsets(context: context),
activeTrack: range.trackActiveStyle?.makeBlock(
context: context,
widthTrait: .resizable,
corners: .all
) ?? trackActiveStyle.makeBlock(
context: context,
widthTrait: .resizable,
corners: .all
),
inactiveTrack: range.trackInactiveStyle?.makeBlock(
context: context,
widthTrait: .resizable,
corners: .all
) ?? trackInactiveStyle.makeBlock(
context: context,
widthTrait: .resizable,
corners: .all
)
)
}

let makeBasicRange: (Int, Int, CGRect.Corners) -> SliderModel.RangeModel = { [self] in
SliderModel.RangeModel(
start: $0,
end: $1,
margins: EdgeInsets.zero,
activeTrack: trackActiveStyle.makeBlock(
context: context,
widthTrait: .resizable,
corners: $2
),
inactiveTrack: trackInactiveStyle.makeBlock(
context: context,
widthTrait: .resizable,
corners: $2
)
)
}

sliderRanges.sort { $0.start < $1.start }

var lastRangeEnd = minValue
for (index, range) in sliderRanges.enumerated() {
if range.start != lastRangeEnd {
let corner: CGRect.Corners = index == 0 ? .left : .all
sliderRanges.append(makeBasicRange(lastRangeEnd, range.start, corner))
}
lastRangeEnd = range.end
}
if lastRangeEnd != maxValue {
let corner: CGRect.Corners = sliderRanges.count == 0 ? .all : .right
sliderRanges.append(makeBasicRange(lastRangeEnd, maxValue, corner))
}

sliderRanges.sort { $0.start < $1.start }

return sliderRanges
}
}

private func makeThumbBlock(
Expand Down
12 changes: 11 additions & 1 deletion DivKit/Extensions/DivStateExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,23 @@ extension DivState: DivBlockModeling {

let stateInterceptor = context.getStateInterceptor(for: self)
let divStatePath = context.parentDivStatePath + id
let defaultStateId = resolveDefaultStateId(context.expressionResolver)
let stateManager = context.stateManager
if let stateIdVariable {
let stateBinding = context.makeBinding(
variableName: stateIdVariable,
defaultValue: defaultStateId ?? states[0].stateId
)
stateManager.setState(stateBlockPath: divStatePath, stateBinding: stateBinding)
} else {
stateManager.resetBinding(for: divStatePath)
}
let stateManagerItem = stateManager.get(stateBlockPath: divStatePath)

let expressionResolver = context.expressionResolver
let activeState = stateInterceptor?.getAppropriateState(divState: self, context: context)
?? states.first { $0.stateId == stateManagerItem?.currentStateID.rawValue }
?? states.first { $0.stateId == resolveDefaultStateId(expressionResolver) }
?? states.first { $0.stateId == defaultStateId }
?? states[0]
let activeStateID = DivStateID(rawValue: activeState.stateId)
let activeStatePath = divStatePath + activeStateID
Expand Down
Loading

0 comments on commit 497c332

Please sign in to comment.