mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various improvements
This commit is contained in:
parent
732dc8baf5
commit
b569c0d4db
@ -378,6 +378,7 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
|
|||||||
self.iconNode = ASImageNode()
|
self.iconNode = ASImageNode()
|
||||||
self.iconNode.displaysAsynchronously = false
|
self.iconNode.displaysAsynchronously = false
|
||||||
self.iconNode.image = generateTintedImage(image: icon, color: self.theme.foregroundColor)
|
self.iconNode.image = generateTintedImage(image: icon, color: self.theme.foregroundColor)
|
||||||
|
self.iconNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ swift_library(
|
|||||||
"//submodules/Markdown",
|
"//submodules/Markdown",
|
||||||
"//submodules/AvatarNode",
|
"//submodules/AvatarNode",
|
||||||
"//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode",
|
"//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode",
|
||||||
|
"//submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode",
|
||||||
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
|
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
|
||||||
"//submodules/TelegramUI/Components/Utils/RoundedRectWithTailPath",
|
"//submodules/TelegramUI/Components/Utils/RoundedRectWithTailPath",
|
||||||
"//submodules/Components/MultilineTextComponent",
|
"//submodules/Components/MultilineTextComponent",
|
||||||
|
@ -18,6 +18,7 @@ import ChatControllerInteraction
|
|||||||
import ShimmerEffect
|
import ShimmerEffect
|
||||||
import Markdown
|
import Markdown
|
||||||
import ChatMessageBubbleContentNode
|
import ChatMessageBubbleContentNode
|
||||||
|
import ChatMessagePollBubbleContentNode
|
||||||
import ChatMessageItemCommon
|
import ChatMessageItemCommon
|
||||||
import RoundedRectWithTailPath
|
import RoundedRectWithTailPath
|
||||||
import AvatarNode
|
import AvatarNode
|
||||||
@ -343,11 +344,13 @@ public class ChatMessageJoinedChannelBubbleContentNode: ChatMessageBubbleContent
|
|||||||
presentationData: presentationData,
|
presentationData: presentationData,
|
||||||
content: .premiumPaywall(title: nil, text: "Subcribe to [Telegram Premium]() to unlock up to **100** channels.", customUndoText: nil, timeout: nil, linkAction: nil),
|
content: .premiumPaywall(title: nil, text: "Subcribe to [Telegram Premium]() to unlock up to **100** channels.", customUndoText: nil, timeout: nil, linkAction: nil),
|
||||||
elevatedLayout: false,
|
elevatedLayout: false,
|
||||||
action: { [weak self] _ in
|
action: { [weak self] action in
|
||||||
|
if case .info = action {
|
||||||
if let self, let item = self.item {
|
if let self, let item = self.item {
|
||||||
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .ads, forceDark: false, dismissed: nil)
|
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .ads, forceDark: false, dismissed: nil)
|
||||||
item.controllerInteraction.navigationController()?.pushViewController(controller)
|
item.controllerInteraction.navigationController()?.pushViewController(controller)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -536,7 +539,7 @@ private final class ChannelItemComponent: Component {
|
|||||||
let title: String
|
let title: String
|
||||||
let subtitle: String
|
let subtitle: String
|
||||||
let action: (EnginePeer?) -> Void
|
let action: (EnginePeer?) -> Void
|
||||||
let contextAction: (EnginePeer, UIView, ContextGesture?) -> Void
|
let contextAction: ((EnginePeer, UIView, ContextGesture?) -> Void)?
|
||||||
|
|
||||||
init(
|
init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
@ -547,7 +550,7 @@ private final class ChannelItemComponent: Component {
|
|||||||
title: String,
|
title: String,
|
||||||
subtitle: String,
|
subtitle: String,
|
||||||
action: @escaping (EnginePeer?) -> Void,
|
action: @escaping (EnginePeer?) -> Void,
|
||||||
contextAction: @escaping (EnginePeer, UIView, ContextGesture?) -> Void
|
contextAction: ((EnginePeer, UIView, ContextGesture?) -> Void)?
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
@ -593,6 +596,7 @@ private final class ChannelItemComponent: Component {
|
|||||||
private let circleView2: UIImageView
|
private let circleView2: UIImageView
|
||||||
|
|
||||||
private let avatarNode: AvatarNode
|
private let avatarNode: AvatarNode
|
||||||
|
private var mergedAvatarsNode: MergedAvatarsNode?
|
||||||
private let avatarBadge: AvatarBadgeView
|
private let avatarBadge: AvatarBadgeView
|
||||||
private let subtitleIcon = ComponentView<Empty>()
|
private let subtitleIcon = ComponentView<Empty>()
|
||||||
|
|
||||||
@ -608,15 +612,13 @@ private final class ChannelItemComponent: Component {
|
|||||||
self.circleView.clipsToBounds = true
|
self.circleView.clipsToBounds = true
|
||||||
self.circleView.layer.cornerRadius = 30
|
self.circleView.layer.cornerRadius = 30
|
||||||
|
|
||||||
let colors: NSArray = [UIColor(rgb: 0x6a2267).cgColor, UIColor(rgb: 0x000000).cgColor]
|
let colors: NSArray = [UIColor(rgb: 0x000000).cgColor, UIColor(rgb: 0x6a2267).cgColor]
|
||||||
self.circleView2 = UIImageView(image: generateGradientFilledCircleImage(diameter: 60, colors: colors))
|
self.circleView2 = UIImageView(image: generateGradientFilledCircleImage(diameter: 60, colors: colors))
|
||||||
self.circleView2.clipsToBounds = true
|
self.circleView2.clipsToBounds = true
|
||||||
self.circleView2.layer.cornerRadius = 30
|
self.circleView2.layer.cornerRadius = 30
|
||||||
|
|
||||||
self.avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 26.0))
|
self.avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 26.0))
|
||||||
self.avatarNode.isUserInteractionEnabled = false
|
self.avatarNode.isUserInteractionEnabled = false
|
||||||
self.avatarNode.clipsToBounds = true
|
|
||||||
self.avatarNode.layer.cornerRadius = 30
|
|
||||||
|
|
||||||
self.avatarBadge = AvatarBadgeView(frame: CGRect())
|
self.avatarBadge = AvatarBadgeView(frame: CGRect())
|
||||||
|
|
||||||
@ -631,7 +633,7 @@ private final class ChannelItemComponent: Component {
|
|||||||
self.contextContainer.addSubview(self.circleView2)
|
self.contextContainer.addSubview(self.circleView2)
|
||||||
self.contextContainer.addSubview(self.circleView)
|
self.contextContainer.addSubview(self.circleView)
|
||||||
self.contextContainer.addSubnode(self.avatarNode)
|
self.contextContainer.addSubnode(self.avatarNode)
|
||||||
self.avatarNode.view.addSubview(self.avatarBadge)
|
self.contextContainer.addSubview(self.avatarBadge)
|
||||||
|
|
||||||
self.avatarNode.badgeView = self.avatarBadge
|
self.avatarNode.badgeView = self.avatarBadge
|
||||||
|
|
||||||
@ -639,7 +641,7 @@ private final class ChannelItemComponent: Component {
|
|||||||
|
|
||||||
self.contextContainer.activated = { [weak self] gesture, point in
|
self.contextContainer.activated = { [weak self] gesture, point in
|
||||||
if let self, let component = self.component, let peer = component.peers.first {
|
if let self, let component = self.component, let peer = component.peers.first {
|
||||||
component.contextAction(peer, self.contextContainer, gesture)
|
component.contextAction?(peer, self.contextContainer, gesture)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -663,6 +665,8 @@ private final class ChannelItemComponent: Component {
|
|||||||
self.component = component
|
self.component = component
|
||||||
self.state = state
|
self.state = state
|
||||||
|
|
||||||
|
self.contextContainer.isGestureEnabled = component.contextAction != nil
|
||||||
|
|
||||||
let titleSize = self.title.update(
|
let titleSize = self.title.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
component: AnyComponent(MultilineTextComponent(
|
component: AnyComponent(MultilineTextComponent(
|
||||||
@ -707,7 +711,10 @@ private final class ChannelItemComponent: Component {
|
|||||||
|
|
||||||
let subtitleOriginX = floorToScreenPixels((itemSize.width - subtitleTotalWidth) / 2.0) + 1.0 - UIScreenPixel
|
let subtitleOriginX = floorToScreenPixels((itemSize.width - subtitleTotalWidth) / 2.0) + 1.0 - UIScreenPixel
|
||||||
var iconOriginX = subtitleOriginX
|
var iconOriginX = subtitleOriginX
|
||||||
var textOriginX = subtitleOriginX + subtitleIconSize.width + subtitleSpacing
|
var textOriginX = subtitleOriginX
|
||||||
|
if subtitleIconSize.width > 0.0 {
|
||||||
|
textOriginX += subtitleIconSize.width + subtitleSpacing
|
||||||
|
}
|
||||||
if component.isLocked {
|
if component.isLocked {
|
||||||
textOriginX = subtitleOriginX
|
textOriginX = subtitleOriginX
|
||||||
iconOriginX = subtitleOriginX + subtitleSize.width + subtitleSpacing
|
iconOriginX = subtitleOriginX + subtitleSize.width + subtitleSpacing
|
||||||
@ -717,7 +724,7 @@ private final class ChannelItemComponent: Component {
|
|||||||
let subtitleFrame = CGRect(origin: CGPoint(x: textOriginX, y: avatarFrame.maxY - subtitleSize.height - UIScreenPixel), size: subtitleSize)
|
let subtitleFrame = CGRect(origin: CGPoint(x: textOriginX, y: avatarFrame.maxY - subtitleSize.height - UIScreenPixel), size: subtitleSize)
|
||||||
|
|
||||||
var avatarHorizontalOffset: CGFloat = 0.0
|
var avatarHorizontalOffset: CGFloat = 0.0
|
||||||
if component.peers.count > 1 || component.isLocked {
|
if component.isLocked {
|
||||||
avatarHorizontalOffset = -10.0
|
avatarHorizontalOffset = -10.0
|
||||||
}
|
}
|
||||||
avatarFrame = avatarFrame.offsetBy(dx: avatarHorizontalOffset, dy: 0.0)
|
avatarFrame = avatarFrame.offsetBy(dx: avatarHorizontalOffset, dy: 0.0)
|
||||||
@ -726,6 +733,27 @@ private final class ChannelItemComponent: Component {
|
|||||||
self.avatarNode.setPeer(context: component.context, theme: component.theme, peer: peer)
|
self.avatarNode.setPeer(context: component.context, theme: component.theme, peer: peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if component.peers.count > 1 {
|
||||||
|
let mergedAvatarsNode: MergedAvatarsNode
|
||||||
|
if let current = self.mergedAvatarsNode {
|
||||||
|
mergedAvatarsNode = current
|
||||||
|
} else {
|
||||||
|
mergedAvatarsNode = MergedAvatarsNode()
|
||||||
|
self.contextContainer.insertSubview(mergedAvatarsNode.view, aboveSubview: self.avatarNode.view)
|
||||||
|
self.mergedAvatarsNode = mergedAvatarsNode
|
||||||
|
}
|
||||||
|
|
||||||
|
mergedAvatarsNode.update(context: component.context, peers: component.peers.map { $0._asPeer() }, synchronousLoad: false, imageSize: 60.0, imageSpacing: 10.0, borderWidth: 2.0)
|
||||||
|
let avatarsSize = CGSize(width: avatarSize.width + 20.0, height: avatarSize.height)
|
||||||
|
mergedAvatarsNode.updateLayout(size: avatarsSize)
|
||||||
|
mergedAvatarsNode.frame = CGRect(origin: CGPoint(x: avatarFrame.midX - avatarsSize.width / 2.0, y: avatarFrame.minY), size: avatarsSize)
|
||||||
|
self.avatarNode.isHidden = true
|
||||||
|
} else {
|
||||||
|
self.mergedAvatarsNode?.view.removeFromSuperview()
|
||||||
|
self.mergedAvatarsNode = nil
|
||||||
|
self.avatarNode.isHidden = false
|
||||||
|
}
|
||||||
|
|
||||||
if component.isLocked {
|
if component.isLocked {
|
||||||
self.circleView.isHidden = false
|
self.circleView.isHidden = false
|
||||||
self.circleView.frame = avatarFrame.offsetBy(dx: 10.0, dy: 0.0)
|
self.circleView.frame = avatarFrame.offsetBy(dx: 10.0, dy: 0.0)
|
||||||
@ -760,10 +788,10 @@ private final class ChannelItemComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let strokeWidth: CGFloat = 1.0 + UIScreenPixel
|
let strokeWidth: CGFloat = 1.0 + UIScreenPixel
|
||||||
let avatarBadgeSize = CGSize(width: subtitleSize.width + 10.0 + 6.0, height: 15.0)
|
let avatarBadgeSize = CGSize(width: subtitleSize.width + subtitleIconSize.width + 10.0, height: 15.0)
|
||||||
self.avatarBadge.update(size: avatarBadgeSize, text: "", hasTimeoutIcon: false, useSolidColor: true, strokeColor: component.theme.chat.message.incoming.bubble.withoutWallpaper.fill.first!)
|
self.avatarBadge.update(size: avatarBadgeSize, text: "", hasTimeoutIcon: false, useSolidColor: true, strokeColor: component.theme.chat.message.incoming.bubble.withoutWallpaper.fill.first!)
|
||||||
|
|
||||||
let avatarBadgeFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((avatarFrame.width - avatarBadgeSize.width) / 2.0) - avatarHorizontalOffset, y: avatarFrame.height - avatarBadgeSize.height + 2.0), size: avatarBadgeSize).insetBy(dx: -strokeWidth, dy: -strokeWidth)
|
let avatarBadgeFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((itemSize.width - avatarBadgeSize.width) / 2.0), y: avatarFrame.minY + avatarFrame.height - avatarBadgeSize.height + 2.0), size: avatarBadgeSize).insetBy(dx: -strokeWidth, dy: -strokeWidth)
|
||||||
self.avatarBadge.frame = avatarBadgeFrame
|
self.avatarBadge.frame = avatarBadgeFrame
|
||||||
|
|
||||||
let bounds = CGRect(origin: .zero, size: itemSize)
|
let bounds = CGRect(origin: .zero, size: itemSize)
|
||||||
@ -783,7 +811,7 @@ private final class ChannelItemComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private let channelsLimit: Int32 = 8
|
private let channelsLimit: Int32 = 10
|
||||||
|
|
||||||
final class ChannelListPanelComponent: Component {
|
final class ChannelListPanelComponent: Component {
|
||||||
typealias EnvironmentType = Empty
|
typealias EnvironmentType = Empty
|
||||||
@ -926,7 +954,7 @@ final class ChannelListPanelComponent: Component {
|
|||||||
|
|
||||||
let visibleBounds = self.scrollView.bounds.insetBy(dx: -100.0, dy: 0.0)
|
let visibleBounds = self.scrollView.bounds.insetBy(dx: -100.0, dy: 0.0)
|
||||||
|
|
||||||
let hasMore = component.peers.channels.count >= channelsLimit
|
let hasMore = component.peers.count > channelsLimit
|
||||||
|
|
||||||
var validIds = Set<EnginePeer.Id>()
|
var validIds = Set<EnginePeer.Id>()
|
||||||
if let visibleItems = itemLayout.visibleItems(for: visibleBounds) {
|
if let visibleItems = itemLayout.visibleItems(for: visibleBounds) {
|
||||||
@ -953,28 +981,40 @@ final class ChannelListPanelComponent: Component {
|
|||||||
let title: String
|
let title: String
|
||||||
let subtitle: String
|
let subtitle: String
|
||||||
var isLocked = false
|
var isLocked = false
|
||||||
|
var isLast = false
|
||||||
if index == upperBound - 1 && hasMore {
|
if index == upperBound - 1 && hasMore {
|
||||||
if !component.context.isPremium {
|
if !component.context.isPremium {
|
||||||
isLocked = true
|
isLocked = true
|
||||||
}
|
}
|
||||||
title = isLocked ? "Unlock More Channels" : "View More Channels"
|
title = isLocked ? "Unlock More Channels" : "View More Channels"
|
||||||
subtitle = "+\(component.peers.count - channelsLimit)"
|
subtitle = "+\(component.peers.count - channelsLimit)"
|
||||||
|
isLast = true
|
||||||
} else {
|
} else {
|
||||||
title = item.peer.compactDisplayTitle
|
title = item.peer.compactDisplayTitle
|
||||||
subtitle = countString(Int64(item.subscribers))
|
subtitle = countString(Int64(item.subscribers))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var peers: [EnginePeer] = [item.peer]
|
||||||
|
if isLast && !isLocked {
|
||||||
|
for i in index + 1 ..< index + 3 {
|
||||||
|
if i < component.peers.channels.count {
|
||||||
|
peers.append(component.peers.channels[i].peer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let _ = itemView.update(
|
let _ = itemView.update(
|
||||||
transition: itemTransition,
|
transition: itemTransition,
|
||||||
component: AnyComponent(ChannelItemComponent(
|
component: AnyComponent(ChannelItemComponent(
|
||||||
context: component.context,
|
context: component.context,
|
||||||
theme: component.theme,
|
theme: component.theme,
|
||||||
strings: component.strings,
|
strings: component.strings,
|
||||||
peers: [item.peer],
|
peers: peers,
|
||||||
isLocked: isLocked,
|
isLocked: isLocked,
|
||||||
title: title,
|
title: title,
|
||||||
subtitle: subtitle,
|
subtitle: subtitle,
|
||||||
action: component.action,
|
action: component.action,
|
||||||
contextAction: component.contextAction
|
contextAction: !isLocked && peers.count == 1 ? component.contextAction : nil
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: CGSize(width: itemLayout.itemWidth, height: itemLayout.containerHeight)
|
containerSize: CGSize(width: itemLayout.itemWidth, height: itemLayout.containerHeight)
|
||||||
|
@ -98,7 +98,7 @@ final class PeerInfoRecommendedChannelsPaneNode: ASDisplayNode, PeerInfoPaneNode
|
|||||||
|
|
||||||
private let listNode: ListView
|
private let listNode: ListView
|
||||||
private var currentEntries: [RecommendedChannelsListEntry] = []
|
private var currentEntries: [RecommendedChannelsListEntry] = []
|
||||||
private var currentState: RecommendedChannels?
|
private var currentState: (RecommendedChannels?, Bool)?
|
||||||
private var canLoadMore: Bool = false
|
private var canLoadMore: Bool = false
|
||||||
private var enqueuedTransactions: [RecommendedChannelsListTransaction] = []
|
private var enqueuedTransactions: [RecommendedChannelsListTransaction] = []
|
||||||
|
|
||||||
@ -106,7 +106,9 @@ final class PeerInfoRecommendedChannelsPaneNode: ASDisplayNode, PeerInfoPaneNode
|
|||||||
private var unlockText: ComponentView<Empty>?
|
private var unlockText: ComponentView<Empty>?
|
||||||
private var unlockButton: SolidRoundedButtonNode?
|
private var unlockButton: SolidRoundedButtonNode?
|
||||||
|
|
||||||
private var currentParams: (size: CGSize, isScrollingLockedAtTop: Bool)?
|
private var currentParams: (size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, isScrollingLockedAtTop: Bool)?
|
||||||
|
|
||||||
|
private var theme: PresentationTheme?
|
||||||
private let presentationDataPromise = Promise<PresentationData>()
|
private let presentationDataPromise = Promise<PresentationData>()
|
||||||
|
|
||||||
private let ready = Promise<Bool>()
|
private let ready = Promise<Bool>()
|
||||||
@ -144,14 +146,18 @@ final class PeerInfoRecommendedChannelsPaneNode: ASDisplayNode, PeerInfoPaneNode
|
|||||||
|
|
||||||
self.disposable = (combineLatest(queue: .mainQueue(),
|
self.disposable = (combineLatest(queue: .mainQueue(),
|
||||||
self.presentationDataPromise.get(),
|
self.presentationDataPromise.get(),
|
||||||
context.engine.peers.recommendedChannels(peerId: peerId)
|
context.engine.peers.recommendedChannels(peerId: peerId),
|
||||||
|
context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||||
|
|> map { peer -> Bool in
|
||||||
|
return peer?.isPremium ?? false
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|> deliverOnMainQueue).startStrict(next: { [weak self] presentationData, recommendedChannels in
|
|> deliverOnMainQueue).startStrict(next: { [weak self] presentationData, recommendedChannels, isPremium in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
strongSelf.currentState = (recommendedChannels, isPremium)
|
||||||
strongSelf.updateState(recommendedChannels: recommendedChannels, presentationData: presentationData)
|
strongSelf.updateState(recommendedChannels: recommendedChannels, isPremium: isPremium, presentationData: presentationData)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,7 +179,7 @@ final class PeerInfoRecommendedChannelsPaneNode: ASDisplayNode, PeerInfoPaneNode
|
|||||||
|
|
||||||
func update(size: CGSize, topInset: CGFloat, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, expandProgress: CGFloat, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) {
|
func update(size: CGSize, topInset: CGFloat, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, expandProgress: CGFloat, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) {
|
||||||
let isFirstLayout = self.currentParams == nil
|
let isFirstLayout = self.currentParams == nil
|
||||||
self.currentParams = (size, isScrollingLockedAtTop)
|
self.currentParams = (size, sideInset, bottomInset, isScrollingLockedAtTop)
|
||||||
self.presentationDataPromise.set(.single(presentationData))
|
self.presentationDataPromise.set(.single(presentationData))
|
||||||
|
|
||||||
transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(), size: size))
|
transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||||
@ -192,11 +198,41 @@ final class PeerInfoRecommendedChannelsPaneNode: ASDisplayNode, PeerInfoPaneNode
|
|||||||
|
|
||||||
self.listNode.scrollEnabled = !isScrollingLockedAtTop
|
self.listNode.scrollEnabled = !isScrollingLockedAtTop
|
||||||
|
|
||||||
if isFirstLayout, let recommendedChannels = self.currentState {
|
if isFirstLayout, let (recommendedChannels, isPremium) = self.currentState {
|
||||||
self.updateState(recommendedChannels: recommendedChannels, presentationData: presentationData)
|
self.updateState(recommendedChannels: recommendedChannels, isPremium: isPremium, presentationData: presentationData)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.context.isPremium {
|
@objc private func unlockPressed() {
|
||||||
|
let controller = self.context.sharedContext.makePremiumIntroController(context: self.context, source: .ads, forceDark: false, dismissed: nil)
|
||||||
|
self.chatControllerInteraction.navigationController()?.pushViewController(controller)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateState(recommendedChannels: RecommendedChannels?, isPremium: Bool, presentationData: PresentationData) {
|
||||||
|
var entries: [RecommendedChannelsListEntry] = []
|
||||||
|
|
||||||
|
if let channels = recommendedChannels?.channels {
|
||||||
|
for channel in channels {
|
||||||
|
entries.append(.peer(theme: presentationData.theme, index: entries.count, peer: channel.peer, subscribers: channel.subscribers))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let transaction = preparedTransition(from: self.currentEntries, to: entries, context: self.context, presentationData: presentationData, action: { [weak self] peer in
|
||||||
|
self?.chatControllerInteraction.openPeer(peer, .default, nil, .default)
|
||||||
|
}, openPeerContextAction: { [weak self] peer, node, gesture in
|
||||||
|
self?.openPeerContextAction(true, peer, node, gesture)
|
||||||
|
})
|
||||||
|
self.currentEntries = entries
|
||||||
|
self.enqueuedTransactions.append(transaction)
|
||||||
|
self.dequeueTransaction()
|
||||||
|
|
||||||
|
if !isPremium {
|
||||||
|
guard let size = self.currentParams?.size, let sideInset = self.currentParams?.sideInset, let bottomInset = self.currentParams?.bottomInset else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let themeUpdated = self.theme !== presentationData.theme
|
||||||
|
self.theme = presentationData.theme
|
||||||
|
|
||||||
let unlockText: ComponentView<Empty>
|
let unlockText: ComponentView<Empty>
|
||||||
let unlockBackground: UIImageView
|
let unlockBackground: UIImageView
|
||||||
let unlockButton: SolidRoundedButtonNode
|
let unlockButton: SolidRoundedButtonNode
|
||||||
@ -210,9 +246,7 @@ final class PeerInfoRecommendedChannelsPaneNode: ASDisplayNode, PeerInfoPaneNode
|
|||||||
if let current = self.unlockBackground {
|
if let current = self.unlockBackground {
|
||||||
unlockBackground = current
|
unlockBackground = current
|
||||||
} else {
|
} else {
|
||||||
let topColor = presentationData.theme.list.plainBackgroundColor.withAlphaComponent(0.0)
|
unlockBackground = UIImageView()
|
||||||
let bottomColor = presentationData.theme.list.plainBackgroundColor
|
|
||||||
unlockBackground = UIImageView(image: generateGradientImage(size: CGSize(width: 1.0, height: 160.0), colors: [topColor, bottomColor], locations: [0.0, 1.0]))
|
|
||||||
unlockBackground.contentMode = .scaleToFill
|
unlockBackground.contentMode = .scaleToFill
|
||||||
self.view.addSubview(unlockBackground)
|
self.view.addSubview(unlockBackground)
|
||||||
self.unlockBackground = unlockBackground
|
self.unlockBackground = unlockBackground
|
||||||
@ -221,7 +255,7 @@ final class PeerInfoRecommendedChannelsPaneNode: ASDisplayNode, PeerInfoPaneNode
|
|||||||
if let current = self.unlockButton {
|
if let current = self.unlockButton {
|
||||||
unlockButton = current
|
unlockButton = current
|
||||||
} else {
|
} else {
|
||||||
unlockButton = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(theme: presentationData.theme), cornerRadius: 11.0)
|
unlockButton = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(theme: presentationData.theme), height: 50.0, cornerRadius: 10.0)
|
||||||
self.view.addSubview(unlockButton.view)
|
self.view.addSubview(unlockButton.view)
|
||||||
self.unlockButton = unlockButton
|
self.unlockButton = unlockButton
|
||||||
|
|
||||||
@ -235,6 +269,13 @@ final class PeerInfoRecommendedChannelsPaneNode: ASDisplayNode, PeerInfoPaneNode
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if themeUpdated {
|
||||||
|
let topColor = presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.0)
|
||||||
|
let bottomColor = presentationData.theme.list.itemBlocksBackgroundColor
|
||||||
|
unlockBackground.image = generateGradientImage(size: CGSize(width: 1.0, height: 170.0), colors: [topColor, bottomColor, bottomColor], locations: [0.0, 0.3, 1.0])
|
||||||
|
unlockButton.updateTheme(SolidRoundedButtonTheme(theme: presentationData.theme))
|
||||||
|
}
|
||||||
|
|
||||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
let textFont = Font.regular(15.0)
|
let textFont = Font.regular(15.0)
|
||||||
let boldTextFont = Font.semibold(15.0)
|
let boldTextFont = Font.semibold(15.0)
|
||||||
@ -265,45 +306,24 @@ final class PeerInfoRecommendedChannelsPaneNode: ASDisplayNode, PeerInfoPaneNode
|
|||||||
view.frame = CGRect(origin: CGPoint(x: floor((size.width - unlockSize.width) / 2.0), y: size.height - bottomInset - unlockSize.height - 13.0), size: unlockSize)
|
view.frame = CGRect(origin: CGPoint(x: floor((size.width - unlockSize.width) / 2.0), y: size.height - bottomInset - unlockSize.height - 13.0), size: unlockSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
unlockBackground.frame = CGRect(x: 0.0, y: size.height - bottomInset - 160.0, width: size.width, height: bottomInset + 160.0)
|
unlockBackground.frame = CGRect(x: 0.0, y: size.height - bottomInset - 170.0, width: size.width, height: bottomInset + 170.0)
|
||||||
|
|
||||||
let buttonSideInset = sideInset + 16.0
|
let buttonSideInset = sideInset + 16.0
|
||||||
let buttonSize = CGSize(width: size.width - buttonSideInset * 2.0, height: 50.0)
|
let buttonSize = CGSize(width: size.width - buttonSideInset * 2.0, height: 50.0)
|
||||||
unlockButton.frame = CGRect(origin: CGPoint(x: buttonSideInset, y: size.height - bottomInset - unlockSize.height - buttonSize.height - 26.0), size: buttonSize)
|
unlockButton.frame = CGRect(origin: CGPoint(x: buttonSideInset, y: size.height - bottomInset - unlockSize.height - buttonSize.height - 26.0), size: buttonSize)
|
||||||
let _ = unlockButton.updateLayout(width: buttonSize.width, transition: transition)
|
let _ = unlockButton.updateLayout(width: buttonSize.width, transition: .immediate)
|
||||||
} else {
|
} else {
|
||||||
self.unlockBackground?.removeFromSuperview()
|
self.unlockBackground?.removeFromSuperview()
|
||||||
self.unlockBackground = nil
|
self.unlockBackground = nil
|
||||||
|
|
||||||
|
self.unlockButton?.view.removeFromSuperview()
|
||||||
|
self.unlockButton = nil
|
||||||
|
|
||||||
self.unlockText?.view?.removeFromSuperview()
|
self.unlockText?.view?.removeFromSuperview()
|
||||||
self.unlockText = nil
|
self.unlockText = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func unlockPressed() {
|
|
||||||
let controller = self.context.sharedContext.makePremiumIntroController(context: self.context, source: .ads, forceDark: false, dismissed: nil)
|
|
||||||
self.chatControllerInteraction.navigationController()?.pushViewController(controller)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func updateState(recommendedChannels: RecommendedChannels?, presentationData: PresentationData) {
|
|
||||||
var entries: [RecommendedChannelsListEntry] = []
|
|
||||||
|
|
||||||
if let channels = recommendedChannels?.channels {
|
|
||||||
for channel in channels {
|
|
||||||
entries.append(.peer(theme: presentationData.theme, index: entries.count, peer: channel.peer, subscribers: channel.subscribers))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let transaction = preparedTransition(from: self.currentEntries, to: entries, context: self.context, presentationData: presentationData, action: { [weak self] peer in
|
|
||||||
self?.chatControllerInteraction.openPeer(peer, .default, nil, .default)
|
|
||||||
}, openPeerContextAction: { [weak self] peer, node, gesture in
|
|
||||||
self?.openPeerContextAction(true, peer, node, gesture)
|
|
||||||
})
|
|
||||||
self.currentEntries = entries
|
|
||||||
self.enqueuedTransactions.append(transaction)
|
|
||||||
self.dequeueTransaction()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func dequeueTransaction() {
|
private func dequeueTransaction() {
|
||||||
guard let _ = self.currentParams, let transaction = self.enqueuedTransactions.first else {
|
guard let _ = self.currentParams, let transaction = self.enqueuedTransactions.first else {
|
||||||
return
|
return
|
||||||
|
Loading…
x
Reference in New Issue
Block a user