Merge commit 'b70c7b2868b04cca4d86dc568a7c97f5ce02d466'

This commit is contained in:
Ali 2023-10-30 19:50:45 +04:00
commit 4e01a117db
11 changed files with 324 additions and 206 deletions

View File

@ -791,9 +791,9 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
let badgeCount: Int32 let badgeCount: Int32
switch state.mode { switch state.mode {
case .giveaway: case .giveaway:
badgeCount = state.subscriptions badgeCount = state.subscriptions * 4
case .gift: case .gift:
badgeCount = Int32(state.peers.count) badgeCount = Int32(state.peers.count) * 4
} }
let footerItem = CreateGiveawayFooterItem(theme: presentationData.theme, title: state.mode == .gift ? presentationData.strings.BoostGift_GiftPremium : presentationData.strings.BoostGift_StartGiveaway, badgeCount: badgeCount, isLoading: state.updating, action: { let footerItem = CreateGiveawayFooterItem(theme: presentationData.theme, title: state.mode == .gift ? presentationData.strings.BoostGift_GiftPremium : presentationData.strings.BoostGift_StartGiveaway, badgeCount: badgeCount, isLoading: state.updating, action: {
buyActionImpl?() buyActionImpl?()

View File

@ -303,7 +303,10 @@ class GiftOptionItemNode: ItemListRevealOptionsItemNode {
let (labelLayout, labelApply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: labelAttributedString, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: .greatestFiniteMagnitude))) let (labelLayout, labelApply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: labelAttributedString, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: .greatestFiniteMagnitude)))
let textConstrainedWidth = params.width - leftInset - 8.0 - editingOffset - rightInset - labelLayout.size.width - avatarInset var textConstrainedWidth = params.width - leftInset - 8.0 - editingOffset - rightInset - labelLayout.size.width - avatarInset
if let label = item.label, case .semitransparent = label {
textConstrainedWidth -= 54.0
}
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: textConstrainedWidth, height: .greatestFiniteMagnitude))) let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: textConstrainedWidth, height: .greatestFiniteMagnitude)))
let (statusLayout, statusApply) = makeStatusLayout(TextNodeLayoutArguments(attributedString: statusAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: textConstrainedWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let (statusLayout, statusApply) = makeStatusLayout(TextNodeLayoutArguments(attributedString: statusAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: textConstrainedWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))

View File

@ -10,157 +10,182 @@ import TelegramPresentationData
import Markdown import Markdown
import AlertUI import AlertUI
public func giveawayInfoController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, message: EngineMessage, giveawayInfo: PremiumGiveawayInfo, openLink: @escaping (String) -> Void) -> ViewController? { public func presentGiveawayInfoController(
guard let giveaway = message.media.first(where: { $0 is TelegramMediaGiveaway }) as? TelegramMediaGiveaway else { context: AccountContext,
return nil updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil,
messageId: EngineMessage.Id,
giveawayInfo: PremiumGiveawayInfo,
present: @escaping (ViewController) -> Void,
openLink: @escaping (String) -> Void
) {
var peerIds: [EnginePeer.Id] = [context.account.peerId]
if case let .ongoing(_, status) = giveawayInfo, case let .notAllowed(reason) = status, case let .channelAdmin(adminId) = reason {
peerIds.append(adminId)
} }
let presentationData = context.sharedContext.currentPresentationData.with { $0 } let _ = (context.engine.data.get(
TelegramEngine.EngineData.Item.Messages.Message(id: messageId),
var peerName = "" EngineDataMap(peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init))
if let peerId = giveaway.channelPeerIds.first, let peer = message.peers[peerId] {
peerName = EnginePeer(peer).compactDisplayTitle
}
let untilDate = stringForDate(timestamp: giveaway.untilDate, strings: presentationData.strings)
let title: String
let text: String
var warning: String?
var dismissImpl: (() -> Void)?
var actions: [TextAlertAction] = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
dismissImpl?()
})]
switch giveawayInfo {
case let .ongoing(start, status):
let startDate = stringForDate(timestamp: start, strings: presentationData.strings)
title = presentationData.strings.Chat_Giveaway_Info_Title
let intro: String
if case .almostOver = status {
intro = presentationData.strings.Chat_Giveaway_Info_EndedIntro(peerName, presentationData.strings.Chat_Giveaway_Info_Subscriptions(giveaway.quantity), presentationData.strings.Chat_Giveaway_Info_Months(giveaway.months)).string
} else {
intro = presentationData.strings.Chat_Giveaway_Info_OngoingIntro(peerName, presentationData.strings.Chat_Giveaway_Info_Subscriptions(giveaway.quantity), presentationData.strings.Chat_Giveaway_Info_Months(giveaway.months)).string
}
let ending: String
if giveaway.flags.contains(.onlyNewSubscribers) {
let randomUsers = presentationData.strings.Chat_Giveaway_Info_RandomUsers(giveaway.quantity)
if giveaway.channelPeerIds.count > 1 {
ending = presentationData.strings.Chat_Giveaway_Info_OngoingNewMany(untilDate, randomUsers, peerName, presentationData.strings.Chat_Giveaway_Info_OtherChannels(Int32(giveaway.channelPeerIds.count - 1)), startDate).string
} else {
ending = presentationData.strings.Chat_Giveaway_Info_OngoingNew(untilDate, randomUsers, peerName, startDate).string
}
} else {
let randomSubscribers = presentationData.strings.Chat_Giveaway_Info_RandomSubscribers(giveaway.quantity)
if giveaway.channelPeerIds.count > 1 {
ending = presentationData.strings.Chat_Giveaway_Info_OngoingMany(untilDate, randomSubscribers, peerName, presentationData.strings.Chat_Giveaway_Info_OtherChannels(Int32(giveaway.channelPeerIds.count - 1))).string
} else {
ending = presentationData.strings.Chat_Giveaway_Info_Ongoing(untilDate, randomSubscribers, peerName).string
}
}
var participation: String
switch status {
case .notQualified:
if giveaway.channelPeerIds.count > 1 {
participation = presentationData.strings.Chat_Giveaway_Info_NotQualifiedMany(peerName, presentationData.strings.Chat_Giveaway_Info_OtherChannels(Int32(giveaway.channelPeerIds.count - 1)), untilDate).string
} else {
participation = presentationData.strings.Chat_Giveaway_Info_NotQualified(peerName, untilDate).string
}
case let .notAllowed(reason):
switch reason {
case let .joinedTooEarly(joinedOn):
let joinDate = stringForDate(timestamp: joinedOn, strings: presentationData.strings)
participation = presentationData.strings.Chat_Giveaway_Info_NotAllowedJoinedEarly(joinDate).string
case let .channelAdmin(adminId):
let _ = adminId
participation = presentationData.strings.Chat_Giveaway_Info_NotAllowedAdmin(peerName).string
case .disallowedCountry:
participation = presentationData.strings.Chat_Giveaway_Info_NotAllowedCountry
}
case .participating:
if giveaway.channelPeerIds.count > 1 {
participation = presentationData.strings.Chat_Giveaway_Info_ParticipatingMany(peerName, presentationData.strings.Chat_Giveaway_Info_OtherChannels(Int32(giveaway.channelPeerIds.count - 1))).string
} else {
participation = presentationData.strings.Chat_Giveaway_Info_Participating(peerName).string
}
case .almostOver:
participation = presentationData.strings.Chat_Giveaway_Info_AlmostOver
}
if !participation.isEmpty {
participation = "\n\n\(participation)"
}
text = "\(intro)\n\n\(ending)\(participation)"
case let .finished(status, start, finish, _, activatedCount):
let startDate = stringForDate(timestamp: start, strings: presentationData.strings)
let finishDate = stringForDate(timestamp: finish, strings: presentationData.strings)
title = presentationData.strings.Chat_Giveaway_Info_EndedTitle
let intro = presentationData.strings.Chat_Giveaway_Info_EndedIntro(peerName, presentationData.strings.Chat_Giveaway_Info_Subscriptions(giveaway.quantity), presentationData.strings.Chat_Giveaway_Info_Months(giveaway.months)).string
var ending: String
if giveaway.flags.contains(.onlyNewSubscribers) {
let randomUsers = presentationData.strings.Chat_Giveaway_Info_RandomUsers(giveaway.quantity)
if giveaway.channelPeerIds.count > 1 {
ending = presentationData.strings.Chat_Giveaway_Info_EndedNewMany(finishDate, randomUsers, peerName, startDate).string
} else {
ending = presentationData.strings.Chat_Giveaway_Info_EndedNew(finishDate, randomUsers, peerName, startDate).string
}
} else {
let randomSubscribers = presentationData.strings.Chat_Giveaway_Info_RandomSubscribers(giveaway.quantity)
if giveaway.channelPeerIds.count > 1 {
ending = presentationData.strings.Chat_Giveaway_Info_EndedMany(finishDate, randomSubscribers, peerName).string
} else {
ending = presentationData.strings.Chat_Giveaway_Info_Ended(finishDate, randomSubscribers, peerName).string
}
}
if activatedCount > 0 {
ending += " " + presentationData.strings.Chat_Giveaway_Info_ActivatedLinks(activatedCount)
}
var result: String
switch status {
case .refunded:
result = ""
warning = presentationData.strings.Chat_Giveaway_Info_Refunded
actions = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Close, action: {
dismissImpl?()
})]
case .notWon:
result = "\n\n" + presentationData.strings.Chat_Giveaway_Info_DidntWin
case let .won(slug):
result = "\n\n" + presentationData.strings.Chat_Giveaway_Info_Won("🏆").string
actions = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Chat_Giveaway_Info_ViewPrize, action: {
dismissImpl?()
openLink(slug)
}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
dismissImpl?()
})]
}
text = "\(intro)\n\n\(ending)\(result)"
}
let alertController = giveawayInfoAlertController(
context: context,
updatedPresentationData: updatedPresentationData,
title: title,
text: text,
warning: warning,
actions: actions
) )
dismissImpl = { [weak alertController] in |> deliverOnMainQueue).startStandalone(next: { message, peerMap in
alertController?.dismissAnimated() guard let message else {
} return
return alertController }
guard let giveaway = message.media.first(where: { $0 is TelegramMediaGiveaway }) as? TelegramMediaGiveaway else {
return
}
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
var peerName = ""
if let peerId = giveaway.channelPeerIds.first, let peer = message.peers[peerId] {
peerName = EnginePeer(peer).compactDisplayTitle
}
let timeZone = TimeZone.current
let untilDate = stringForDate(timestamp: giveaway.untilDate, timeZone: timeZone, strings: presentationData.strings)
let title: String
let text: String
var warning: String?
var dismissImpl: (() -> Void)?
var actions: [TextAlertAction] = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
dismissImpl?()
})]
switch giveawayInfo {
case let .ongoing(start, status):
let startDate = stringForDate(timestamp: start, timeZone: timeZone, strings: presentationData.strings)
title = presentationData.strings.Chat_Giveaway_Info_Title
let intro: String
if case .almostOver = status {
intro = presentationData.strings.Chat_Giveaway_Info_EndedIntro(peerName, presentationData.strings.Chat_Giveaway_Info_Subscriptions(giveaway.quantity), presentationData.strings.Chat_Giveaway_Info_Months(giveaway.months)).string
} else {
intro = presentationData.strings.Chat_Giveaway_Info_OngoingIntro(peerName, presentationData.strings.Chat_Giveaway_Info_Subscriptions(giveaway.quantity), presentationData.strings.Chat_Giveaway_Info_Months(giveaway.months)).string
}
let ending: String
if giveaway.flags.contains(.onlyNewSubscribers) {
let randomUsers = presentationData.strings.Chat_Giveaway_Info_RandomUsers(giveaway.quantity)
if giveaway.channelPeerIds.count > 1 {
ending = presentationData.strings.Chat_Giveaway_Info_OngoingNewMany(untilDate, randomUsers, peerName, presentationData.strings.Chat_Giveaway_Info_OtherChannels(Int32(giveaway.channelPeerIds.count - 1)), startDate).string
} else {
ending = presentationData.strings.Chat_Giveaway_Info_OngoingNew(untilDate, randomUsers, peerName, startDate).string
}
} else {
let randomSubscribers = presentationData.strings.Chat_Giveaway_Info_RandomSubscribers(giveaway.quantity)
if giveaway.channelPeerIds.count > 1 {
ending = presentationData.strings.Chat_Giveaway_Info_OngoingMany(untilDate, randomSubscribers, peerName, presentationData.strings.Chat_Giveaway_Info_OtherChannels(Int32(giveaway.channelPeerIds.count - 1))).string
} else {
ending = presentationData.strings.Chat_Giveaway_Info_Ongoing(untilDate, randomSubscribers, peerName).string
}
}
var participation: String
switch status {
case .notQualified:
if giveaway.channelPeerIds.count > 1 {
participation = presentationData.strings.Chat_Giveaway_Info_NotQualifiedMany(peerName, presentationData.strings.Chat_Giveaway_Info_OtherChannels(Int32(giveaway.channelPeerIds.count - 1)), untilDate).string
} else {
participation = presentationData.strings.Chat_Giveaway_Info_NotQualified(peerName, untilDate).string
}
case let .notAllowed(reason):
switch reason {
case let .joinedTooEarly(joinedOn):
let joinDate = stringForDate(timestamp: joinedOn, strings: presentationData.strings)
participation = presentationData.strings.Chat_Giveaway_Info_NotAllowedJoinedEarly(joinDate).string
case let .channelAdmin(adminId):
var channelName = peerName
if let maybePeer = peerMap[adminId], let peer = maybePeer {
channelName = peer.compactDisplayTitle
}
participation = presentationData.strings.Chat_Giveaway_Info_NotAllowedAdmin(channelName).string
case .disallowedCountry:
participation = presentationData.strings.Chat_Giveaway_Info_NotAllowedCountry
}
case .participating:
if giveaway.channelPeerIds.count > 1 {
participation = presentationData.strings.Chat_Giveaway_Info_ParticipatingMany(peerName, presentationData.strings.Chat_Giveaway_Info_OtherChannels(Int32(giveaway.channelPeerIds.count - 1))).string
} else {
participation = presentationData.strings.Chat_Giveaway_Info_Participating(peerName).string
}
case .almostOver:
participation = presentationData.strings.Chat_Giveaway_Info_AlmostOver
}
if !participation.isEmpty {
participation = "\n\n\(participation)"
}
text = "\(intro)\n\n\(ending)\(participation)"
case let .finished(status, start, finish, _, activatedCount):
let startDate = stringForDate(timestamp: start, timeZone: timeZone, strings: presentationData.strings)
let finishDate = stringForDate(timestamp: finish, timeZone: timeZone, strings: presentationData.strings)
title = presentationData.strings.Chat_Giveaway_Info_EndedTitle
let intro = presentationData.strings.Chat_Giveaway_Info_EndedIntro(peerName, presentationData.strings.Chat_Giveaway_Info_Subscriptions(giveaway.quantity), presentationData.strings.Chat_Giveaway_Info_Months(giveaway.months)).string
var ending: String
if giveaway.flags.contains(.onlyNewSubscribers) {
let randomUsers = presentationData.strings.Chat_Giveaway_Info_RandomUsers(giveaway.quantity)
if giveaway.channelPeerIds.count > 1 {
ending = presentationData.strings.Chat_Giveaway_Info_EndedNewMany(finishDate, randomUsers, peerName, startDate).string
} else {
ending = presentationData.strings.Chat_Giveaway_Info_EndedNew(finishDate, randomUsers, peerName, startDate).string
}
} else {
let randomSubscribers = presentationData.strings.Chat_Giveaway_Info_RandomSubscribers(giveaway.quantity)
if giveaway.channelPeerIds.count > 1 {
ending = presentationData.strings.Chat_Giveaway_Info_EndedMany(finishDate, randomSubscribers, peerName).string
} else {
ending = presentationData.strings.Chat_Giveaway_Info_Ended(finishDate, randomSubscribers, peerName).string
}
}
if activatedCount > 0 {
ending += " " + presentationData.strings.Chat_Giveaway_Info_ActivatedLinks(activatedCount)
}
var result: String
switch status {
case .refunded:
result = ""
warning = presentationData.strings.Chat_Giveaway_Info_Refunded
actions = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Close, action: {
dismissImpl?()
})]
case .notWon:
result = "\n\n" + presentationData.strings.Chat_Giveaway_Info_DidntWin
case let .won(slug):
result = "\n\n" + presentationData.strings.Chat_Giveaway_Info_Won("🏆").string
actions = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Chat_Giveaway_Info_ViewPrize, action: {
dismissImpl?()
openLink(slug)
}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
dismissImpl?()
})]
}
text = "\(intro)\n\n\(ending)\(result)"
}
let alertController = giveawayInfoAlertController(
context: context,
updatedPresentationData: updatedPresentationData,
title: title,
text: text,
warning: warning,
actions: actions
)
dismissImpl = { [weak alertController] in
alertController?.dismissAnimated()
}
present(alertController)
})
} }
private final class GiveawayInfoAlertContentNode: AlertContentNode { private final class GiveawayInfoAlertContentNode: AlertContentNode {

View File

@ -666,6 +666,7 @@ private final class DemoSheetContent: CombinedComponent {
let background = Child(GradientBackgroundComponent.self) let background = Child(GradientBackgroundComponent.self)
let pager = Child(DemoPagerComponent.self) let pager = Child(DemoPagerComponent.self)
let button = Child(SolidRoundedButtonComponent.self) let button = Child(SolidRoundedButtonComponent.self)
let measureText = Child(MultilineTextComponent.self)
return { context in return { context in
let environment = context.environment[ViewControllerComponentContainer.Environment.self].value let environment = context.environment[ViewControllerComponentContainer.Environment.self].value
@ -1003,44 +1004,108 @@ private final class DemoSheetContent: CombinedComponent {
.cornerRadius(15.0) .cornerRadius(15.0)
) )
var measuredTextHeight: CGFloat?
let buttonText: String let buttonText: String
var buttonAnimationName: String? var buttonAnimationName: String?
if state.isPremium == true { if state.isPremium == true {
buttonText = strings.Common_OK buttonText = strings.Common_OK
} else { } else {
switch component.source { switch component.source {
case let .intro(price): case let .intro(price):
buttonText = strings.Premium_SubscribeFor(price ?? "").string buttonText = strings.Premium_SubscribeFor(price ?? "").string
case let .gift(price): case let .gift(price):
buttonText = strings.Premium_Gift_GiftSubscription(price ?? "").string buttonText = strings.Premium_Gift_GiftSubscription(price ?? "").string
case .other: case .other:
switch component.subject { var text: String
case .fasterDownload: switch component.subject {
buttonText = strings.Premium_FasterSpeed_Proceed case .fasterDownload:
case .advancedChatManagement: buttonText = strings.Premium_FasterSpeed_Proceed
buttonText = strings.Premium_ChatManagement_Proceed case .advancedChatManagement:
case .uniqueReactions: buttonText = strings.Premium_ChatManagement_Proceed
buttonText = strings.Premium_Reactions_Proceed case .uniqueReactions:
buttonAnimationName = "premium_unlock" buttonText = strings.Premium_Reactions_Proceed
case .premiumStickers: buttonAnimationName = "premium_unlock"
buttonText = strings.Premium_Stickers_Proceed case .premiumStickers:
buttonAnimationName = "premium_unlock" buttonText = strings.Premium_Stickers_Proceed
case .appIcons: buttonAnimationName = "premium_unlock"
buttonText = strings.Premium_AppIcons_Proceed case .appIcons:
buttonAnimationName = "premium_unlock" buttonText = strings.Premium_AppIcons_Proceed
case .noAds: buttonAnimationName = "premium_unlock"
buttonText = strings.Premium_NoAds_Proceed case .noAds:
case .animatedEmoji: buttonText = strings.Premium_NoAds_Proceed
buttonText = strings.Premium_AnimatedEmoji_Proceed case .animatedEmoji:
buttonAnimationName = "premium_unlock" buttonText = strings.Premium_AnimatedEmoji_Proceed
case .translation: buttonAnimationName = "premium_unlock"
buttonText = strings.Premium_Translation_Proceed case .translation:
case .stories: buttonText = strings.Premium_Translation_Proceed
buttonText = strings.Common_OK case .stories:
buttonAnimationName = "premium_unlock" buttonText = strings.Common_OK
default: buttonAnimationName = "premium_unlock"
buttonText = strings.Common_OK default:
buttonText = strings.Common_OK
}
switch component.subject {
case .moreUpload:
text = strings.Premium_UploadSizeInfo
case .fasterDownload:
text = strings.Premium_FasterSpeedStandaloneInfo
case .voiceToText:
text = strings.Premium_VoiceToTextStandaloneInfo
case .noAds:
text = strings.Premium_NoAdsStandaloneInfo
case .uniqueReactions:
text = strings.Premium_InfiniteReactionsInfo
case .premiumStickers:
text = strings.Premium_StickersInfo
case .emojiStatus:
text = strings.Premium_EmojiStatusInfo
case .advancedChatManagement:
text = strings.Premium_ChatManagementStandaloneInfo
case .profileBadge:
text = strings.Premium_BadgeInfo
case .animatedUserpics:
text = strings.Premium_AvatarInfo
case .appIcons:
text = strings.Premium_AppIconStandaloneInfo
case .animatedEmoji:
text = strings.Premium_AnimatedEmojiStandaloneInfo
case .translation:
text = strings.Premium_TranslationStandaloneInfo
case .doubleLimits:
text = ""
case .stories:
text = ""
}
let textSideInset: CGFloat = 24.0
let textColor = UIColor.black
let textFont = Font.regular(17.0)
let boldTextFont = Font.semibold(17.0)
let markdownAttributes = MarkdownAttributes(
body: MarkdownAttributeSet(font: textFont, textColor: textColor),
bold: MarkdownAttributeSet(font: boldTextFont, textColor: textColor),
link: MarkdownAttributeSet(font: textFont, textColor: textColor),
linkAttribute: { _ in
return nil
} }
)
let measureText = measureText.update(
component: MultilineTextComponent(
text: .markdown(text: text, attributes: markdownAttributes),
horizontalAlignment: .center,
maximumNumberOfLines: 0,
lineSpacing: 0.0
),
availableSize: CGSize(width: context.availableSize.width - textSideInset * 2.0, height: context.availableSize.height),
transition: .immediate
)
context.add(measureText
.position(CGPoint(x: 0.0, y: 1000.0))
)
measuredTextHeight = measureText.size.height
} }
} }
@ -1079,12 +1144,17 @@ private final class DemoSheetContent: CombinedComponent {
transition: context.transition transition: context.transition
) )
var contentHeight: CGFloat = context.availableSize.width + 146.0 var contentHeight: CGFloat = context.availableSize.width
if case .other = component.source { if let measuredTextHeight {
contentHeight -= 40.0 contentHeight += measuredTextHeight + 66.0
} else {
contentHeight += 146.0
if case .other = component.source {
contentHeight -= 40.0
if [.advancedChatManagement, .fasterDownload].contains(component.subject) { if [.advancedChatManagement, .fasterDownload].contains(component.subject) {
contentHeight += 20.0 contentHeight += 20.0
}
} }
} }
@ -1166,6 +1236,7 @@ private final class DemoSheetComponent: CombinedComponent {
} }
)), )),
backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor), backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor),
followContentSizeChanges: context.component.source == .other,
animateOut: animateOut animateOut: animateOut
), ),
environment: { environment: {

View File

@ -817,7 +817,7 @@ public class PremiumLimitsListScreen: ViewController {
additionalInset = 20.0 additionalInset = 20.0
} }
return layout.size.height - layout.size.width - 178.0 - panelHeight + additionalInset return layout.size.height - layout.size.width - 181.0 - panelHeight + additionalInset
} else { } else {
return 210.0 return 210.0
} }

