diff --git a/submodules/PremiumUI/Sources/CreateGiveawayController.swift b/submodules/PremiumUI/Sources/CreateGiveawayController.swift index 817742e941..0d9932c675 100644 --- a/submodules/PremiumUI/Sources/CreateGiveawayController.swift +++ b/submodules/PremiumUI/Sources/CreateGiveawayController.swift @@ -791,9 +791,9 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio let badgeCount: Int32 switch state.mode { case .giveaway: - badgeCount = state.subscriptions + badgeCount = state.subscriptions * 4 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: { buyActionImpl?() diff --git a/submodules/PremiumUI/Sources/GiftOptionItem.swift b/submodules/PremiumUI/Sources/GiftOptionItem.swift index 5fefc71ad6..239293955a 100644 --- a/submodules/PremiumUI/Sources/GiftOptionItem.swift +++ b/submodules/PremiumUI/Sources/GiftOptionItem.swift @@ -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 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 (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())) diff --git a/submodules/PremiumUI/Sources/GiveawayInfoController.swift b/submodules/PremiumUI/Sources/GiveawayInfoController.swift index 7719ac3f2e..981c4a7ada 100644 --- a/submodules/PremiumUI/Sources/GiveawayInfoController.swift +++ b/submodules/PremiumUI/Sources/GiveawayInfoController.swift @@ -10,157 +10,182 @@ import TelegramPresentationData import Markdown import AlertUI -public func giveawayInfoController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, message: EngineMessage, giveawayInfo: PremiumGiveawayInfo, openLink: @escaping (String) -> Void) -> ViewController? { - guard let giveaway = message.media.first(where: { $0 is TelegramMediaGiveaway }) as? TelegramMediaGiveaway else { - return nil +public func presentGiveawayInfoController( + context: AccountContext, + updatedPresentationData: (initial: PresentationData, signal: Signal)? = 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 } - - var peerName = "" - 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 + let _ = (context.engine.data.get( + TelegramEngine.EngineData.Item.Messages.Message(id: messageId), + EngineDataMap(peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init)) ) - dismissImpl = { [weak alertController] in - alertController?.dismissAnimated() - } - return alertController + |> deliverOnMainQueue).startStandalone(next: { message, peerMap in + guard let message else { + return + } + 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 { diff --git a/submodules/StatisticsUI/Sources/ChannelStatsController.swift b/submodules/StatisticsUI/Sources/ChannelStatsController.swift index 6a93e6f1b1..9e9d0a2068 100644 --- a/submodules/StatisticsUI/Sources/ChannelStatsController.swift +++ b/submodules/StatisticsUI/Sources/ChannelStatsController.swift @@ -1077,7 +1077,7 @@ public func channelStatsController(context: AccountContext, updatedPresentationD } controller.visibleBottomContentOffsetChanged = { offset in 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() } } diff --git a/submodules/TelegramStringFormatting/Sources/DateFormat.swift b/submodules/TelegramStringFormatting/Sources/DateFormat.swift index 759d3811ec..ac65710077 100644 --- a/submodules/TelegramStringFormatting/Sources/DateFormat.swift +++ b/submodules/TelegramStringFormatting/Sources/DateFormat.swift @@ -117,11 +117,11 @@ public func stringForFullDate(timestamp: Int32, strings: PresentationStrings, da 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() formatter.timeStyle = .none formatter.dateStyle = .medium - formatter.timeZone = TimeZone(secondsFromGMT: 0) + formatter.timeZone = timeZone formatter.locale = localeWithStrings(strings) return formatter.string(from: Date(timeIntervalSince1970: Double(timestamp))) } diff --git a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorScreen.swift b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorScreen.swift index a117df7ef5..0b82acb69c 100644 --- a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorScreen.swift +++ b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorScreen.swift @@ -535,6 +535,7 @@ public func PeerNameColorScreen( } let controller = ItemListController(context: context, state: signal) + controller.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait) presentImpl = { [weak controller] c in guard let controller else { return diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index cc4e08bd62..70bec1f7b7 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -19177,19 +19177,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } func displayGiveawayStatusInfo(messageId: EngineMessage.Id, giveawayInfo: PremiumGiveawayInfo) { - let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Messages.Message(id: messageId)) - |> deliverOnMainQueue).startStandalone(next: { [weak self] message in - guard let self, let message else { + presentGiveawayInfoController(context: self.context, updatedPresentationData: self.updatedPresentationData, messageId: messageId, giveawayInfo: giveawayInfo, present: { [weak self] c in + guard let self else { return } - if let controller = giveawayInfoController(context: self.context, updatedPresentationData: self.updatedPresentationData, message: message, giveawayInfo: giveawayInfo, openLink: { [weak self] slug in - guard let self else { - return - } - self.openResolved(result: .premiumGiftCode(slug: slug), sourceMessageId: messageId) - }) { - self.present(controller, in: .window(.root)) + self.present(c, in: .window(.root)) + }, openLink: { [weak self] slug in + guard let self else { + return } + self.openResolved(result: .premiumGiftCode(slug: slug), sourceMessageId: messageId) }) } } diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index 5c9c0df71b..c80636df48 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -913,6 +913,9 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur openPeer: { peer in if peer.id != context.account.peerId { openPeer(peer, .chat(textInputState: nil, subject: nil, peekData: nil)) + if case let .chat(peerId, _) = urlContext, peerId == peer.id { + dismissImpl?() + } } }, openMessage: { messageId in @@ -922,6 +925,9 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur return } 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