Various improvements

This commit is contained in:
Ilya Laktyushin 2023-10-23 16:43:49 +04:00
parent 3d4ccb4eb0
commit 2246a9f1c2
24 changed files with 637 additions and 135 deletions

View File

@ -23,6 +23,7 @@ public final class ReactionIconView: PortalSourceView {
private var file: TelegramMediaFile?
private var animationCache: AnimationCache?
private var animationRenderer: MultiAnimationRenderer?
private var contentTintColor: UIColor?
private var placeholderColor: UIColor?
private var size: CGSize?
private var animateIdle: Bool?
@ -58,6 +59,7 @@ public final class ReactionIconView: PortalSourceView {
fileId: Int64,
animationCache: AnimationCache,
animationRenderer: MultiAnimationRenderer,
tintColor: UIColor?,
placeholderColor: UIColor,
animateIdle: Bool,
reaction: MessageReaction.Reaction,
@ -66,6 +68,7 @@ public final class ReactionIconView: PortalSourceView {
self.context = context
self.animationCache = animationCache
self.animationRenderer = animationRenderer
self.contentTintColor = tintColor
self.placeholderColor = placeholderColor
self.size = size
self.animateIdle = animateIdle
@ -112,6 +115,8 @@ public final class ReactionIconView: PortalSourceView {
transition.updateFrame(layer: animationLayer, frame: CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize))
}
self.updateTintColor()
}
public func updateIsAnimationHidden(isAnimationHidden: Bool, transition: ContainedViewLayoutTransition) {
@ -170,6 +175,36 @@ public final class ReactionIconView: PortalSourceView {
animationLayer.frame = CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize)
animationLayer.isVisibleForAnimations = animateIdle && context.sharedContext.energyUsageSettings.loopEmoji
self.updateTintColor()
}
private func updateTintColor() {
guard let file = self.file, let animationLayer = self.animationLayer else {
return
}
var accentTint = false
if file.isCustomTemplateEmoji {
accentTint = true
}
for attribute in file.attributes {
if case let .CustomEmoji(_, _, _, packReference) = attribute {
switch packReference {
case let .id(id, _):
if id == 773947703670341676 || id == 2964141614563343 {
accentTint = true
}
default:
break
}
}
}
if accentTint, let tintColor = self.contentTintColor {
animationLayer.contentTintColor = tintColor
animationLayer.dynamicColor = tintColor
} else {
animationLayer.contentTintColor = nil
animationLayer.dynamicColor = nil
}
}
func reset() {
@ -769,6 +804,17 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceView {
animateIdle = false
}
let tintColor: UIColor
if layout.backgroundLayout.colors.isSelected {
if layout.spec.component.colors.selectedForeground != 0 {
tintColor = UIColor(argb: layout.spec.component.colors.selectedForeground)
} else {
tintColor = .white
}
} else {
tintColor = UIColor(argb: layout.spec.component.colors.deselectedForeground)
}
iconView.update(
size: layout.imageFrame.size,
context: layout.spec.component.context,
@ -776,6 +822,7 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceView {
fileId: fileId,
animationCache: arguments.animationCache,
animationRenderer: arguments.animationRenderer,
tintColor: tintColor,
placeholderColor: layout.spec.component.chosenOrder != nil ? UIColor(argb: layout.spec.component.colors.selectedMediaPlaceholder) : UIColor(argb: layout.spec.component.colors.deselectedMediaPlaceholder),
animateIdle: animateIdle,
reaction: layout.spec.component.reaction.value,

View File

@ -218,6 +218,37 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent
}
reactionLayer.frame = iconFrame
}
self.updateReactionAccentColor()
}
func updateReactionAccentColor() {
guard let file = self.file, let reactionLayer = self.reactionLayer, let theme = self.theme else {
return
}
var accentTint = false
if file.isCustomTemplateEmoji {
accentTint = true
}
for attribute in file.attributes {
if case let .CustomEmoji(_, _, _, packReference) = attribute {
switch packReference {
case let .id(id, _):
if id == 773947703670341676 || id == 2964141614563343 {
accentTint = true
}
default:
break
}
}
}
if accentTint {
reactionLayer.contentTintColor = theme.contextMenu.badgeFillColor
reactionLayer.dynamicColor = theme.contextMenu.badgeFillColor
} else {
reactionLayer.contentTintColor = nil
reactionLayer.dynamicColor = nil
}
}
func update(presentationData: PresentationData, constrainedSize: CGSize, isSelected: Bool) -> CGSize {
@ -227,6 +258,8 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent
if let iconNode = self.iconNode {
iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Reactions"), color: presentationData.theme.contextMenu.primaryColor)
}
self.updateReactionLayer()
}
let sideInset: CGFloat = 12.0
@ -478,6 +511,35 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent
}
}
func updateReactionAccentColor(theme: PresentationTheme) {
guard let file = self.file, let reactionLayer = self.reactionLayer else {
return
}
var accentTint = false
if file.isCustomTemplateEmoji {
accentTint = true
}
for attribute in file.attributes {
if case let .CustomEmoji(_, _, _, packReference) = attribute {
switch packReference {
case let .id(id, _):
if id == 773947703670341676 || id == 2964141614563343 {
accentTint = true
}
default:
break
}
}
}
if accentTint {
reactionLayer.contentTintColor = theme.contextMenu.badgeFillColor
reactionLayer.dynamicColor = theme.contextMenu.badgeFillColor
} else {
reactionLayer.contentTintColor = nil
reactionLayer.dynamicColor = nil
}
}
func update(size: CGSize, presentationData: PresentationData, item: EngineMessageReactionListContext.Item, isLast: Bool, syncronousLoad: Bool) {
let avatarInset: CGFloat = 12.0
let avatarSpacing: CGFloat = 8.0
@ -495,6 +557,7 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent
if availableReaction.value == reaction {
self.file = availableReaction.centerAnimation
self.updateReactionLayer()
self.updateReactionAccentColor(theme: presentationData.theme)
break
}
}
@ -507,6 +570,7 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent
}
strongSelf.file = file
strongSelf.updateReactionLayer()
strongSelf.updateReactionAccentColor(theme: presentationData.theme)
}).strict()
}
} else {
@ -520,6 +584,7 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent
}
}
}
self.updateReactionAccentColor(theme: presentationData.theme)
if self.item != item {
self.item = item

View File

@ -39,7 +39,6 @@ public final class SheetComponentEnvironment: Equatable {
public let sheetComponentTag = GenericComponentViewTag()
public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
public typealias EnvironmentType = (ChildEnvironmentType, SheetComponentEnvironment)
public enum BackgroundColor: Equatable {
@ -54,15 +53,18 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
public let content: AnyComponent<ChildEnvironmentType>
public let backgroundColor: BackgroundColor
public let followContentSizeChanges: Bool
public let animateOut: ActionSlot<Action<()>>
public init(
content: AnyComponent<ChildEnvironmentType>,
backgroundColor: BackgroundColor,
followContentSizeChanges: Bool = false,
animateOut: ActionSlot<Action<()>>
) {
self.content = content
self.backgroundColor = backgroundColor
self.followContentSizeChanges = followContentSizeChanges
self.animateOut = animateOut
}
@ -73,6 +75,9 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
if lhs.backgroundColor != rhs.backgroundColor {
return false
}
if lhs.followContentSizeChanges != rhs.followContentSizeChanges {
return false
}
if lhs.animateOut != rhs.animateOut {
return false
}
@ -338,12 +343,15 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
}
transition.setFrame(view: self.scrollView, frame: CGRect(origin: CGPoint(), size: availableSize), completion: nil)
let previousContentSize = self.scrollView.contentSize
self.scrollView.contentSize = contentSize
self.scrollView.contentInset = UIEdgeInsets(top: max(0.0, availableSize.height - contentSize.height) + contentSize.height, left: 0.0, bottom: 0.0, right: 0.0)
self.ignoreScrolling = false
if let currentAvailableSize = self.currentAvailableSize, currentAvailableSize.height != availableSize.height {
self.scrollView.contentOffset = CGPoint(x: 0.0, y: -(availableSize.height - contentSize.height))
} else if component.followContentSizeChanges, !previousContentSize.height.isZero, previousContentSize != contentSize {
transition.setBounds(view: self.scrollView, bounds: CGRect(origin: CGPoint(x: 0.0, y: -(availableSize.height - contentSize.height)), size: availableSize))
}
if self.currentHasInputHeight != previousHasInputHeight {
transition.setBounds(view: self.scrollView, bounds: CGRect(origin: CGPoint(x: 0.0, y: -(availableSize.height - contentSize.height)), size: self.scrollView.bounds.size))

View File

@ -0,0 +1,123 @@
import Foundation
import UIKit
import Display
import SwiftSignalKit
import TelegramCore
import AccountContext
import TelegramPresentationData
import UndoUI
import PresentationDataUtils
//TODO:localize
public func PremiumBoostScreen(
context: AccountContext,
contentContext: Any?,
peerId: EnginePeer.Id,
isCurrent: Bool,
status: ChannelBoostStatus?,
myBoostStatus: MyBoostStatus?,
forceDark: Bool,
openPeer: @escaping (EnginePeer) -> Void,
presentController: @escaping (ViewController) -> Void,
pushController: @escaping (ViewController) -> Void,
dismissed: @escaping () -> Void
) {
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|> deliverOnMainQueue).startStandalone(next: { peer in
guard let peer, let status else {
return
}
var myBoostCount: Int32 = 0
var availableBoosts: [MyBoostStatus.Boost] = []
var occupiedBoosts: [MyBoostStatus.Boost] = []
if let myBoostStatus {
for boost in myBoostStatus.boosts {
if let boostPeer = boost.peer {
if boostPeer.id == peer.id {
myBoostCount += 1
} else {
occupiedBoosts.append(boost)
}
} else {
availableBoosts.append(boost)
}
}
}
var currentLevel = Int32(status.level)
var currentLevelBoosts = Int32(status.currentLevelBoosts)
var nextLevelBoosts = status.nextLevelBoosts.flatMap(Int32.init)
if myBoostCount > 0 && status.boosts == currentLevelBoosts {
currentLevel = max(0, currentLevel - 1)
nextLevelBoosts = currentLevelBoosts
currentLevelBoosts = max(0, currentLevelBoosts - 1)
}
let subject: PremiumLimitScreen.Subject = .storiesChannelBoost(peer: peer, isCurrent: isCurrent, level: currentLevel, currentLevelBoosts: currentLevelBoosts, nextLevelBoosts: nextLevelBoosts, link: nil, myBoostCount: myBoostCount)
let nextSubject: PremiumLimitScreen.Subject = .storiesChannelBoost(peer: peer, isCurrent: isCurrent, level: currentLevel, currentLevelBoosts: currentLevelBoosts, nextLevelBoosts: nextLevelBoosts, link: nil, myBoostCount: myBoostCount + 1)
var nextCount = Int32(status.boosts + 1)
var updateImpl: (() -> Void)?
var dismissImpl: (() -> Void)?
let controller = PremiumLimitScreen(context: context, subject: subject, count: Int32(status.boosts), forceDark: forceDark, action: {
let dismiss = false
updateImpl?()
return dismiss
},
openPeer: { peer in
openPeer(peer)
})
pushController(controller)
controller.disposed = {
dismissed()
}
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
updateImpl = { [weak controller] in
if let _ = status.nextLevelBoosts {
if let availableBoost = availableBoosts.first {
let _ = context.engine.peers.applyChannelBoost(peerId: peerId, slots: [availableBoost.slot]).startStandalone()
controller?.updateSubject(nextSubject, count: nextCount)
availableBoosts.removeFirst()
nextCount += 1
} else if !occupiedBoosts.isEmpty, let myBoostStatus {
let replaceController = ReplaceBoostScreen(context: context, peerId: peerId, myBoostStatus: myBoostStatus, replaceBoosts: { slots in
let _ = context.engine.peers.applyChannelBoost(peerId: peerId, slots: slots).startStandalone()
let undoController = UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: "\(slots.count) boosts are reassigned from 1 other channel.", timeout: nil, customUndoText: nil), elevatedLayout: true, position: .bottom, action: { _ in return true })
presentController(undoController)
})
dismissImpl?()
pushController(replaceController)
} else {
let controller = textAlertController(
sharedContext: context.sharedContext,
updatedPresentationData: nil,
title: presentationData.strings.ChannelBoost_Error_PremiumNeededTitle,
text: presentationData.strings.ChannelBoost_Error_PremiumNeededText,
actions: [
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}),
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Yes, action: {
dismissImpl?()
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .channelBoost(peerId), forceDark: forceDark, dismissed: nil)
pushController(controller)
})
],
parseMarkdown: true
)
presentController(controller)
}
} else {
dismissImpl?()
}
}
dismissImpl = { [weak controller] in
controller?.dismissAnimated()
}
})
}