View File

@ -1077,7 +1077,7 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
} }
controller.visibleBottomContentOffsetChanged = { offset in controller.visibleBottomContentOffsetChanged = { offset in
let state = stateValue.with { $0 } let state = stateValue.with { $0 }
if case let .known(value) = offset, value < 100.0, case .boosts = state.section, state.boostersExpanded { if case let .known(value) = offset, value < 510.0, case .boosts = state.section, state.boostersExpanded {
boostsContext.loadMore() boostsContext.loadMore()
} }
} }

View File

@ -117,11 +117,11 @@ public func stringForFullDate(timestamp: Int32, strings: PresentationStrings, da
return monthFormat(dayString, yearString, timeString).string return monthFormat(dayString, yearString, timeString).string
} }
public func stringForDate(timestamp: Int32, strings: PresentationStrings) -> String { public func stringForDate(timestamp: Int32, timeZone: TimeZone? = TimeZone(secondsFromGMT: 0), strings: PresentationStrings) -> String {
let formatter = DateFormatter() let formatter = DateFormatter()
formatter.timeStyle = .none formatter.timeStyle = .none
formatter.dateStyle = .medium formatter.dateStyle = .medium
formatter.timeZone = TimeZone(secondsFromGMT: 0) formatter.timeZone = timeZone
formatter.locale = localeWithStrings(strings) formatter.locale = localeWithStrings(strings)
return formatter.string(from: Date(timeIntervalSince1970: Double(timestamp))) return formatter.string(from: Date(timeIntervalSince1970: Double(timestamp)))
} }

