- custom poll emoji input

- avatars in forward info
- ban user sheet
This commit is contained in:
Isaac
2024-04-16 23:42:39 +04:00
parent a9c8ae8595
commit 5123b841c3
39 changed files with 4240 additions and 789 deletions

View File

@@ -88,8 +88,6 @@ public final class ListSectionContentView: UIView {
super.init(frame: CGRect())
self.clipsToBounds = true
self.layer.addSublayer(self.contentSeparatorContainerLayer)
self.layer.addSublayer(self.contentHighlightContainerLayer)
self.addSubview(self.contentItemContainerView)
@@ -132,9 +130,16 @@ public final class ListSectionContentView: UIView {
}
}
public func update(configuration: Configuration, width: CGFloat, readyItems: [ReadyItem], transition: Transition) -> UpdateResult {
public func update(configuration: Configuration, width: CGFloat, leftInset: CGFloat, readyItems: [ReadyItem], transition: Transition) -> UpdateResult {
self.configuration = configuration
switch configuration.background {
case .all, .range:
self.clipsToBounds = true
case let .none(clipped):
self.clipsToBounds = clipped
}
let backgroundColor: UIColor
if self.highlightedItemId != nil && configuration.extendsItemHighlightToSection {
backgroundColor = configuration.theme.list.itemHighlightedBackgroundColor
@@ -149,9 +154,11 @@ public final class ListSectionContentView: UIView {
let readyItem = readyItems[index]
validItemIds.append(readyItem.id)
let itemFrame = CGRect(origin: CGPoint(x: 0.0, y: innerContentHeight), size: readyItem.size)
let itemFrame = CGRect(origin: CGPoint(x: leftInset, y: innerContentHeight), size: readyItem.size)
if let itemComponentView = readyItem.itemView.contents.view {
var isAdded = false
if itemComponentView.superview == nil {
isAdded = true
readyItem.itemView.addSubview(itemComponentView)
self.contentItemContainerView.addSubview(readyItem.itemView)
self.contentSeparatorContainerLayer.addSublayer(readyItem.itemView.separatorLayer)
@@ -174,7 +181,26 @@ public final class ListSectionContentView: UIView {
if let itemComponentView = itemComponentView as? ListSectionComponentChildView {
separatorInset = itemComponentView.separatorInset
}
readyItem.transition.setFrame(view: readyItem.itemView, frame: itemFrame)
let itemSeparatorFrame = CGRect(origin: CGPoint(x: separatorInset, y: itemFrame.maxY - UIScreenPixel), size: CGSize(width: width - separatorInset, height: UIScreenPixel))
if isAdded && itemComponentView is ListSubSectionComponent.View {
readyItem.itemView.frame = itemFrame
readyItem.itemView.clipsToBounds = true
readyItem.itemView.frame = CGRect(origin: CGPoint(x: itemFrame.minX, y: itemFrame.minY), size: CGSize(width: itemFrame.width, height: 0.0))
let itemView = readyItem.itemView
transition.setFrame(view: readyItem.itemView, frame: itemFrame, completion: { [weak itemView] completed in
if completed {
itemView?.clipsToBounds = false
}
})
readyItem.itemView.separatorLayer.frame = CGRect(origin: CGPoint(x: itemSeparatorFrame.minX, y: itemFrame.minY), size: CGSize(width: itemSeparatorFrame.width, height: 0.0))
transition.setFrame(layer: readyItem.itemView.separatorLayer, frame: itemSeparatorFrame)
} else {
readyItem.transition.setFrame(view: readyItem.itemView, frame: itemFrame)
readyItem.transition.setFrame(layer: readyItem.itemView.separatorLayer, frame: itemSeparatorFrame)
}
let itemSeparatorTopOffset: CGFloat = index == 0 ? 0.0 : -UIScreenPixel
let itemHighlightFrame = CGRect(origin: CGPoint(x: itemFrame.minX, y: itemFrame.minY + itemSeparatorTopOffset), size: CGSize(width: itemFrame.width, height: itemFrame.height - itemSeparatorTopOffset))
@@ -182,9 +208,6 @@ public final class ListSectionContentView: UIView {
readyItem.transition.setFrame(view: itemComponentView, frame: CGRect(origin: CGPoint(), size: itemFrame.size))
let itemSeparatorFrame = CGRect(origin: CGPoint(x: separatorInset, y: itemFrame.maxY - UIScreenPixel), size: CGSize(width: width - separatorInset, height: UIScreenPixel))
readyItem.transition.setFrame(layer: readyItem.itemView.separatorLayer, frame: itemSeparatorFrame)
let separatorAlpha: CGFloat
if configuration.displaySeparators {
if index != readyItems.count - 1 {
@@ -206,6 +229,12 @@ public final class ListSectionContentView: UIView {
if !validItemIds.contains(id) {
removedItemIds.append(id)
if let itemComponentView = itemView.contents.view, itemComponentView is ListSubSectionComponent.View {
itemView.clipsToBounds = true
transition.setFrame(view: itemView, frame: CGRect(origin: itemView.frame.origin, size: CGSize(width: itemView.bounds.width, height: 0.0)))
transition.setFrame(layer: itemView.separatorLayer, frame: CGRect(origin: CGPoint(x: itemView.separatorLayer.frame.minX, y: itemView.frame.minY), size: itemView.separatorLayer.bounds.size))
}
transition.setAlpha(view: itemView, alpha: 0.0, completion: { [weak itemView] _ in
itemView?.removeFromSuperview()
})
@@ -328,8 +357,6 @@ public final class ListSectionComponent: Component {
private var header: ComponentView<Empty>?
private var footer: ComponentView<Empty>?
private var highlightedItemId: AnyHashable?
private var component: ListSectionComponent?
public override init(frame: CGRect) {
@@ -345,6 +372,10 @@ public final class ListSectionComponent: Component {
preconditionFailure()
}
public func itemView(id: AnyHashable) -> UIView? {
return self.contentView.itemViews[id]?.contents.view
}
func update(component: ListSectionComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
self.component = component
@@ -422,6 +453,7 @@ public final class ListSectionComponent: Component {
background: component.background
),
width: availableSize.width,
leftInset: 0.0,
readyItems: readyItems,
transition: transition
)
@@ -483,3 +515,135 @@ public final class ListSectionComponent: Component {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}
public final class ListSubSectionComponent: Component {
public typealias ChildView = ListSectionComponentChildView
public let theme: PresentationTheme
public let leftInset: CGFloat
public let items: [AnyComponentWithIdentity<Empty>]
public let displaySeparators: Bool
public init(
theme: PresentationTheme,
leftInset: CGFloat,
items: [AnyComponentWithIdentity<Empty>],
displaySeparators: Bool = true
) {
self.theme = theme
self.leftInset = leftInset
self.items = items
self.displaySeparators = displaySeparators
}
public static func ==(lhs: ListSubSectionComponent, rhs: ListSubSectionComponent) -> Bool {
if lhs.theme !== rhs.theme {
return false
}
if lhs.leftInset != rhs.leftInset {
return false
}
if lhs.items != rhs.items {
return false
}
if lhs.displaySeparators != rhs.displaySeparators {
return false
}
return true
}
public final class View: UIView, ListSectionComponent.ChildView {
private let contentView: ListSectionContentView
private var component: ListSubSectionComponent?
public var customUpdateIsHighlighted: ((Bool) -> Void)?
public var separatorInset: CGFloat = 0.0
public override init(frame: CGRect) {
self.contentView = ListSectionContentView()
super.init(frame: CGRect())
self.addSubview(self.contentView)
}
required public init?(coder: NSCoder) {
preconditionFailure()
}
public func itemView(id: AnyHashable) -> UIView? {
return self.contentView.itemViews[id]?.contents.view
}
func update(component: ListSubSectionComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
self.component = component
var contentHeight: CGFloat = 0.0
var readyItems: [ListSectionContentView.ReadyItem] = []
for i in 0 ..< component.items.count {
let item = component.items[i]
let itemId = item.id
let itemView: ListSectionContentView.ItemView
var itemTransition = transition
if let current = self.contentView.itemViews[itemId] {
itemView = current
} else {
itemTransition = itemTransition.withAnimation(.none)
itemView = ListSectionContentView.ItemView()
self.contentView.itemViews[itemId] = itemView
itemView.contents.parentState = state
}
let itemSize = itemView.contents.update(
transition: itemTransition,
component: item.component,
environment: {},
containerSize: CGSize(width: availableSize.width - component.leftInset, height: availableSize.height)
)
readyItems.append(ListSectionContentView.ReadyItem(
id: itemId,
itemView: itemView,
size: itemSize,
transition: itemTransition
))
}
let contentResult = self.contentView.update(
configuration: ListSectionContentView.Configuration(
theme: component.theme,
displaySeparators: component.displaySeparators,
extendsItemHighlightToSection: false,
background: .none(clipped: false)
),
width: availableSize.width - component.leftInset,
leftInset: 0.0,
readyItems: readyItems,
transition: transition
)
let innerContentHeight = contentResult.size.height
let contentFrame = CGRect(origin: CGPoint(x: component.leftInset, y: contentHeight), size: CGSize(width: availableSize.width - component.leftInset, height: innerContentHeight))
transition.setFrame(view: self.contentView, frame: contentFrame)
transition.setFrame(view: self.contentView.externalContentBackgroundView, frame: contentResult.backgroundFrame.offsetBy(dx: contentFrame.minX, dy: contentFrame.minY))
contentHeight += innerContentHeight
self.separatorInset = component.leftInset
return CGSize(width: availableSize.width, height: contentHeight)
}
}
public func makeView() -> View {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}