View File

@ -1262,11 +1262,6 @@ public class PremiumDemoScreen: ViewControllerComponentContainer {
self.view.disablesInteractiveModalDismiss = true
}
public override func replace(with controller: ViewController) {
self.dismissAnimated()
super.replace(with: controller)
}
public func dismissAnimated() {
if let view = self.node.hostView.findTaggedView(tag: SheetComponent<ViewControllerComponentContainer.Environment>.View.Tag()) as? SheetComponent<ViewControllerComponentContainer.Environment>.View {
view.dismissAnimated()

View File

@ -162,6 +162,9 @@ public class PremiumLimitDisplayComponent: Component {
private let badgeLabel: BadgeLabelView
private let badgeLabelMaskView = UIImageView()
private var badgeTailPosition: CGFloat = 0.0
private var badgeShapeArguments: (Double, Double, CGSize, CGFloat, CGFloat)?
private let hapticFeedback = HapticFeedback()
override init(frame: CGRect) {
@ -232,6 +235,10 @@ public class PremiumLimitDisplayComponent: Component {
fatalError("init(coder:) has not been implemented")
}
deinit {
self.badgeShapeAnimator?.invalidate()
}
private var didPlayAppearanceAnimation = false
func playAppearanceAnimation(component: PremiumLimitDisplayComponent, badgeFullSize: CGSize, from: CGFloat? = nil) {
if from == nil {
@ -534,17 +541,30 @@ public class PremiumLimitDisplayComponent: Component {
if badgePosition > 1.0 - 0.15 {
progressTransition.setAnchorPoint(layer: self.badgeView.layer, anchorPoint: CGPoint(x: 1.0, y: 1.0))
progressTransition.setShapeLayerPath(layer: self.badgeShapeLayer, path: generateRoundedRectWithTailPath(rectSize: badgeSize, tailPosition: component.isPremiumDisabled ? nil : 1.0).cgPath)
if component.isPremiumDisabled || progressTransition.animation.isImmediate {
self.badgeShapeLayer.path = generateRoundedRectWithTailPath(rectSize: badgeSize, tailPosition: component.isPremiumDisabled ? nil : 1.0).cgPath
} else {
self.badgeShapeArguments = (CACurrentMediaTime(), 0.5, badgeSize, self.badgeTailPosition, 1.0)
self.animateBadgeTailPositionChange()
}
self.badgeTailPosition = 1.0
if let _ = self.badgeView.layer.animation(forKey: "appearance1") {
} else {
self.badgeView.center = CGPoint(x: 3.0 + (size.width - 6.0) * badgePosition + 3.0, y: 82.0)
}
} else if badgePosition < 0.15 {
progressTransition.setAnchorPoint(layer: self.badgeView.layer, anchorPoint: CGPoint(x: 0.0, y: 1.0))
progressTransition.setShapeLayerPath(layer: self.badgeShapeLayer, path: generateRoundedRectWithTailPath(rectSize: badgeSize, tailPosition: component.isPremiumDisabled ? nil : 0.0).cgPath)
if component.isPremiumDisabled || progressTransition.animation.isImmediate {
self.badgeShapeLayer.path = generateRoundedRectWithTailPath(rectSize: badgeSize, tailPosition: component.isPremiumDisabled ? nil : 0.0).cgPath
} else {
self.badgeShapeArguments = (CACurrentMediaTime(), 0.5, badgeSize, self.badgeTailPosition, 0.0)
self.animateBadgeTailPositionChange()
}
self.badgeTailPosition = 0.0
if let _ = self.badgeView.layer.animation(forKey: "appearance1") {
} else {
@ -552,8 +572,15 @@ public class PremiumLimitDisplayComponent: Component {
}
} else {
progressTransition.setAnchorPoint(layer: self.badgeView.layer, anchorPoint: CGPoint(x: 0.5, y: 1.0))
progressTransition.setShapeLayerPath(layer: self.badgeShapeLayer, path: generateRoundedRectWithTailPath(rectSize: badgeSize, tailPosition: component.isPremiumDisabled ? nil : 0.5).cgPath)
if component.isPremiumDisabled || progressTransition.animation.isImmediate {
self.badgeShapeLayer.path = generateRoundedRectWithTailPath(rectSize: badgeSize, tailPosition: component.isPremiumDisabled ? nil : 0.5).cgPath
} else {
self.badgeShapeArguments = (CACurrentMediaTime(), 0.5, badgeSize, self.badgeTailPosition, 0.5)
self.animateBadgeTailPositionChange()
}
self.badgeTailPosition = 0.5
if let _ = self.badgeView.layer.animation(forKey: "appearance1") {
} else {
@ -617,6 +644,36 @@ public class PremiumLimitDisplayComponent: Component {
return size
}
private var badgeShapeAnimator: ConstantDisplayLinkAnimator?
private func animateBadgeTailPositionChange() {
if self.badgeShapeAnimator == nil {
self.badgeShapeAnimator = ConstantDisplayLinkAnimator(update: { [weak self] in
self?.animateBadgeTailPositionChange()
})
self.badgeShapeAnimator?.isPaused = true
}
if let (startTime, duration, badgeSize, initial, target) = self.badgeShapeArguments {
self.badgeShapeAnimator?.isPaused = false
let t = CGFloat(max(0.0, min(1.0, (CACurrentMediaTime() - startTime) / duration)))
let value = initial + (target - initial) * t
self.badgeShapeLayer.path = generateRoundedRectWithTailPath(rectSize: badgeSize, tailPosition: value).cgPath
if t >= 1.0 {
self.badgeShapeArguments = nil
self.badgeShapeAnimator?.isPaused = true
self.badgeShapeAnimator?.invalidate()
self.badgeShapeAnimator = nil
}
} else {
self.badgeShapeAnimator?.isPaused = true
self.badgeShapeAnimator?.invalidate()
self.badgeShapeAnimator = nil
}
}
private func setupGradientAnimations() {
guard let _ = self.component else {
return
@ -1143,12 +1200,14 @@ private final class LimitSheetContent: CombinedComponent {
string = strings.ChannelBoost_HelpUpgradeChannelText(peer.compactDisplayTitle, boostsString, storiesString).string
}
actionButtonText = strings.ChannelBoost_BoostChannel
buttonIconName = "Premium/BoostChannel"
} else {
titleText = strings.ChannelBoost_MaxLevelReached
string = strings.ChannelBoost_BoostedChannelReachedLevel("\(level)", storiesString).string
actionButtonText = strings.Common_OK
buttonIconName = nil
actionButtonHasGloss = false
}
buttonIconName = "Premium/BoostChannel"
}
buttonAnimationName = nil
defaultTitle = strings.ChannelBoost_Level("\(level)").string
@ -1161,11 +1220,13 @@ private final class LimitSheetContent: CombinedComponent {
let prefixString = isCurrent ? strings.ChannelBoost_YouBoostedChannelText(peer.compactDisplayTitle).string : strings.ChannelBoost_YouBoostedOtherChannelText
let storiesString = strings.ChannelBoost_StoriesPerDay(level + 1)
// buttonIconName = nil
// actionButtonText = environment.strings.Common_OK
actionButtonText = "Boost Again"
if let _ = remaining {
actionButtonText = "Boost Again"
} else {
buttonIconName = nil
actionButtonText = environment.strings.Common_OK
actionButtonHasGloss = false
}
if let remaining {
let boostsString = strings.ChannelBoost_MoreBoosts(remaining)
if level == 0 {
@ -1209,7 +1270,6 @@ private final class LimitSheetContent: CombinedComponent {
reachedMaximumLimit = false
}
let contentSize: CGSize
if state.initialized {
let title = title.update(
@ -1391,6 +1451,7 @@ private final class LimitSheetContent: CombinedComponent {
}))
)
} else if let alternateTextChild {
textOffset += 9.0
textSize = alternateTextChild.size
context.add(alternateTextChild
.position(CGPoint(x: context.availableSize.width / 2.0, y: textOffset))
@ -1498,7 +1559,7 @@ private final class LimitSheetContent: CombinedComponent {
.position(CGPoint(x: context.availableSize.width / 2.0, y: buttonFrame.maxY + 50.0 + giftText.size.height / 2.0))
)
additionalContentHeight += giftText.size.height + 50.0
additionalContentHeight += giftText.size.height + 30.0
}
contentSize = CGSize(width: context.availableSize.width, height: buttonFrame.maxY + additionalContentHeight + 5.0 + environment.safeInsets.bottom)
@ -1598,6 +1659,7 @@ private final class LimitSheetComponent: CombinedComponent {
openGift: context.component.openGift
)),
backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor),
followContentSizeChanges: true,
animateOut: animateOut
),
environment: {

View File

@ -19,6 +19,8 @@ import PeerListItemComponent
import TelegramStringFormatting
import AvatarNode
//TODO:localize
private final class ReplaceBoostScreenComponent: CombinedComponent {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
@ -799,6 +801,7 @@ public class ReplaceBoostScreen: ViewController {
self?.node.selectedSlots = selectedSlots
}
presentControllerImpl = { [weak self] c in
self?.dismissAllTooltips()
self?.present(c, in: .window(.root))
}
@ -819,15 +822,29 @@ public class ReplaceBoostScreen: ViewController {
fatalError("init(coder:) has not been implemented")
}
@objc private func cancelPressed() {
self.dismiss(animated: true, completion: nil)
}
override open func loadDisplayNode() {
self.displayNode = Node(context: self.context, controller: self, component: self.component)
self.displayNodeDidLoad()
}
fileprivate func dismissAllTooltips() {
self.window?.forEachController({ controller in
if let controller = controller as? UndoOverlayController {
controller.dismiss()
}
})
self.forEachController({ controller in
if let controller = controller as? UndoOverlayController {
controller.dismiss()
}
return true
})
}
@objc private func cancelPressed() {
self.dismiss(animated: true, completion: nil)
}
public override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
self.view.endEditing(true)

View File

@ -133,9 +133,9 @@ class ForwardPrivacyChatPreviewItemNode: ListViewItemNode {
return { item, params, neighbors in
if currentBackgroundNode == nil {
currentBackgroundNode = createWallpaperBackgroundNode(context: item.context, forChatDisplay: false)
currentBackgroundNode?.update(wallpaper: item.wallpaper)
currentBackgroundNode?.updateBubbleTheme(bubbleTheme: item.theme, bubbleCorners: item.chatBubbleCorners)
}
currentBackgroundNode?.update(wallpaper: item.wallpaper)
currentBackgroundNode?.updateBubbleTheme(bubbleTheme: item.theme, bubbleCorners: item.chatBubbleCorners)
let insets: UIEdgeInsets
let separatorHeight = UIScreenPixel
@ -189,6 +189,11 @@ class ForwardPrivacyChatPreviewItemNode: ListViewItemNode {
if let strongSelf = self {
strongSelf.item = item
if let currentBackgroundNode {
currentBackgroundNode.update(wallpaper: item.wallpaper)
currentBackgroundNode.updateBubbleTheme(bubbleTheme: item.theme, bubbleCorners: item.chatBubbleCorners)
}
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: contentSize)
var topOffset: CGFloat = 8.0

View File

@ -261,10 +261,10 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
return { item, params, neighbors in
if currentBackgroundNode == nil {
currentBackgroundNode = createWallpaperBackgroundNode(context: item.context, forChatDisplay: false)
currentBackgroundNode?.update(wallpaper: item.wallpaper)
currentBackgroundNode?.updateBubbleTheme(bubbleTheme: item.theme, bubbleCorners: item.chatBubbleCorners)
}
currentBackgroundNode?.update(wallpaper: item.wallpaper)
currentBackgroundNode?.updateBubbleTheme(bubbleTheme: item.theme, bubbleCorners: item.chatBubbleCorners)
let insets: UIEdgeInsets
let separatorHeight = UIScreenPixel
@ -330,6 +330,11 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
strongSelf.item = item
if let currentBackgroundNode {
currentBackgroundNode.update(wallpaper: item.wallpaper)
currentBackgroundNode.updateBubbleTheme(bubbleTheme: item.theme, bubbleCorners: item.chatBubbleCorners)
}
if strongSelf.genericReactionEffectDisposable == nil {
strongSelf.loadNextGenericReactionEffect(context: item.context)
}

View File

@ -128,7 +128,7 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
case let .messageActionSetSameChatWallPaper(wallpaper):
return TelegramMediaAction(action: .setSameChatWallpaper(wallpaper: TelegramWallpaper(apiWallpaper: wallpaper)))
case let .messageActionGiftCode(flags, boostPeer, months, slug):
return TelegramMediaAction(action: .giftCode(slug: slug, fromGiveaway: (flags & (1 << 0)) != 0, boostPeerId: boostPeer?.peerId, months: months))
return TelegramMediaAction(action: .giftCode(slug: slug, fromGiveaway: (flags & (1 << 0)) != 0, isUnclaimed: (flags & (1 << 1)) != 0, boostPeerId: boostPeer?.peerId, months: months))
case .messageActionGiveawayLaunch:
return TelegramMediaAction(action: .giveawayLaunched)
}

View File

@ -113,7 +113,7 @@ func _internal_applyChannelBoost(account: Account, peerId: PeerId, slots: [Int32
|> map (Optional.init)
|> `catch` { error -> Signal<Api.premium.MyBoosts?, NoError> in
return .complete()
}
}
|> mapToSignal { result -> Signal<MyBoostStatus?, NoError> in
if let result = result {
return account.postbox.transaction { transaction -> MyBoostStatus? in

View File

@ -109,7 +109,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
case requestedPeer(buttonId: Int32, peerId: PeerId)
case setChatWallpaper(wallpaper: TelegramWallpaper)
case setSameChatWallpaper(wallpaper: TelegramWallpaper)
case giftCode(slug: String, fromGiveaway: Bool, boostPeerId: PeerId?, months: Int32)
case giftCode(slug: String, fromGiveaway: Bool, isUnclaimed: Bool, boostPeerId: PeerId?, months: Int32)
case giveawayLaunched
public init(decoder: PostboxDecoder) {
@ -206,7 +206,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
case 35:
self = .botAppAccessGranted(appName: decoder.decodeOptionalStringForKey("app"), type: decoder.decodeOptionalInt32ForKey("atp").flatMap { BotSendMessageAccessGrantedType(rawValue: $0) })
case 36:
self = .giftCode(slug: decoder.decodeStringForKey("slug", orElse: ""), fromGiveaway: decoder.decodeBoolForKey("give", orElse: false), boostPeerId: PeerId(decoder.decodeInt64ForKey("pi", orElse: 0)), months: decoder.decodeInt32ForKey("months", orElse: 0))
self = .giftCode(slug: decoder.decodeStringForKey("slug", orElse: ""), fromGiveaway: decoder.decodeBoolForKey("give", orElse: false), isUnclaimed: decoder.decodeBoolForKey("unclaimed", orElse: false), boostPeerId: PeerId(decoder.decodeInt64ForKey("pi", orElse: 0)), months: decoder.decodeInt32ForKey("months", orElse: 0))
case 37:
self = .giveawayLaunched
default:
@ -388,10 +388,11 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
} else {
encoder.encodeNil(forKey: "atp")
}
case let .giftCode(slug, fromGiveaway, boostPeerId, months):
case let .giftCode(slug, fromGiveaway, unclaimed, boostPeerId, months):
encoder.encodeInt32(36, forKey: "_rawValue")
encoder.encodeString(slug, forKey: "slug")
encoder.encodeBool(fromGiveaway, forKey: "give")
encoder.encodeBool(unclaimed, forKey: "unclaimed")
if let boostPeerId = boostPeerId {
encoder.encodeInt64(boostPeerId.toInt64(), forKey: "pi")
} else {
@ -421,7 +422,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
return peerIds
case let .requestedPeer(_, peerId):
return [peerId]
case let .giftCode(_, _, boostPeerId, _):
case let .giftCode(_, _, _, boostPeerId, _):
return boostPeerId.flatMap { [$0] } ?? []
default:
return []

View File

@ -166,6 +166,7 @@ private final class StatusReactionNode: ASDisplayNode {
fileId: fileId,
animationCache: animationCache,
animationRenderer: animationRenderer,
tintColor: nil,
placeholderColor: placeholderColor,
animateIdle: animateIdle,
reaction: value,

View File

@ -188,7 +188,8 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
})
}
}
//TODO:localize
override public func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let makeLabelLayout = TextNode.asyncLayout(self.labelNode)
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
@ -220,17 +221,22 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
case let .giftPremium(_, _, monthsValue, _, _):
months = monthsValue
text = item.presentationData.strings.Notification_PremiumGift_Subtitle(item.presentationData.strings.Notification_PremiumGift_Months(months)).string
case let .giftCode(_, fromGiveaway, channelId, monthsValue):
case let .giftCode(_, fromGiveaway, unclaimed, channelId, monthsValue):
giftSize.width += 34.0
giftSize.height += 84.0
textSpacing += 13.0
title = "Congratulations!"
if unclaimed {
title = "Unclaimed Prize"
} else {
title = "Congratulations!"
}
var peerName = ""
if let channelId, let channel = item.message.peers[channelId] {
peerName = EnginePeer(channel).compactDisplayTitle
}
if fromGiveaway {
if unclaimed {
text = "You have an unclaimed prize from a giveaway by **\(peerName)**.\n\nThis prize is a **Telegram Premium** subscription for **\(monthsValue)** months."
} else if fromGiveaway {
text = "You won a prize in a giveaway organized by **\(peerName)**.\n\nYour prize is a **Telegram Premium** subscription for **\(monthsValue)** months."
} else {
text = "You've received a gift from **\(peerName)**.\n\nYour gift is a **Telegram Premium** subscription for **\(monthsValue)** months."
@ -273,6 +279,8 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
let (buttonTitleLayout, buttonTitleApply) = makeButtonTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: buttonTitle, font: Font.semibold(15.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
giftSize.height = titleLayout.size.height + subtitleLayout.size.height + 225.0
var labelRects = labelLayout.linesRects()
if labelRects.count > 1 {
let sortedIndices = (0 ..< labelRects.count).sorted(by: { labelRects[$0].width > labelRects[$1].width })

View File

@ -449,6 +449,7 @@ public final class MessageInputActionButtonComponent: Component {
fileId: animationFileId ?? reactionFile?.fileId.id ?? 0,
animationCache: component.context.animationCache,
animationRenderer: component.context.animationRenderer,
tintColor: nil,
placeholderColor: UIColor(white: 1.0, alpha: 0.2),
animateIdle: false,
reaction: reaction,

View File

@ -168,9 +168,9 @@ final class PeerNameColorChatPreviewItemNode: ListViewItemNode {
return { item, params, neighbors in
if currentBackgroundNode == nil {
currentBackgroundNode = createWallpaperBackgroundNode(context: item.context, forChatDisplay: false)
currentBackgroundNode?.update(wallpaper: item.wallpaper)
currentBackgroundNode?.updateBubbleTheme(bubbleTheme: item.componentTheme, bubbleCorners: item.chatBubbleCorners)
}
currentBackgroundNode?.update(wallpaper: item.wallpaper)
currentBackgroundNode?.updateBubbleTheme(bubbleTheme: item.componentTheme, bubbleCorners: item.chatBubbleCorners)
let insets: UIEdgeInsets
let separatorHeight = UIScreenPixel
@ -250,6 +250,11 @@ final class PeerNameColorChatPreviewItemNode: ListViewItemNode {
if let strongSelf = self {
strongSelf.item = item
if let currentBackgroundNode {
currentBackgroundNode.update(wallpaper: item.wallpaper)
currentBackgroundNode.updateBubbleTheme(bubbleTheme: item.theme, bubbleCorners: item.chatBubbleCorners)
}
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: contentSize)
if let currentItem, currentItem.messageItems.first?.nameColor != item.messageItems.first?.nameColor || currentItem.messageItems.first?.backgroundEmojiId != item.messageItems.first?.backgroundEmojiId {

View File

@ -412,7 +412,8 @@ public func PeerNameColorScreen(
updatedState.inProgress = true
return updatedState
}
let _ = context.engine.peers.updatePeerNameColorAndEmoji(peerId: peerId, nameColor: nameColor ?? .blue, backgroundEmojiId: backgroundEmojiId ?? 0).startStandalone(next: {
let _ = (context.engine.peers.updatePeerNameColorAndEmoji(peerId: peerId, nameColor: nameColor ?? .blue, backgroundEmojiId: backgroundEmojiId ?? 0)
|> deliverOnMainQueue).startStandalone(next: {
}, error: { error in
if case .channelBoostRequired = error {
let _ = combineLatest(

View File

@ -25,6 +25,7 @@ import TelegramUIPreferences
import UndoUI
import TelegramStringFormatting
//TODO:localize
final class ShareWithPeersScreenComponent: Component {
typealias EnvironmentType = ViewControllerComponentContainer.Environment

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "brush_30.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,193 @@
%PDF-1.7
1 0 obj
<< /Type /XObject
/Length 2 0 R
/Group << /Type /Group
/S /Transparency
>>
/Subtype /Form
/Resources << >>
/BBox [ 0.000000 0.000000 30.000000 30.000000 ]
>>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
1.000000 0.584314 0.000000 scn
0.000000 18.799999 m
0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c
1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c
5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c
18.799999 30.000000 l
22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c
27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c
30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c
30.000000 11.200001 l
30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c
28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c
24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c
11.200000 0.000000 l
7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c
0.000000 18.799999 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 5.000000 3.864258 cm
1.000000 1.000000 1.000000 scn
17.269485 19.786890 m
18.869095 20.947046 20.890579 18.978296 19.730423 17.325953 c
19.405228 16.877710 16.109329 12.034937 13.402297 8.967554 c
12.690383 11.103296 11.038039 12.755640 8.911086 13.458765 c
11.978469 16.165796 16.821243 19.461695 17.269485 19.786890 c
h
8.867141 8.932398 m
8.164016 9.635523 7.267532 10.136499 6.476516 10.285913 c
6.590774 10.927515 6.889602 11.481226 7.408157 12.034937 c
7.496047 12.131617 7.583938 12.219507 7.680618 12.307398 c
9.965775 11.982203 11.908156 10.022242 12.242141 7.737085 c
12.154250 7.640406 12.066360 7.552515 11.960891 7.464624 c
11.415969 6.954859 10.879836 6.664820 10.229445 6.541773 c
10.071242 7.332788 9.570266 8.229273 8.867141 8.932398 c
h
0.385696 3.527124 m
-0.062546 4.072046 -0.141648 4.564234 0.262649 4.889429 c
0.746047 5.267359 1.378860 4.915796 2.081985 5.460718 c
2.864211 6.058374 2.310500 7.394312 3.690383 8.466578 c
5.043899 9.565210 7.074172 9.204859 8.287063 7.666773 c
9.623000 5.961695 9.368118 3.869898 7.592727 2.481226 c
5.465774 0.811304 2.064407 1.400171 0.385696 3.527124 c
h
f
n
Q
endstream
endobj
2 0 obj
2104
endobj
3 0 obj
<< /Type /XObject
/Length 4 0 R
/Group << /Type /Group
/S /Transparency
>>
/Subtype /Form
/Resources << >>
/BBox [ 0.000000 0.000000 30.000000 30.000000 ]
>>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
0.000000 0.000000 0.000000 scn
0.000000 18.799999 m
0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c
1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c
5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c
18.799999 30.000000 l
22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c
27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c
30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c
30.000000 11.200001 l
30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c
28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c
24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c
11.200000 0.000000 l
7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c
0.000000 18.799999 l
h
f
n
Q
endstream
endobj
4 0 obj
944
endobj
5 0 obj
<< /XObject << /X1 1 0 R >>
/ExtGState << /E1 << /SMask << /Type /Mask
/G 3 0 R
/S /Alpha
>>
/Type /ExtGState
>> >>
>>
endobj
6 0 obj
<< /Length 7 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
/E1 gs
/X1 Do
Q
endstream
endobj
7 0 obj
46
endobj
8 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
/Resources 5 0 R
/Contents 6 0 R
/Parent 9 0 R
>>
endobj
9 0 obj
<< /Kids [ 8 0 R ]
/Count 1
/Type /Pages
>>
endobj
10 0 obj
<< /Pages 9 0 R
/Type /Catalog
>>
endobj
xref
0 11
0000000000 65535 f
0000000010 00000 n
0000002362 00000 n
0000002385 00000 n
0000003577 00000 n
0000003599 00000 n
0000003897 00000 n
0000003999 00000 n
0000004020 00000 n
0000004193 00000 n
0000004267 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 10 0 R
/Size 11
>>
startxref
4327
%%EOF

View File

@ -948,7 +948,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let controller = PremiumIntroScreen(context: strongSelf.context, source: .gift(from: fromPeerId, to: toPeerId, duration: duration))
strongSelf.push(controller)
return true
case let .giftCode(slug, _, _, _):
case let .giftCode(slug, _, _, _, _):
strongSelf.openResolved(result: .premiumGiftCode(slug: slug), sourceMessageId: message.id)
return true
case let .suggestedProfilePhoto(image):

View File

@ -842,101 +842,49 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
}
})
case let .boost(peerId, status, myBoostStatus):
let _ = myBoostStatus
var isCurrent = false
if case let .chat(chatPeerId, _) = urlContext, chatPeerId == peerId {
isCurrent = true
}
var forceDark = false
if let updatedPresentationData, updatedPresentationData.initial.theme.overallDarkAppearance {
forceDark = true
}
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|> deliverOnMainQueue).startStandalone(next: { peer in
guard let peer, let status else {
return
var dismissedImpl: (() -> Void)?
if let storyProgressPauseContext = contentContext as? StoryProgressPauseContext {
let updateExternalController = storyProgressPauseContext.update
dismissedImpl = {
updateExternalController(nil)
}
var myBoostCount: Int32 = 0
var availableBoosts: [MyBoostStatus.Boost] = []
var occupiedBoosts: [MyBoostStatus.Boost] = []
if let myBoostStatus {
for boost in myBoostStatus.boosts {
if let boostPeer = boost.peer {
if boostPeer.id == peer.id {
myBoostCount += 1
} else {
occupiedBoosts.append(boost)
}
} else {
availableBoosts.append(boost)
}
}
}
var isCurrent = false
if case let .chat(chatPeerId, _) = urlContext, chatPeerId == peerId {
isCurrent = true
}
var currentLevel = Int32(status.level)
var currentLevelBoosts = Int32(status.currentLevelBoosts)
var nextLevelBoosts = status.nextLevelBoosts.flatMap(Int32.init)
if myBoostCount > 0 && status.boosts == currentLevelBoosts {
currentLevel = max(0, currentLevel - 1)
nextLevelBoosts = currentLevelBoosts
currentLevelBoosts = max(0, currentLevelBoosts - 1)
}
let subject: PremiumLimitScreen.Subject = .storiesChannelBoost(peer: peer, isCurrent: isCurrent, level: currentLevel, currentLevelBoosts: currentLevelBoosts, nextLevelBoosts: nextLevelBoosts, link: nil, myBoostCount: myBoostCount)
let nextSubject: PremiumLimitScreen.Subject = .storiesChannelBoost(peer: peer, isCurrent: isCurrent, level: currentLevel, currentLevelBoosts: currentLevelBoosts, nextLevelBoosts: nextLevelBoosts, link: nil, myBoostCount: myBoostCount + 1)
var nextCount = Int32(status.boosts + 1)
var updateImpl: (() -> Void)?
var dismissImpl: (() -> Void)?
let controller = PremiumLimitScreen(context: context, subject: subject, count: Int32(status.boosts), forceDark: forceDark, action: {
let dismiss = false
updateImpl?()
return dismiss
},
}
PremiumBoostScreen(
context: context,
contentContext: contentContext,
peerId: peerId,
isCurrent: isCurrent,
status: status,
myBoostStatus: myBoostStatus,
forceDark: forceDark,
openPeer: { peer in
openPeer(peer, .chat(textInputState: nil, subject: nil, peekData: nil))
})
navigationController?.pushViewController(controller)
if let storyProgressPauseContext = contentContext as? StoryProgressPauseContext {
storyProgressPauseContext.update(controller)
},
presentController: { [weak navigationController] c in
(navigationController?.viewControllers.last as? ViewController)?.present(c, in: .window(.root))
},
pushController: { [weak navigationController] c in
navigationController?.pushViewController(c)
let updateExternalController = storyProgressPauseContext.update
controller.disposed = {
updateExternalController(nil)
}
}
updateImpl = { [weak controller] in
if let _ = status.nextLevelBoosts {
if let availableBoost = availableBoosts.first {
let _ = context.engine.peers.applyChannelBoost(peerId: peerId, slots: [availableBoost.slot]).startStandalone()
controller?.updateSubject(nextSubject, count: nextCount)
availableBoosts.removeFirst()
nextCount += 1
} else if !occupiedBoosts.isEmpty, let myBoostStatus {
let replaceController = ReplaceBoostScreen(context: context, peerId: peerId, myBoostStatus: myBoostStatus, replaceBoosts: { slots in
let _ = context.engine.peers.applyChannelBoost(peerId: peerId, slots: slots).startStandalone()
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let undoController = UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: "\(slots.count) boosts are reassigned from 1 other channel.", timeout: nil, customUndoText: nil), elevatedLayout: true, position: .bottom, action: { _ in return true })
(navigationController?.viewControllers.last as? ViewController)?.present(undoController, in: .window(.root))
})
dismissImpl?()
navigationController?.pushViewController(replaceController)
if c is PremiumLimitScreen {
if let storyProgressPauseContext = contentContext as? StoryProgressPauseContext {
storyProgressPauseContext.update(c)
}
} else {
dismissImpl?()
}
}, dismissed: {
dismissedImpl?()
}
dismissImpl = { [weak controller] in
controller?.dismissAnimated()
}
})
)
case let .premiumGiftCode(slug):
var forceDark = false
if let updatedPresentationData, updatedPresentationData.initial.theme.overallDarkAppearance {

View File

@ -156,7 +156,11 @@ private final class PeerInfoScreenDisclosureItemNode: PeerInfoScreenItemNode {
self.textNode.attributedText = NSAttributedString(string: item.text, font: titleFont, textColor: textColorValue)
let textSize = self.textNode.updateLayout(CGSize(width: width - (leftInset + rightInset), height: .greatestFiniteMagnitude))
let labelSize = self.labelNode.updateLayout(CGSize(width: width - textSize.width - (leftInset + rightInset), height: .greatestFiniteMagnitude))
var labelConstrainWidth = width - textSize.width - (leftInset + rightInset)
if case .semitransparentBadge = item.label {
labelConstrainWidth -= 16.0
}
let labelSize = self.labelNode.updateLayout(CGSize(width: labelConstrainWidth, height: .greatestFiniteMagnitude))
let textFrame = CGRect(origin: CGPoint(x: leftInset, y: 12.0), size: textSize)

View File

@ -1568,12 +1568,6 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL
}))
}
if isCreator || (channel.adminRights?.rights.contains(.canChangeInfo) == true) {
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemNameColor, label: .semitransparentBadge(EnginePeer(channel).compactDisplayTitle, (data.peer?.nameColor ?? .blue).color), text: "Channel Color", icon: UIImage(bundleImageName: "Settings/Menu/Appearance"), action: {
interaction.editingOpenNameColorSetup()
}))
}
if (isCreator && (channel.addressName?.isEmpty ?? true)) || (!channel.flags.contains(.isCreator) && channel.adminRights?.rights.contains(.canInviteUsers) == true) {
let invitesText: String
if let count = data.invitations?.count, count > 0 {
@ -1626,6 +1620,12 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL
}))
}
if isCreator || (channel.adminRights?.rights.contains(.canChangeInfo) == true) {
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemNameColor, label: .semitransparentBadge(EnginePeer(channel).compactDisplayTitle, (data.peer?.nameColor ?? .blue).color), text: "Channel Color", icon: UIImage(bundleImageName: "Chat/Info/NameColorIcon"), action: {
interaction.editingOpenNameColorSetup()
}))
}
if isCreator || (channel.adminRights != nil && channel.hasPermission(.sendSomething)) {
let messagesShouldHaveSignatures: Bool
switch channel.info {