View File

@ -184,6 +184,7 @@ private struct PeerNameColorScreenState: Equatable {
var updatedNameColor: PeerNameColor? var updatedNameColor: PeerNameColor?
var updatedBackgroundEmojiId: Int64? var updatedBackgroundEmojiId: Int64?
var inProgress: Bool = false var inProgress: Bool = false
var needsBoosts: Bool = false
} }
private func peerNameColorScreenEntries( private func peerNameColorScreenEntries(
@ -253,7 +254,11 @@ private func peerNameColorScreenEntries(
colors: nameColors, colors: nameColors,
currentColor: nameColor currentColor: nameColor
)) ))
entries.append(.colorDescription(presentationData.strings.NameColor_ChatPreview_Description_Account)) if case .channel = peer {
entries.append(.colorDescription(presentationData.strings.NameColor_ChatPreview_Description_Channel))
} else {
entries.append(.colorDescription(presentationData.strings.NameColor_ChatPreview_Description_Account))
}
if let emojiContent { if let emojiContent {
entries.append(.backgroundEmojiHeader(presentationData.strings.NameColor_BackgroundEmoji_Title, backgroundEmojiId != nil ? presentationData.strings.NameColor_BackgroundEmoji_Remove : nil)) entries.append(.backgroundEmojiHeader(presentationData.strings.NameColor_BackgroundEmoji_Title, backgroundEmojiId != nil ? presentationData.strings.NameColor_BackgroundEmoji_Remove : nil))
@ -530,6 +535,7 @@ public func PeerNameColorScreen(
} }
let controller = ItemListController(context: context, state: signal) let controller = ItemListController(context: context, state: signal)
controller.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
presentImpl = { [weak controller] c in presentImpl = { [weak controller] c in
guard let controller else { guard let controller else {
return return
@ -561,6 +567,10 @@ public func PeerNameColorScreen(
return true return true
} }
let state = stateValue.with({ $0 }) let state = stateValue.with({ $0 })
if case .channel = subject, state.needsBoosts {
f()
return true
}
var hasChanges = false var hasChanges = false
if state.updatedNameColor != nil || state.updatedBackgroundEmojiId != nil { if state.updatedNameColor != nil || state.updatedBackgroundEmojiId != nil {
hasChanges = true hasChanges = true
@ -624,6 +634,12 @@ public func PeerNameColorScreen(
|> deliverOnMainQueue).startStandalone(next: { |> deliverOnMainQueue).startStandalone(next: {
}, error: { error in }, error: { error in
if case .channelBoostRequired = error { if case .channelBoostRequired = error {
updateState { state in
var updatedState = state
updatedState.needsBoosts = true
return updatedState
}
let _ = combineLatest( let _ = combineLatest(
queue: Queue.mainQueue(), queue: Queue.mainQueue(),
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)), context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)),

View File

@ -19177,19 +19177,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
func displayGiveawayStatusInfo(messageId: EngineMessage.Id, giveawayInfo: PremiumGiveawayInfo) { func displayGiveawayStatusInfo(messageId: EngineMessage.Id, giveawayInfo: PremiumGiveawayInfo) {
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Messages.Message(id: messageId)) presentGiveawayInfoController(context: self.context, updatedPresentationData: self.updatedPresentationData, messageId: messageId, giveawayInfo: giveawayInfo, present: { [weak self] c in
|> deliverOnMainQueue).startStandalone(next: { [weak self] message in guard let self else {
guard let self, let message else {
return return
} }
if let controller = giveawayInfoController(context: self.context, updatedPresentationData: self.updatedPresentationData, message: message, giveawayInfo: giveawayInfo, openLink: { [weak self] slug in self.present(c, in: .window(.root))
guard let self else { }, openLink: { [weak self] slug in
return guard let self else {
} return
self.openResolved(result: .premiumGiftCode(slug: slug), sourceMessageId: messageId)
}) {
self.present(controller, in: .window(.root))
} }
self.openResolved(result: .premiumGiftCode(slug: slug), sourceMessageId: messageId)
}) })
} }
} }

View File

@ -913,6 +913,9 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
openPeer: { peer in openPeer: { peer in
if peer.id != context.account.peerId { if peer.id != context.account.peerId {
openPeer(peer, .chat(textInputState: nil, subject: nil, peekData: nil)) openPeer(peer, .chat(textInputState: nil, subject: nil, peekData: nil))
if case let .chat(peerId, _) = urlContext, peerId == peer.id {
dismissImpl?()
}
} }
}, },
openMessage: { messageId in openMessage: { messageId in
@ -922,6 +925,9 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
return return
} }
openPeer(peer, .chat(textInputState: nil, subject: .message(id: .id(messageId), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: nil), peekData: nil)) openPeer(peer, .chat(textInputState: nil, subject: .message(id: .id(messageId), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: nil), peekData: nil))
if case let .chat(peerId, _) = urlContext, peerId == messageId.peerId {
dismissImpl?()
}
}) })
}, },
shareLink: { link in shareLink: { link in

View File

@ -1,5 +1,5 @@
{ {
"app": "10.2.1", "app": "10.2.2",
"bazel": "6.4.0", "bazel": "6.4.0",
"xcode": "15.0" "xcode": "15.0"
} }