This commit is contained in:
Isaac 2025-09-18 14:15:51 +04:00
parent 202274073f
commit d3a3ea008d
8 changed files with 218 additions and 87 deletions

View file

@ -750,7 +750,7 @@ public final class CallListController: TelegramBaseController {
})
}
override public func tabBarItemContextAction(sourceNode: ContextExtractedContentContainingNode, gesture: ContextGesture) {
override public func tabBarItemContextAction(sourceView: ContextExtractedContentContainingView, gesture: ContextGesture) {
var items: [ContextMenuItem] = []
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Calls_StartNewCall, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor)
@ -775,30 +775,27 @@ public final class CallListController: TelegramBaseController {
})
})))
let controller = ContextController(presentationData: self.presentationData, source: .extracted(CallListTabBarContextExtractedContentSource(controller: self, sourceNode: sourceNode)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
let controller = ContextController(presentationData: self.presentationData, source: .reference(CallListTabBarContextReferenceContentSource(controller: self, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
self.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller)
}
}
private final class CallListTabBarContextExtractedContentSource: ContextExtractedContentSource {
private final class CallListTabBarContextReferenceContentSource: ContextReferenceContentSource {
let keepInPlace: Bool = true
let ignoreContentTouches: Bool = true
let blurBackground: Bool = true
let actionsHorizontalAlignment: ContextActionsHorizontalAlignment = .center
private let controller: ViewController
private let sourceNode: ContextExtractedContentContainingNode
private let sourceView: ContextExtractedContentContainingView
init(controller: ViewController, sourceNode: ContextExtractedContentContainingNode) {
init(controller: ViewController, sourceView: ContextExtractedContentContainingView) {
self.controller = controller
self.sourceNode = sourceNode
self.sourceView = sourceView
}
func takeView() -> ContextControllerTakeViewInfo? {
return ContextControllerTakeViewInfo(containingItem: .node(self.sourceNode), contentAreaInScreenSpace: UIScreen.main.bounds)
}
func putBack() -> ContextControllerPutBackViewInfo? {
return ContextControllerPutBackViewInfo(contentAreaInScreenSpace: UIScreen.main.bounds)
func transitionInfo() -> ContextControllerReferenceViewInfo? {
return ContextControllerReferenceViewInfo(
referenceView: self.sourceView.contentView,
contentAreaInScreenSpace: UIScreen.main.bounds,
actionsPosition: .top
)
}
}

View file

@ -6061,7 +6061,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
self.donePressed()
}
override public func tabBarItemContextAction(sourceNode: ContextExtractedContentContainingNode, gesture: ContextGesture) {
override public func tabBarItemContextAction(sourceView: ContextExtractedContentContainingView, gesture: ContextGesture) {
let _ = (combineLatest(queue: .mainQueue(),
self.context.engine.peers.currentChatListFilters(),
chatListFilterItems(context: self.context)
@ -6178,7 +6178,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}
}
let controller = ContextController(context: strongSelf.context, presentationData: strongSelf.presentationData, source: .extracted(ChatListTabBarContextExtractedContentSource(controller: strongSelf, sourceNode: sourceNode)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
let controller = ContextController(context: strongSelf.context, presentationData: strongSelf.presentationData, source: .reference(ChatListTabBarContextReferenceContentSource(controller: strongSelf, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
strongSelf.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller)
})
}
@ -6435,26 +6435,24 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}
}
private final class ChatListTabBarContextExtractedContentSource: ContextExtractedContentSource {
private final class ChatListTabBarContextReferenceContentSource: ContextReferenceContentSource {
let keepInPlace: Bool = true
let ignoreContentTouches: Bool = true
let blurBackground: Bool = true
let actionsHorizontalAlignment: ContextActionsHorizontalAlignment = .center
private let controller: ChatListController
private let sourceNode: ContextExtractedContentContainingNode
private let sourceView: ContextExtractedContentContainingView
init(controller: ChatListController, sourceNode: ContextExtractedContentContainingNode) {
init(controller: ChatListController, sourceView: ContextExtractedContentContainingView) {
self.controller = controller
self.sourceNode = sourceNode
self.sourceView = sourceView
}
func takeView() -> ContextControllerTakeViewInfo? {
return ContextControllerTakeViewInfo(containingItem: .node(self.sourceNode), contentAreaInScreenSpace: UIScreen.main.bounds)
}
func putBack() -> ContextControllerPutBackViewInfo? {
return ContextControllerPutBackViewInfo(contentAreaInScreenSpace: UIScreen.main.bounds)
func transitionInfo() -> ContextControllerReferenceViewInfo? {
return ContextControllerReferenceViewInfo(
referenceView: self.sourceView.contentView,
contentAreaInScreenSpace: UIScreen.main.bounds,
actionsPosition: .top
)
}
}

View file

@ -774,7 +774,7 @@ public class ContactsController: ViewController {
})
}
override public func tabBarItemContextAction(sourceNode: ContextExtractedContentContainingNode, gesture: ContextGesture) {
override public func tabBarItemContextAction(sourceView: ContextExtractedContentContainingView, gesture: ContextGesture) {
var items: [ContextMenuItem] = []
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Contacts_AddContact, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor)
@ -787,31 +787,28 @@ public class ContactsController: ViewController {
})
})))
let controller = ContextController(presentationData: self.presentationData, source: .extracted(ContactsTabBarContextExtractedContentSource(controller: self, sourceNode: sourceNode)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
let controller = ContextController(presentationData: self.presentationData, source: .reference(ContactsTabBarContextReferenceContentSource(controller: self, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
self.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller)
}
}
private final class ContactsTabBarContextExtractedContentSource: ContextExtractedContentSource {
private final class ContactsTabBarContextReferenceContentSource: ContextReferenceContentSource {
let keepInPlace: Bool = true
let ignoreContentTouches: Bool = true
let blurBackground: Bool = true
let actionsHorizontalAlignment: ContextActionsHorizontalAlignment = .center
private let controller: ViewController
private let sourceNode: ContextExtractedContentContainingNode
private let sourceView: ContextExtractedContentContainingView
init(controller: ViewController, sourceNode: ContextExtractedContentContainingNode) {
init(controller: ViewController, sourceView: ContextExtractedContentContainingView) {
self.controller = controller
self.sourceNode = sourceNode
self.sourceView = sourceView
}
func takeView() -> ContextControllerTakeViewInfo? {
return ContextControllerTakeViewInfo(containingItem: .node(self.sourceNode), contentAreaInScreenSpace: UIScreen.main.bounds)
}
func putBack() -> ContextControllerPutBackViewInfo? {
return ContextControllerPutBackViewInfo(contentAreaInScreenSpace: UIScreen.main.bounds)
func transitionInfo() -> ContextControllerReferenceViewInfo? {
return ContextControllerReferenceViewInfo(
referenceView: self.sourceView.contentView,
contentAreaInScreenSpace: UIScreen.main.bounds,
actionsPosition: .top
)
}
}

View file

@ -697,7 +697,7 @@ public protocol CustomViewControllerNavigationDataSummary: AnyObject {
open var tabBarItemContextActionType: TabBarItemContextActionType = .none
open func tabBarItemContextAction(sourceNode: ContextExtractedContentContainingNode, gesture: ContextGesture) {
open func tabBarItemContextAction(sourceView: ContextExtractedContentContainingView, gesture: ContextGesture) {
}
open func tabBarDisabledAction() {

View file

@ -49,9 +49,8 @@ final class TabBarControllerNode: ASDisplayNode {
private var theme: PresentationTheme
private let itemSelected: (Int, Bool, [ASDisplayNode]) -> Void
private let contextAction: (Int, ContextExtractedContentContainingNode, ContextGesture) -> Void
private let contextAction: (Int, ContextExtractedContentContainingView, ContextGesture) -> Void
private let tabBarNode: TabBarNode
private let tabBarView = ComponentView<Empty>()
private let disabledOverlayNode: ASDisplayNode
@ -62,7 +61,7 @@ final class TabBarControllerNode: ASDisplayNode {
private(set) var tabBarItems: [TabBarNodeItem] = []
private(set) var selectedIndex: Int = 0
var currentControllerNode: ASDisplayNode?
private(set) var currentControllerNode: ASDisplayNode?
private var layoutResult: LayoutResult?
private var isUpdateRequested: Bool = false
@ -81,6 +80,9 @@ final class TabBarControllerNode: ASDisplayNode {
} else {
self.insertSubnode(currentControllerNode, at: 0)
}
if let tabBarView = self.tabBarView.view {
self.view.bringSubviewToFront(tabBarView)
}
}
return { [weak self, weak previousNode] in
@ -90,11 +92,10 @@ final class TabBarControllerNode: ASDisplayNode {
}
}
init(theme: PresentationTheme, itemSelected: @escaping (Int, Bool, [ASDisplayNode]) -> Void, contextAction: @escaping (Int, ContextExtractedContentContainingNode, ContextGesture) -> Void, swipeAction: @escaping (Int, TabBarItemSwipeDirection) -> Void, toolbarActionSelected: @escaping (ToolbarActionOption) -> Void, disabledPressed: @escaping () -> Void) {
init(theme: PresentationTheme, itemSelected: @escaping (Int, Bool, [ASDisplayNode]) -> Void, contextAction: @escaping (Int, ContextExtractedContentContainingView, ContextGesture) -> Void, swipeAction: @escaping (Int, TabBarItemSwipeDirection) -> Void, toolbarActionSelected: @escaping (ToolbarActionOption) -> Void, disabledPressed: @escaping () -> Void) {
self.theme = theme
self.itemSelected = itemSelected
self.contextAction = contextAction
self.tabBarNode = TabBarNode(theme: theme, itemSelected: itemSelected, contextAction: contextAction, swipeAction: swipeAction)
self.disabledOverlayNode = ASDisplayNode()
self.disabledOverlayNode.backgroundColor = theme.rootController.tabBar.backgroundColor.withAlphaComponent(0.5)
self.disabledOverlayNode.alpha = 0.0
@ -141,7 +142,6 @@ final class TabBarControllerNode: ASDisplayNode {
self.theme = theme
self.backgroundColor = theme.list.plainBackgroundColor
self.tabBarNode.updateTheme(theme)
self.disabledOverlayNode.backgroundColor = theme.rootController.tabBar.backgroundColor.withAlphaComponent(0.5)
self.toolbarNode?.updateTheme(ToolbarTheme(theme: theme))
self.requestUpdate()
@ -210,6 +210,14 @@ final class TabBarControllerNode: ASDisplayNode {
if let index = self.tabBarItems.firstIndex(where: { AnyHashable(ObjectIdentifier($0.item)) == itemId }) {
self.itemSelected(index, isLongTap, [])
}
},
contextAction: { [weak self] gesture, sourceView in
guard let self else {
return
}
if let index = self.tabBarItems.firstIndex(where: { AnyHashable(ObjectIdentifier($0.item)) == itemId }) {
self.contextAction(index, sourceView, gesture)
}
}
)
},
@ -227,9 +235,6 @@ final class TabBarControllerNode: ASDisplayNode {
transition.updateFrame(view: tabBarComponentView, frame: tabBarFrame)
}
//transition.updateFrame(node: self.tabBarNode, frame: tabBarFrame)
//self.tabBarNode.updateLayout(size: params.layout.size, leftInset: params.layout.safeInsets.left, rightInset: params.layout.safeInsets.right, additionalSideInsets: params.layout.additionalInsets, bottomInset: bottomInset, transition: transition)
transition.updateFrame(node: self.disabledOverlayNode, frame: tabBarFrame)
if let toolbar = params.toolbar {
@ -263,11 +268,20 @@ final class TabBarControllerNode: ASDisplayNode {
}
func frameForControllerTab(at index: Int) -> CGRect? {
return self.tabBarNode.frameForControllerTab(at: index).flatMap { self.tabBarNode.view.convert($0, to: self.view) }
guard let tabBarView = self.tabBarView.view as? TabBarComponent.View else {
return nil
}
guard let itemFrame = tabBarView.frameForItem(at: index) else {
return nil
}
return self.view.convert(itemFrame, from: tabBarView)
}
func isPointInsideContentArea(point: CGPoint) -> Bool {
if point.y < self.tabBarNode.frame.minY {
guard let tabBarView = self.tabBarView.view else {
return false
}
if point.y < tabBarView.frame.minY {
return true
}
return false
@ -275,13 +289,11 @@ final class TabBarControllerNode: ASDisplayNode {
func updateTabBarItems(items: [TabBarNodeItem]) {
self.tabBarItems = items
self.tabBarNode.tabBarItems = items
self.requestUpdate()
}
func updateSelectedIndex(index: Int) {
self.selectedIndex = index
self.tabBarNode.selectedIndex = index
self.isChangingSelectedIndex = true
self.requestUpdate()
}

View file

@ -217,12 +217,12 @@ open class TabBarControllerImpl: ViewController, TabBarController {
}
}))
}
}, contextAction: { [weak self] index, node, gesture in
}, contextAction: { [weak self] index, view, gesture in
guard let strongSelf = self else {
return
}
if index >= 0 && index < strongSelf.tabBarControllerNode.tabBarItems.count {
strongSelf.controllers[index].tabBarItemContextAction(sourceNode: node, gesture: gesture)
strongSelf.controllers[index].tabBarItemContextAction(sourceView: view, gesture: gesture)
}
}, swipeAction: { [weak self] index, direction in
guard let strongSelf = self else {

View file

@ -13943,7 +13943,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
self.controllerNode.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: transition)
}
override public func tabBarItemContextAction(sourceNode: ContextExtractedContentContainingNode, gesture: ContextGesture) {
override public func tabBarItemContextAction(sourceView: ContextExtractedContentContainingView, gesture: ContextGesture) {
guard let (maybePrimary, other) = self.accountsAndPeersValue, let primary = maybePrimary else {
return
}
@ -13994,7 +13994,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
})))*/
}
let controller = ContextController(presentationData: self.presentationData, source: .extracted(SettingsTabBarContextExtractedContentSource(controller: self, sourceNode: sourceNode)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
let controller = ContextController(presentationData: self.presentationData, source: .reference(SettingsTabBarContextReferenceContentSource(controller: self, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
self.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller)
}
@ -14123,26 +14123,23 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
}
}
private final class SettingsTabBarContextExtractedContentSource: ContextExtractedContentSource {
private final class SettingsTabBarContextReferenceContentSource: ContextReferenceContentSource {
let keepInPlace: Bool = true
let ignoreContentTouches: Bool = true
let blurBackground: Bool = true
let actionsHorizontalAlignment: ContextActionsHorizontalAlignment = .center
private let controller: ViewController
private let sourceNode: ContextExtractedContentContainingNode
private let sourceView: ContextExtractedContentContainingView
init(controller: ViewController, sourceNode: ContextExtractedContentContainingNode) {
init(controller: ViewController, sourceView: ContextExtractedContentContainingView) {
self.controller = controller
self.sourceNode = sourceNode
self.sourceView = sourceView
}
func takeView() -> ContextControllerTakeViewInfo? {
return ContextControllerTakeViewInfo(containingItem: .node(self.sourceNode), contentAreaInScreenSpace: UIScreen.main.bounds)
}
func putBack() -> ContextControllerPutBackViewInfo? {
return ContextControllerPutBackViewInfo(contentAreaInScreenSpace: UIScreen.main.bounds)
func transitionInfo() -> ContextControllerReferenceViewInfo? {
return ContextControllerReferenceViewInfo(
referenceView: self.sourceView.contentView,
contentAreaInScreenSpace: UIScreen.main.bounds,
actionsPosition: .top
)
}
}

View file

@ -15,14 +15,16 @@ public final class TabBarComponent: Component {
public final class Item: Equatable {
public let item: UITabBarItem
public let action: (Bool) -> Void
public let contextAction: ((ContextGesture, ContextExtractedContentContainingView) -> Void)?
fileprivate var id: AnyHashable {
return AnyHashable(ObjectIdentifier(self.item))
}
public init(item: UITabBarItem, action: @escaping (Bool) -> Void) {
public init(item: UITabBarItem, action: @escaping (Bool) -> Void, contextAction: ((ContextGesture, ContextExtractedContentContainingView) -> Void)?) {
self.item = item
self.action = action
self.contextAction = contextAction
}
public static func ==(lhs: Item, rhs: Item) -> Bool {
@ -32,6 +34,9 @@ public final class TabBarComponent: Component {
if lhs.item !== rhs.item {
return false
}
if (lhs.contextAction == nil) != (rhs.contextAction == nil) {
return false
}
return true
}
}
@ -66,11 +71,14 @@ public final class TabBarComponent: Component {
public final class View: UIView, UITabBarDelegate, UIGestureRecognizerDelegate {
private let backgroundView: GlassBackgroundView
private let selectionView: GlassBackgroundView.ContentImageView
private let contextGestureContainerView: ContextControllerSourceView
private let nativeTabBar: UITabBar?
private var itemViews: [AnyHashable: ComponentView<Empty>] = [:]
private var selectedItemViews: [AnyHashable: ComponentView<Empty>] = [:]
private var itemWithActiveContextGesture: AnyHashable?
private var component: TabBarComponent?
private weak var state: EmptyComponentState?
@ -78,6 +86,9 @@ public final class TabBarComponent: Component {
self.backgroundView = GlassBackgroundView(frame: CGRect())
self.selectionView = GlassBackgroundView.ContentImageView()
self.contextGestureContainerView = ContextControllerSourceView()
self.contextGestureContainerView.isGestureEnabled = true
if #available(iOS 26.0, *) {
self.nativeTabBar = UITabBar()
} else {
@ -86,16 +97,110 @@ public final class TabBarComponent: Component {
super.init(frame: frame)
self.addSubview(self.contextGestureContainerView)
if let nativeTabBar = self.nativeTabBar {
self.addSubview(nativeTabBar)
self.contextGestureContainerView.addSubview(nativeTabBar)
nativeTabBar.delegate = self
let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(self.onLongPressGesture(_:)))
/*let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(self.onLongPressGesture(_:)))
longPressGesture.delegate = self
self.addGestureRecognizer(longPressGesture)
self.addGestureRecognizer(longPressGesture)*/
} else {
self.addSubview(self.backgroundView)
self.contextGestureContainerView.addSubview(self.backgroundView)
self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.onTapGesture(_:))))
}
self.contextGestureContainerView.shouldBegin = { [weak self] point in
guard let self, let component = self.component else {
return false
}
for (id, itemView) in self.itemViews {
if let itemView = itemView.view {
if self.convert(itemView.bounds, from: itemView).contains(point) {
guard let item = component.items.first(where: { $0.id == id }) else {
return false
}
if item.contextAction == nil {
return false
}
self.itemWithActiveContextGesture = id
return true
}
}
}
return false
}
/*self.contextGestureContainerView.customActivationProgress = { [weak self] progress, update in
guard let self, let itemWithActiveContextGesture = self.itemWithActiveContextGesture else {
return
}
guard let itemView = self.itemViews[itemWithActiveContextGesture]?.view else {
return
}
let scaleSide = itemView.bounds.width
let minScale: CGFloat = max(0.7, (scaleSide - 15.0) / scaleSide)
let currentScale = 1.0 * (1.0 - progress) + minScale * progress
switch update {
case .update:
let sublayerTransform = CATransform3DScale(CATransform3DIdentity, currentScale, currentScale, 1.0)
itemView.layer.sublayerTransform = sublayerTransform
case .begin:
let sublayerTransform = CATransform3DScale(CATransform3DIdentity, currentScale, currentScale, 1.0)
itemView.layer.sublayerTransform = sublayerTransform
case .ended:
let sublayerTransform = CATransform3DScale(CATransform3DIdentity, currentScale, currentScale, 1.0)
let previousTransform = itemView.layer.sublayerTransform
itemView.layer.sublayerTransform = sublayerTransform
itemView.layer.animate(from: NSValue(caTransform3D: previousTransform), to: NSValue(caTransform3D: sublayerTransform), keyPath: "sublayerTransform", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, duration: 0.2)
}
}*/
self.contextGestureContainerView.activated = { [weak self] gesture, _ in
guard let self, let component = self.component else {
return
}
guard let itemWithActiveContextGesture = self.itemWithActiveContextGesture else {
return
}
var itemView: ItemComponent.View?
if self.nativeTabBar != nil {
itemView = self.selectedItemViews[itemWithActiveContextGesture]?.view as? ItemComponent.View
} else {
itemView = self.itemViews[itemWithActiveContextGesture]?.view as? ItemComponent.View
}
guard let itemView else {
return
}
DispatchQueue.main.async { [weak self] in
guard let self else {
return
}
if let nativeTabBar = self.nativeTabBar {
func cancelGestures(view: UIView) {
for recognizer in view.gestureRecognizers ?? [] {
if NSStringFromClass(type(of: recognizer)).contains("sSelectionGestureRecognizer") {
recognizer.state = .cancelled
}
}
for subview in view.subviews {
cancelGestures(view: subview)
}
}
cancelGestures(view: nativeTabBar)
}
}
guard let item = component.items.first(where: { $0.id == itemWithActiveContextGesture }) else {
return
}
item.contextAction?(gesture, itemView.contextContainerView)
}
}
required public init?(coder: NSCoder) {
@ -175,6 +280,19 @@ public final class TabBarComponent: Component {
return super.hitTest(point, with: event)
}
public func frameForItem(at index: Int) -> CGRect? {
guard let component = self.component else {
return nil
}
if index < 0 || index >= component.items.count {
return nil
}
guard let itemView = self.itemViews[component.items[index].id]?.view else {
return nil
}
return self.convert(itemView.bounds, from: itemView)
}
func update(component: TabBarComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
let innerInset: CGFloat = 3.0
@ -304,7 +422,7 @@ public final class TabBarComponent: Component {
itemContainer.addSubview(selectedItemComponentView)
}
} else {
self.addSubview(itemComponentView)
self.contextGestureContainerView.addSubview(itemComponentView)
}
}
if self.nativeTabBar != nil {
@ -363,6 +481,8 @@ public final class TabBarComponent: Component {
transition.setFrame(view: nativeTabBar, frame: CGRect(origin: CGPoint(x: floor((size.width - nativeTabBar.bounds.width) * 0.5), y: 0.0), size: nativeTabBar.bounds.size))
}
transition.setFrame(view: self.contextGestureContainerView, frame: CGRect(origin: CGPoint(), size: size))
return size
}
}
@ -401,6 +521,8 @@ private final class ItemComponent: Component {
}
final class View: UIView {
let contextContainerView: ContextExtractedContentContainingView
private var imageIcon: ComponentView<Empty>?
private var animationIcon: ComponentView<Empty>?
private let title = ComponentView<Empty>()
@ -414,7 +536,11 @@ private final class ItemComponent: Component {
private var setBadgeListener: Int?
override init(frame: CGRect) {
self.contextContainerView = ContextExtractedContentContainingView()
super.init(frame: frame)
self.addSubview(self.contextContainerView)
}
required init?(coder: NSCoder) {
@ -512,9 +638,9 @@ private final class ItemComponent: Component {
if let animationIconView = animationIcon.view {
if animationIconView.superview == nil {
if let badgeView = self.badge?.view {
self.insertSubview(animationIconView, belowSubview: badgeView)
self.contextContainerView.contentView.insertSubview(animationIconView, belowSubview: badgeView)
} else {
self.addSubview(animationIconView)
self.contextContainerView.contentView.addSubview(animationIconView)
}
}
iconTransition.setFrame(view: animationIconView, frame: iconFrame)
@ -549,9 +675,9 @@ private final class ItemComponent: Component {
if let imageIconView = imageIcon.view {
if imageIconView.superview == nil {
if let badgeView = self.badge?.view {
self.insertSubview(imageIconView, belowSubview: badgeView)
self.contextContainerView.contentView.insertSubview(imageIconView, belowSubview: badgeView)
} else {
self.addSubview(imageIconView)
self.contextContainerView.contentView.addSubview(imageIconView)
}
}
iconTransition.setFrame(view: imageIconView, frame: iconFrame)
@ -569,7 +695,7 @@ private final class ItemComponent: Component {
let titleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - titleSize.width) * 0.5), y: availableSize.height - 9.0 - titleSize.height), size: titleSize)
if let titleView = self.title.view {
if titleView.superview == nil {
self.addSubview(titleView)
self.contextContainerView.contentView.addSubview(titleView)
}
titleView.frame = titleFrame
}
@ -600,7 +726,7 @@ private final class ItemComponent: Component {
let badgeFrame = CGRect(origin: CGPoint(x: floor(availableSize.width / 2.0) + contentWidth - badgeSize.width - 5.0, y: -1.0), size: badgeSize)
if let badgeView = badge.view {
if badgeView.superview == nil {
self.addSubview(badgeView)
self.contextContainerView.contentView.addSubview(badgeView)
}
badgeTransition.setFrame(view: badgeView, frame: badgeFrame)
}
@ -609,6 +735,10 @@ private final class ItemComponent: Component {
badge.view?.removeFromSuperview()
}
transition.setFrame(view: self.contextContainerView, frame: CGRect(origin: CGPoint(), size: availableSize))
transition.setFrame(view: self.contextContainerView.contentView, frame: CGRect(origin: CGPoint(), size: availableSize))
self.contextContainerView.contentRect = CGRect(origin: CGPoint(), size: availableSize)
return availableSize
}
}