mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 01:10:09 +00:00
Merge branch 'beta'
# Conflicts: # Telegram/Telegram-iOS/en.lproj/Localizable.strings
This commit is contained in:
commit
46e71cd7c7
3
.gitignore
vendored
3
.gitignore
vendored
@ -69,4 +69,5 @@ submodules/OpusBinding/SharedHeaders/*
|
|||||||
submodules/FFMpegBinding/SharedHeaders/*
|
submodules/FFMpegBinding/SharedHeaders/*
|
||||||
submodules/OpenSSLEncryptionProvider/SharedHeaders/*
|
submodules/OpenSSLEncryptionProvider/SharedHeaders/*
|
||||||
submodules/TelegramCore/FlatSerialization/Sources/*
|
submodules/TelegramCore/FlatSerialization/Sources/*
|
||||||
buildServer.json
|
buildServer.json
|
||||||
|
.build/**
|
||||||
|
|||||||
@ -13949,6 +13949,7 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"Stars.Intro.BuyShort" = "Top Up";
|
"Stars.Intro.BuyShort" = "Top Up";
|
||||||
"Stars.Intro.Withdraw" = "Withdraw";
|
"Stars.Intro.Withdraw" = "Withdraw";
|
||||||
|
"Stars.Intro.Stats" = "Stats";
|
||||||
|
|
||||||
"Group.Info.Settings" = "Group Settings";
|
"Group.Info.Settings" = "Group Settings";
|
||||||
|
|
||||||
@ -14014,3 +14015,6 @@ Sorry for the inconvenience.";
|
|||||||
"Premium.MaxExpiringStoriesFinalTextNumberFormat_1" = "**%d** story";
|
"Premium.MaxExpiringStoriesFinalTextNumberFormat_1" = "**%d** story";
|
||||||
"Premium.MaxExpiringStoriesFinalTextNumberFormat_any" = "**%d** stories";
|
"Premium.MaxExpiringStoriesFinalTextNumberFormat_any" = "**%d** stories";
|
||||||
"Premium.MaxExpiringStoriesFinalTextFormat" = "You have reached the limit of %@ stories per **24** hours.";
|
"Premium.MaxExpiringStoriesFinalTextFormat" = "You have reached the limit of %@ stories per **24** hours.";
|
||||||
|
|
||||||
|
"Stars.AccountRevenue.Proceeds.Info" = "Stars from your total balance can be withdrawn as rewards 21 days after they are earned.";
|
||||||
|
"Stars.AccountRevenue.Withdraw.Info" = "You can collect rewards for Stars using Fragment. You cannot withdraw less than 1000 stars. [Learn More >]()";
|
||||||
|
|||||||
@ -48,6 +48,7 @@ public enum ContactMultiselectionControllerMode {
|
|||||||
public var onlyUsers: Bool
|
public var onlyUsers: Bool
|
||||||
public var disableChannels: Bool
|
public var disableChannels: Bool
|
||||||
public var disableBots: Bool
|
public var disableBots: Bool
|
||||||
|
public var disableContacts: Bool
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
title: String,
|
title: String,
|
||||||
@ -59,7 +60,8 @@ public enum ContactMultiselectionControllerMode {
|
|||||||
displayPresence: Bool = false,
|
displayPresence: Bool = false,
|
||||||
onlyUsers: Bool = false,
|
onlyUsers: Bool = false,
|
||||||
disableChannels: Bool = false,
|
disableChannels: Bool = false,
|
||||||
disableBots: Bool = false
|
disableBots: Bool = false,
|
||||||
|
disableContacts: Bool = false
|
||||||
) {
|
) {
|
||||||
self.title = title
|
self.title = title
|
||||||
self.searchPlaceholder = searchPlaceholder
|
self.searchPlaceholder = searchPlaceholder
|
||||||
@ -71,6 +73,7 @@ public enum ContactMultiselectionControllerMode {
|
|||||||
self.onlyUsers = onlyUsers
|
self.onlyUsers = onlyUsers
|
||||||
self.disableChannels = disableChannels
|
self.disableChannels = disableChannels
|
||||||
self.disableBots = disableBots
|
self.disableBots = disableBots
|
||||||
|
self.disableContacts = disableContacts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -351,7 +351,7 @@ public final class AuthorizationSequenceController: NavigationController, ASAuth
|
|||||||
|> deliverOnMainQueue).startStrict(error: { [weak self] error in
|
|> deliverOnMainQueue).startStrict(error: { [weak self] error in
|
||||||
if let self, case .alreadyInProgress = error {
|
if let self, case .alreadyInProgress = error {
|
||||||
let formattedNumber = formatPhoneNumber(number)
|
let formattedNumber = formatPhoneNumber(number)
|
||||||
let title = NSAttributedString(string: self.presentationData.strings.Login_Email_PremiumRequiredTitle, font: Font.semibold(self.presentationData.listsFontSize.baseDisplaySize), textColor: self.presentationData.theme.actionSheet.primaryTextColor)
|
let title = NSAttributedString(string: self.presentationData.strings.Login_Email_PremiumRequiredTitle, font: Font.semibold(self.presentationData.listsFontSize.baseDisplaySize), textColor: self.presentationData.theme.actionSheet.primaryTextColor, paragraphAlignment: .center)
|
||||||
let text = parseMarkdownIntoAttributedString(self.presentationData.strings.Login_Email_PremiumRequiredText(formattedNumber).string, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in nil }), textAlignment: .center).mutableCopy() as! NSMutableAttributedString
|
let text = parseMarkdownIntoAttributedString(self.presentationData.strings.Login_Email_PremiumRequiredText(formattedNumber).string, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in nil }), textAlignment: .center).mutableCopy() as! NSMutableAttributedString
|
||||||
|
|
||||||
let alertController = textWithEntitiesAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: title, text: text, actions: [TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_OK, action: { })])
|
let alertController = textWithEntitiesAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: title, text: text, actions: [TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_OK, action: { })])
|
||||||
|
|||||||
@ -1722,10 +1722,10 @@ function tgBrowserHandleMutations(mutations) {
|
|||||||
if (mutation.addedNodes && mutation.addedNodes.length > 0) {
|
if (mutation.addedNodes && mutation.addedNodes.length > 0) {
|
||||||
mutation.addedNodes.forEach((newNode) => {
|
mutation.addedNodes.forEach((newNode) => {
|
||||||
if (newNode.tagName === 'VIDEO') {
|
if (newNode.tagName === 'VIDEO') {
|
||||||
disableWebkitEnterFullscreen(newNode);
|
tgBrowserDisableWebkitEnterFullscreen(newNode);
|
||||||
}
|
}
|
||||||
if (newNode.querySelectorAll) {
|
if (newNode.querySelectorAll) {
|
||||||
newNode.querySelectorAll('video').forEach(disableWebkitEnterFullscreen);
|
newNode.querySelectorAll('video').forEach(tgBrowserDisableWebkitEnterFullscreen);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,10 +37,10 @@ private final class ChannelPermissionsControllerArguments {
|
|||||||
let openChannelExample: () -> Void
|
let openChannelExample: () -> Void
|
||||||
let updateSlowmode: (Int32) -> Void
|
let updateSlowmode: (Int32) -> Void
|
||||||
let updateUnrestrictBoosters: (Int32) -> Void
|
let updateUnrestrictBoosters: (Int32) -> Void
|
||||||
let updateStarsAmount: (StarsAmount?) -> Void
|
let updateStarsAmount: (StarsAmount?, Bool) -> Void
|
||||||
let toggleIsOptionExpanded: (TelegramChatBannedRightsFlags) -> Void
|
let toggleIsOptionExpanded: (TelegramChatBannedRightsFlags) -> Void
|
||||||
|
|
||||||
init(context: AccountContext, updatePermission: @escaping (TelegramChatBannedRightsFlags, Bool) -> Void, setPeerIdWithRevealedOptions: @escaping (EnginePeer.Id?, EnginePeer.Id?) -> Void, addPeer: @escaping () -> Void, removePeer: @escaping (EnginePeer.Id) -> Void, openPeer: @escaping (ChannelParticipant) -> Void, openPeerInfo: @escaping (EnginePeer) -> Void, openKicked: @escaping () -> Void, presentRestrictedPermissionAlert: @escaping (TelegramChatBannedRightsFlags) -> Void, presentConversionToBroadcastGroup: @escaping () -> Void, openChannelExample: @escaping () -> Void, updateSlowmode: @escaping (Int32) -> Void, updateUnrestrictBoosters: @escaping (Int32) -> Void, updateStarsAmount: @escaping (StarsAmount?) -> Void, toggleIsOptionExpanded: @escaping (TelegramChatBannedRightsFlags) -> Void) {
|
init(context: AccountContext, updatePermission: @escaping (TelegramChatBannedRightsFlags, Bool) -> Void, setPeerIdWithRevealedOptions: @escaping (EnginePeer.Id?, EnginePeer.Id?) -> Void, addPeer: @escaping () -> Void, removePeer: @escaping (EnginePeer.Id) -> Void, openPeer: @escaping (ChannelParticipant) -> Void, openPeerInfo: @escaping (EnginePeer) -> Void, openKicked: @escaping () -> Void, presentRestrictedPermissionAlert: @escaping (TelegramChatBannedRightsFlags) -> Void, presentConversionToBroadcastGroup: @escaping () -> Void, openChannelExample: @escaping () -> Void, updateSlowmode: @escaping (Int32) -> Void, updateUnrestrictBoosters: @escaping (Int32) -> Void, updateStarsAmount: @escaping (StarsAmount?, Bool) -> Void, toggleIsOptionExpanded: @escaping (TelegramChatBannedRightsFlags) -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.updatePermission = updatePermission
|
self.updatePermission = updatePermission
|
||||||
self.addPeer = addPeer
|
self.addPeer = addPeer
|
||||||
@ -418,15 +418,15 @@ private enum ChannelPermissionsEntry: ItemListNodeEntry {
|
|||||||
}
|
}
|
||||||
case let .chargeForMessages(_, title, value):
|
case let .chargeForMessages(_, title, value):
|
||||||
return ItemListSwitchItem(presentationData: presentationData, title: title, value: value, sectionId: self.section, style: .blocks, updated: { value in
|
return ItemListSwitchItem(presentationData: presentationData, title: title, value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||||
arguments.updateStarsAmount(value ? StarsAmount(value: 400, nanos: 0) : nil)
|
arguments.updateStarsAmount(value ? StarsAmount(value: 400, nanos: 0) : nil, true)
|
||||||
})
|
})
|
||||||
case let .chargeForMessagesInfo(_, value):
|
case let .chargeForMessagesInfo(_, value):
|
||||||
return ItemListTextItem(presentationData: presentationData, text: .plain(value), sectionId: self.section)
|
return ItemListTextItem(presentationData: presentationData, text: .plain(value), sectionId: self.section)
|
||||||
case let .messagePriceHeader(_, value):
|
case let .messagePriceHeader(_, value):
|
||||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: value, sectionId: self.section)
|
return ItemListSectionHeaderItem(presentationData: presentationData, text: value, sectionId: self.section)
|
||||||
case let .messagePrice(_, value, maxValue, price):
|
case let .messagePrice(_, value, maxValue, price):
|
||||||
return MessagePriceItem(theme: presentationData.theme, strings: presentationData.strings, isEnabled: true, minValue: 1, maxValue: maxValue, value: value, price: price, sectionId: self.section, updated: { value in
|
return MessagePriceItem(theme: presentationData.theme, strings: presentationData.strings, isEnabled: true, minValue: 1, maxValue: maxValue, value: value, price: price, sectionId: self.section, updated: { value, apply in
|
||||||
arguments.updateStarsAmount(StarsAmount(value: value, nanos: 0))
|
arguments.updateStarsAmount(StarsAmount(value: value, nanos: 0), apply)
|
||||||
})
|
})
|
||||||
case let .messagePriceInfo(_, value):
|
case let .messagePriceInfo(_, value):
|
||||||
return ItemListTextItem(presentationData: presentationData, text: .plain(value), sectionId: self.section)
|
return ItemListTextItem(presentationData: presentationData, text: .plain(value), sectionId: self.section)
|
||||||
@ -1248,23 +1248,25 @@ public func channelPermissionsController(context: AccountContext, updatedPresent
|
|||||||
updateUnrestrictBoostersDisposable.set((context.engine.peers.updateChannelBoostsToUnlockRestrictions(peerId: view.peerId, boosts: value)
|
updateUnrestrictBoostersDisposable.set((context.engine.peers.updateChannelBoostsToUnlockRestrictions(peerId: view.peerId, boosts: value)
|
||||||
|> deliverOnMainQueue).start())
|
|> deliverOnMainQueue).start())
|
||||||
})
|
})
|
||||||
}, updateStarsAmount: { value in
|
}, updateStarsAmount: { value, apply in
|
||||||
updateState { state in
|
updateState { state in
|
||||||
var state = state
|
var state = state
|
||||||
state.modifiedStarsAmount = value
|
state.modifiedStarsAmount = value
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = (peerView.get()
|
if apply {
|
||||||
|> take(1)
|
let _ = (peerView.get()
|
||||||
|> deliverOnMainQueue).start(next: { view in
|
|> take(1)
|
||||||
var effectiveValue = value
|
|> deliverOnMainQueue).start(next: { view in
|
||||||
if value?.value == 0 {
|
var effectiveValue = value
|
||||||
effectiveValue = nil
|
if value?.value == 0 {
|
||||||
}
|
effectiveValue = nil
|
||||||
updateSendPaidMessageStarsDisposable.set((context.engine.peers.updateChannelPaidMessagesStars(peerId: view.peerId, stars: effectiveValue)
|
}
|
||||||
|> deliverOnMainQueue).start())
|
updateSendPaidMessageStarsDisposable.set((context.engine.peers.updateChannelPaidMessagesStars(peerId: view.peerId, stars: effectiveValue)
|
||||||
})
|
|> deliverOnMainQueue).start())
|
||||||
|
})
|
||||||
|
}
|
||||||
}, toggleIsOptionExpanded: { flags in
|
}, toggleIsOptionExpanded: { flags in
|
||||||
updateState { state in
|
updateState { state in
|
||||||
var state = state
|
var state = state
|
||||||
|
|||||||
@ -149,7 +149,7 @@ private enum GlobalAutoremoveEntry: ItemListNodeEntry {
|
|||||||
case .priceHeader:
|
case .priceHeader:
|
||||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: presentationData.strings.Privacy_Messages_MessagePrice, sectionId: self.section)
|
return ItemListSectionHeaderItem(presentationData: presentationData, text: presentationData.strings.Privacy_Messages_MessagePrice, sectionId: self.section)
|
||||||
case let .price(value, maxValue, price, isEnabled):
|
case let .price(value, maxValue, price, isEnabled):
|
||||||
return MessagePriceItem(theme: presentationData.theme, strings: presentationData.strings, isEnabled: isEnabled, minValue: 1, maxValue: maxValue, value: value, price: price, sectionId: self.section, updated: { value in
|
return MessagePriceItem(theme: presentationData.theme, strings: presentationData.strings, isEnabled: isEnabled, minValue: 1, maxValue: maxValue, value: value, price: price, sectionId: self.section, updated: { value, _ in
|
||||||
arguments.updateValue(.paidMessages(StarsAmount(value: value, nanos: 0)))
|
arguments.updateValue(.paidMessages(StarsAmount(value: value, nanos: 0)))
|
||||||
}, openPremiumInfo: {
|
}, openPremiumInfo: {
|
||||||
arguments.openPremiumInfo()
|
arguments.openPremiumInfo()
|
||||||
@ -281,8 +281,9 @@ public func incomingMessagePrivacyScreen(context: AccountContext, value: GlobalP
|
|||||||
chatListFilters: nil,
|
chatListFilters: nil,
|
||||||
onlyUsers: false,
|
onlyUsers: false,
|
||||||
disableChannels: true,
|
disableChannels: true,
|
||||||
disableBots: false
|
disableBots: true,
|
||||||
)), filters: [.excludeSelf]))
|
disableContacts: true
|
||||||
|
))))
|
||||||
addPeerDisposable.set((controller.result
|
addPeerDisposable.set((controller.result
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOnMainQueue).start(next: { [weak controller] result in
|
|> deliverOnMainQueue).start(next: { [weak controller] result in
|
||||||
@ -342,7 +343,7 @@ public func incomingMessagePrivacyScreen(context: AccountContext, value: GlobalP
|
|||||||
controller.navigationPresentation = .modal
|
controller.navigationPresentation = .modal
|
||||||
pushControllerImpl?(controller)
|
pushControllerImpl?(controller)
|
||||||
} else {
|
} else {
|
||||||
let controller = selectivePrivacyPeersController(context: context, title: presentationData.strings.Privacy_Messages_Exceptions_Title, footer: presentationData.strings.Privacy_Messages_RemoveFeeInfo, initialPeers: peerIds, initialEnableForPremium: false, displayPremiumCategory: false, initialEnableForBots: false, displayBotsCategory: false, updated: { updatedPeerIds, _, _ in
|
let controller = selectivePrivacyPeersController(context: context, title: presentationData.strings.Privacy_Messages_Exceptions_Title, footer: presentationData.strings.Privacy_Messages_RemoveFeeInfo, hideContacts: true, initialPeers: peerIds, initialEnableForPremium: false, displayPremiumCategory: false, initialEnableForBots: false, displayBotsCategory: false, updated: { updatedPeerIds, _, _ in
|
||||||
updateState { state in
|
updateState { state in
|
||||||
var updatedState = state
|
var updatedState = state
|
||||||
updatedState.disableFor = updatedPeerIds
|
updatedState.disableFor = updatedPeerIds
|
||||||
|
|||||||
@ -322,7 +322,7 @@ private func selectivePrivacyPeersControllerEntries(presentationData: Presentati
|
|||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
public func selectivePrivacyPeersController(context: AccountContext, title: String, footer: String? = nil, initialPeers: [EnginePeer.Id: SelectivePrivacyPeer], initialEnableForPremium: Bool, displayPremiumCategory: Bool, initialEnableForBots: Bool, displayBotsCategory: Bool, updated: @escaping ([EnginePeer.Id: SelectivePrivacyPeer], Bool, Bool) -> Void) -> ViewController {
|
public func selectivePrivacyPeersController(context: AccountContext, title: String, footer: String? = nil, hideContacts: Bool = false, initialPeers: [EnginePeer.Id: SelectivePrivacyPeer], initialEnableForPremium: Bool, displayPremiumCategory: Bool, initialEnableForBots: Bool, displayBotsCategory: Bool, updated: @escaping ([EnginePeer.Id: SelectivePrivacyPeer], Bool, Bool) -> Void) -> ViewController {
|
||||||
let initialState = SelectivePrivacyPeersControllerState(enableForPremium: initialEnableForPremium, enableForBots: initialEnableForBots, editing: false, peerIdWithRevealedOptions: nil)
|
let initialState = SelectivePrivacyPeersControllerState(enableForPremium: initialEnableForPremium, enableForBots: initialEnableForBots, editing: false, peerIdWithRevealedOptions: nil)
|
||||||
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
|
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
|
||||||
let stateValue = Atomic(value: initialState)
|
let stateValue = Atomic(value: initialState)
|
||||||
@ -428,7 +428,8 @@ public func selectivePrivacyPeersController(context: AccountContext, title: Stri
|
|||||||
chatListFilters: nil,
|
chatListFilters: nil,
|
||||||
onlyUsers: false,
|
onlyUsers: false,
|
||||||
disableChannels: true,
|
disableChannels: true,
|
||||||
disableBots: false
|
disableBots: hideContacts,
|
||||||
|
disableContacts: hideContacts
|
||||||
)), alwaysEnabled: true))
|
)), alwaysEnabled: true))
|
||||||
addPeerDisposable.set((controller.result
|
addPeerDisposable.set((controller.result
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|
|||||||
@ -404,6 +404,19 @@ public func resendMessages(account: Account, messageIds: [MessageId]) -> Signal<
|
|||||||
return account.postbox.transaction { transaction -> Void in
|
return account.postbox.transaction { transaction -> Void in
|
||||||
var removeMessageIds: [MessageId] = []
|
var removeMessageIds: [MessageId] = []
|
||||||
for (peerId, ids) in messagesIdsGroupedByPeerId(messageIds) {
|
for (peerId, ids) in messagesIdsGroupedByPeerId(messageIds) {
|
||||||
|
var sendPaidMessageStars: StarsAmount?
|
||||||
|
let peer = transaction.getPeer(peerId)
|
||||||
|
if let user = peer as? TelegramUser, user.flags.contains(.requireStars) {
|
||||||
|
if let cachedUserData = transaction.getPeerCachedData(peerId: user.id) as? CachedUserData {
|
||||||
|
sendPaidMessageStars = cachedUserData.sendPaidMessageStars
|
||||||
|
}
|
||||||
|
} else if let channel = peer as? TelegramChannel {
|
||||||
|
if channel.flags.contains(.isCreator) || channel.adminRights != nil {
|
||||||
|
} else {
|
||||||
|
sendPaidMessageStars = channel.sendPaidMessageStars
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var messages: [EnqueueMessage] = []
|
var messages: [EnqueueMessage] = []
|
||||||
for id in ids {
|
for id in ids {
|
||||||
if let message = transaction.getMessage(id), !message.flags.contains(.Incoming) {
|
if let message = transaction.getMessage(id), !message.flags.contains(.Incoming) {
|
||||||
@ -425,9 +438,16 @@ public func resendMessages(account: Account, messageIds: [MessageId]) -> Signal<
|
|||||||
} else if let attribute = attribute as? ForwardSourceInfoAttribute {
|
} else if let attribute = attribute as? ForwardSourceInfoAttribute {
|
||||||
forwardSource = attribute.messageId
|
forwardSource = attribute.messageId
|
||||||
} else {
|
} else {
|
||||||
filteredAttributes.append(attribute)
|
if attribute is PaidStarsMessageAttribute {
|
||||||
|
} else {
|
||||||
|
filteredAttributes.append(attribute)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let sendPaidMessageStars {
|
||||||
|
filteredAttributes.append(PaidStarsMessageAttribute(stars: sendPaidMessageStars, postponeSending: false))
|
||||||
|
}
|
||||||
|
|
||||||
if let forwardSource = forwardSource {
|
if let forwardSource = forwardSource {
|
||||||
messages.append(.forward(source: forwardSource, threadId: nil, grouping: .auto, attributes: filteredAttributes, correlationId: nil))
|
messages.append(.forward(source: forwardSource, threadId: nil, grouping: .auto, attributes: filteredAttributes, correlationId: nil))
|
||||||
|
|||||||
@ -1016,7 +1016,10 @@ private final class ProfileGiftsContextImpl {
|
|||||||
let sorting = self.sorting
|
let sorting = self.sorting
|
||||||
|
|
||||||
let isFiltered = self.filter != .All || self.sorting != .date
|
let isFiltered = self.filter != .All || self.sorting != .date
|
||||||
|
if !isFiltered {
|
||||||
|
self.filteredGifts = []
|
||||||
|
self.filteredCount = nil
|
||||||
|
}
|
||||||
let dataState = isFiltered ? self.filteredDataState : self.dataState
|
let dataState = isFiltered ? self.filteredDataState : self.dataState
|
||||||
|
|
||||||
if case let .ready(true, initialNextOffset) = dataState {
|
if case let .ready(true, initialNextOffset) = dataState {
|
||||||
@ -1202,12 +1205,15 @@ private final class ProfileGiftsContextImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let existingGifts = Set(pinnedGifts.compactMap { $0.reference })
|
let existingGifts = Set(pinnedGifts.compactMap { $0.reference })
|
||||||
|
|
||||||
var updatedGifts: [ProfileGiftsContext.State.StarGift] = []
|
var updatedGifts: [ProfileGiftsContext.State.StarGift] = []
|
||||||
for gift in self.gifts {
|
for gift in self.gifts {
|
||||||
if let reference = gift.reference, existingGifts.contains(reference) {
|
if let reference = gift.reference, existingGifts.contains(reference) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
var gift = gift
|
||||||
|
if gift.reference == reference {
|
||||||
|
gift = gift.withPinnedToTop(pinnedToTop)
|
||||||
|
}
|
||||||
updatedGifts.append(gift)
|
updatedGifts.append(gift)
|
||||||
}
|
}
|
||||||
updatedGifts.sort { lhs, rhs in
|
updatedGifts.sort { lhs, rhs in
|
||||||
@ -1216,18 +1222,48 @@ private final class ProfileGiftsContextImpl {
|
|||||||
updatedGifts.insert(contentsOf: pinnedGifts, at: 0)
|
updatedGifts.insert(contentsOf: pinnedGifts, at: 0)
|
||||||
self.gifts = updatedGifts
|
self.gifts = updatedGifts
|
||||||
|
|
||||||
if let index = self.filteredGifts.firstIndex(where: { $0.reference == reference }) {
|
var effectiveReferences = pinnedGifts.compactMap { $0.reference }
|
||||||
self.filteredGifts[index] = self.filteredGifts[index].withPinnedToTop(pinnedToTop)
|
if !self.filteredGifts.isEmpty {
|
||||||
|
var filteredPinnedGifts = self.filteredGifts.filter { $0.pinnedToTop }
|
||||||
|
if var gift = self.filteredGifts.first(where: { $0.reference == reference }) {
|
||||||
|
gift = gift.withPinnedToTop(pinnedToTop)
|
||||||
|
if pinnedToTop {
|
||||||
|
if !gift.savedToProfile {
|
||||||
|
gift = gift.withSavedToProfile(true)
|
||||||
|
}
|
||||||
|
filteredPinnedGifts.append(gift)
|
||||||
|
} else {
|
||||||
|
filteredPinnedGifts.removeAll(where: { $0.reference == reference })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let existingFilteredGifts = Set(filteredPinnedGifts.compactMap { $0.reference })
|
||||||
|
var updatedFilteredGifts: [ProfileGiftsContext.State.StarGift] = []
|
||||||
|
for gift in self.filteredGifts {
|
||||||
|
if let reference = gift.reference, existingFilteredGifts.contains(reference) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var gift = gift
|
||||||
|
if gift.reference == reference {
|
||||||
|
gift = gift.withPinnedToTop(pinnedToTop)
|
||||||
|
}
|
||||||
|
updatedFilteredGifts.append(gift)
|
||||||
|
}
|
||||||
|
updatedFilteredGifts.sort { lhs, rhs in
|
||||||
|
lhs.date > rhs.date
|
||||||
|
}
|
||||||
|
updatedFilteredGifts.insert(contentsOf: filteredPinnedGifts, at: 0)
|
||||||
|
self.filteredGifts = updatedFilteredGifts
|
||||||
|
|
||||||
|
effectiveReferences = filteredPinnedGifts.compactMap { $0.reference }
|
||||||
}
|
}
|
||||||
|
|
||||||
self.pushState()
|
self.pushState()
|
||||||
|
|
||||||
var signal = _internal_updateStarGiftsPinnedToTop(account: self.account, peerId: self.peerId, references: pinnedGifts.compactMap { $0.reference })
|
var signal = _internal_updateStarGiftsPinnedToTop(account: self.account, peerId: self.peerId, references: effectiveReferences)
|
||||||
|
|
||||||
if saveToProfile {
|
if saveToProfile {
|
||||||
signal = _internal_updateStarGiftAddedToProfile(account: self.account, reference: reference, added: true)
|
signal = _internal_updateStarGiftAddedToProfile(account: self.account, reference: reference, added: true)
|
||||||
|> then(signal)
|
|> then(signal)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.actionDisposable.set(
|
self.actionDisposable.set(
|
||||||
(signal |> deliverOn(self.queue)).startStrict(completed: { [weak self] in
|
(signal |> deliverOn(self.queue)).startStrict(completed: { [weak self] in
|
||||||
self?.reload()
|
self?.reload()
|
||||||
@ -1279,7 +1315,6 @@ private final class ProfileGiftsContextImpl {
|
|||||||
|> ignoreValues
|
|> ignoreValues
|
||||||
|> then(signal)
|
|> then(signal)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.actionDisposable.set(
|
self.actionDisposable.set(
|
||||||
(signal |> deliverOn(self.queue)).startStrict(completed: { [weak self] in
|
(signal |> deliverOn(self.queue)).startStrict(completed: { [weak self] in
|
||||||
self?.reload()
|
self?.reload()
|
||||||
@ -1349,6 +1384,9 @@ private final class ProfileGiftsContextImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateFilter(_ filter: ProfileGiftsContext.Filters) {
|
func updateFilter(_ filter: ProfileGiftsContext.Filters) {
|
||||||
|
guard self.filter != filter else {
|
||||||
|
return
|
||||||
|
}
|
||||||
self.filter = filter
|
self.filter = filter
|
||||||
self.filteredDataState = .ready(canLoadMore: true, nextOffset: nil)
|
self.filteredDataState = .ready(canLoadMore: true, nextOffset: nil)
|
||||||
self.pushState()
|
self.pushState()
|
||||||
@ -1357,6 +1395,9 @@ private final class ProfileGiftsContextImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateSorting(_ sorting: ProfileGiftsContext.Sorting) {
|
func updateSorting(_ sorting: ProfileGiftsContext.Sorting) {
|
||||||
|
guard self.sorting != sorting else {
|
||||||
|
return
|
||||||
|
}
|
||||||
self.sorting = sorting
|
self.sorting = sorting
|
||||||
self.filteredDataState = .ready(canLoadMore: true, nextOffset: nil)
|
self.filteredDataState = .ready(canLoadMore: true, nextOffset: nil)
|
||||||
self.pushState()
|
self.pushState()
|
||||||
|
|||||||
@ -79,6 +79,7 @@ public enum PresentationResourceKey: Int32 {
|
|||||||
case itemListPremiumIcon
|
case itemListPremiumIcon
|
||||||
case itemListRoundTopupIcon
|
case itemListRoundTopupIcon
|
||||||
case itemListRoundWithdrawIcon
|
case itemListRoundWithdrawIcon
|
||||||
|
case itemListStatsIcon
|
||||||
|
|
||||||
case statsReactionsIcon
|
case statsReactionsIcon
|
||||||
case statsForwardsIcon
|
case statsForwardsIcon
|
||||||
|
|||||||
@ -465,4 +465,10 @@ public struct PresentationResourcesItemList {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func itemListStatsIcon(_ theme: PresentationTheme) -> UIImage? {
|
||||||
|
return theme.image(PresentationResourceKey.itemListStatsIcon.rawValue, { theme in
|
||||||
|
return generateTintedImage(image: UIImage(bundleImageName: "Premium/Stars/Stats"), color: .white)?.withRenderingMode(.alwaysTemplate)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1148,7 +1148,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||||||
case let .starGiftUnique(gift, isUpgrade, _, _, _, _, _, peerId, senderId, _):
|
case let .starGiftUnique(gift, isUpgrade, _, _, _, _, _, peerId, senderId, _):
|
||||||
if case let .unique(gift) = gift {
|
if case let .unique(gift) = gift {
|
||||||
if !forAdditionalServiceMessage && !"".isEmpty {
|
if !forAdditionalServiceMessage && !"".isEmpty {
|
||||||
attributedString = NSAttributedString(string: "\(gift.title) #\(gift.number)", font: titleFont, textColor: primaryTextColor)
|
attributedString = NSAttributedString(string: "\(gift.title) #\(presentationStringsFormattedNumber(gift.number, dateTimeFormat.groupingSeparator))", font: titleFont, textColor: primaryTextColor)
|
||||||
} else if let messagePeer = message.peers[message.id.peerId] {
|
} else if let messagePeer = message.peers[message.id.peerId] {
|
||||||
var peerName = EnginePeer(messagePeer).compactDisplayTitle
|
var peerName = EnginePeer(messagePeer).compactDisplayTitle
|
||||||
var peerIds: [(Int, EnginePeer.Id?)] = [(0, messagePeer.id)]
|
var peerIds: [(Int, EnginePeer.Id?)] = [(0, messagePeer.id)]
|
||||||
|
|||||||
@ -2968,7 +2968,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||||||
} else {
|
} else {
|
||||||
let contentProperties = contentPropertiesAndLayouts[i].3
|
let contentProperties = contentPropertiesAndLayouts[i].3
|
||||||
|
|
||||||
if i == 0 && !headerSize.height.isZero {
|
if (i == 0 || (i == 1 && detachedContentNodesHeight > 0)) && !headerSize.height.isZero {
|
||||||
if contentGroupId == nil {
|
if contentGroupId == nil {
|
||||||
contentNodesHeight += properties.headerSpacing
|
contentNodesHeight += properties.headerSpacing
|
||||||
}
|
}
|
||||||
@ -2981,7 +2981,15 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||||||
if !contentContainerNodeFrames.isEmpty {
|
if !contentContainerNodeFrames.isEmpty {
|
||||||
overlapOffset = currentContainerGroupOverlap
|
overlapOffset = currentContainerGroupOverlap
|
||||||
}
|
}
|
||||||
let containerFrame = CGRect(x: 0.0, y: headerSize.height + totalContentNodesHeight - contentNodesHeight - overlapOffset, width: maxContentWidth, height: contentNodesHeight)
|
var containerContentNodesOrigin = contentNodesHeight
|
||||||
|
var containerContentNodesHeight = contentNodesHeight
|
||||||
|
if detachedContentNodesHeight > 0 {
|
||||||
|
if contentContainerNodeFrames.isEmpty {
|
||||||
|
containerContentNodesHeight -= detachedContentNodesHeight - 4.0
|
||||||
|
containerContentNodesOrigin -= detachedContentNodesHeight - 4.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let containerFrame = CGRect(x: 0.0, y: headerSize.height + totalContentNodesHeight - containerContentNodesOrigin - overlapOffset, width: maxContentWidth, height: containerContentNodesHeight)
|
||||||
contentContainerNodeFrames.append((containerGroupId, containerFrame, currentItemSelection, currentContainerGroupOverlap))
|
contentContainerNodeFrames.append((containerGroupId, containerFrame, currentItemSelection, currentContainerGroupOverlap))
|
||||||
|
|
||||||
if !overlapOffset.isZero {
|
if !overlapOffset.isZero {
|
||||||
@ -2997,7 +3005,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||||||
}
|
}
|
||||||
|
|
||||||
var contentNodeOriginY = contentNodesHeight
|
var contentNodeOriginY = contentNodesHeight
|
||||||
if detachedContentNodesHeight > 0 {
|
if detachedContentNodesHeight > 0, contentContainerNodeFrames.isEmpty {
|
||||||
contentNodeOriginY -= detachedContentNodesHeight - 4.0
|
contentNodeOriginY -= detachedContentNodesHeight - 4.0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3025,7 +3033,15 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||||||
if !contentContainerNodeFrames.isEmpty {
|
if !contentContainerNodeFrames.isEmpty {
|
||||||
overlapOffset = currentContainerGroupOverlap
|
overlapOffset = currentContainerGroupOverlap
|
||||||
}
|
}
|
||||||
contentContainerNodeFrames.append((containerGroupId, CGRect(x: 0.0, y: headerSize.height + totalContentNodesHeight - contentNodesHeight - overlapOffset, width: maxContentWidth, height: contentNodesHeight), currentItemSelection, currentContainerGroupOverlap))
|
var containerContentNodesOrigin = contentNodesHeight
|
||||||
|
var containerContentNodesHeight = contentNodesHeight
|
||||||
|
if detachedContentNodesHeight > 0 {
|
||||||
|
if contentContainerNodeFrames.isEmpty {
|
||||||
|
containerContentNodesHeight -= detachedContentNodesHeight - 4.0
|
||||||
|
containerContentNodesOrigin -= detachedContentNodesHeight - 4.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contentContainerNodeFrames.append((containerGroupId, CGRect(x: 0.0, y: headerSize.height + totalContentNodesHeight - containerContentNodesOrigin - overlapOffset, width: maxContentWidth, height: containerContentNodesHeight), currentItemSelection, currentContainerGroupOverlap))
|
||||||
if !overlapOffset.isZero {
|
if !overlapOffset.isZero {
|
||||||
totalContentNodesHeight -= currentContainerGroupOverlap
|
totalContentNodesHeight -= currentContainerGroupOverlap
|
||||||
}
|
}
|
||||||
|
|||||||
@ -213,7 +213,7 @@ public final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContent
|
|||||||
} else {
|
} else {
|
||||||
textLeftInset = 15.0 + imageSize * min(1.0, CGFloat(replyPeers.count)) + (imageSpacing) * max(0.0, min(2.0, CGFloat(replyPeers.count - 1)))
|
textLeftInset = 15.0 + imageSize * min(1.0, CGFloat(replyPeers.count)) + (imageSpacing) * max(0.0, min(2.0, CGFloat(replyPeers.count - 1)))
|
||||||
}
|
}
|
||||||
let textRightInset: CGFloat = 36.0
|
let textRightInset: CGFloat = 24.0
|
||||||
|
|
||||||
let textConstrainedSize = CGSize(width: min(maxTextWidth, constrainedSize.width - horizontalInset - textLeftInset - textRightInset), height: constrainedSize.height)
|
let textConstrainedSize = CGSize(width: min(maxTextWidth, constrainedSize.width - horizontalInset - textLeftInset - textRightInset), height: constrainedSize.height)
|
||||||
|
|
||||||
|
|||||||
@ -354,8 +354,8 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
|
|
||||||
let attributedString = attributedServiceMessageString(theme: item.presentationData.theme, strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, message: EngineMessage(item.message), accountPeerId: item.context.account.peerId)
|
let attributedString = attributedServiceMessageString(theme: item.presentationData.theme, strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, message: EngineMessage(item.message), accountPeerId: item.context.account.peerId)
|
||||||
|
|
||||||
let primaryTextColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper).primaryText
|
var primaryTextColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper).primaryText
|
||||||
|
|
||||||
var months: Int32 = 3
|
var months: Int32 = 3
|
||||||
var animationName: String = ""
|
var animationName: String = ""
|
||||||
var animationFile: TelegramMediaFile?
|
var animationFile: TelegramMediaFile?
|
||||||
@ -582,7 +582,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
} else {
|
} else {
|
||||||
title = isStoryEntity ? uniqueGift.title : item.presentationData.strings.Notification_StarGift_Title(authorName).string
|
title = isStoryEntity ? uniqueGift.title : item.presentationData.strings.Notification_StarGift_Title(authorName).string
|
||||||
}
|
}
|
||||||
text = isStoryEntity ? "**\(item.presentationData.strings.Notification_StarGift_Collectible) #\(uniqueGift.number)**" : "**\(uniqueGift.title) #\(uniqueGift.number)**"
|
text = isStoryEntity ? "**\(item.presentationData.strings.Notification_StarGift_Collectible) #\(presentationStringsFormattedNumber(uniqueGift.number, item.presentationData.dateTimeFormat.groupingSeparator))**" : "**\(uniqueGift.title) #\(presentationStringsFormattedNumber(uniqueGift.number, item.presentationData.dateTimeFormat.groupingSeparator))**"
|
||||||
ribbonTitle = isStoryEntity ? "" : item.presentationData.strings.Notification_StarGift_Gift
|
ribbonTitle = isStoryEntity ? "" : item.presentationData.strings.Notification_StarGift_Gift
|
||||||
buttonTitle = isStoryEntity ? "" : item.presentationData.strings.Notification_StarGift_View
|
buttonTitle = isStoryEntity ? "" : item.presentationData.strings.Notification_StarGift_View
|
||||||
modelTitle = item.presentationData.strings.Notification_StarGift_Model
|
modelTitle = item.presentationData.strings.Notification_StarGift_Model
|
||||||
@ -599,6 +599,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
uniqueSecondBackgroundColor = UIColor(rgb: UInt32(bitPattern: innerColor))
|
uniqueSecondBackgroundColor = UIColor(rgb: UInt32(bitPattern: innerColor))
|
||||||
uniquePatternColor = UIColor(rgb: UInt32(bitPattern: patternColor))
|
uniquePatternColor = UIColor(rgb: UInt32(bitPattern: patternColor))
|
||||||
backdropValue = name
|
backdropValue = name
|
||||||
|
primaryTextColor = UIColor(rgb: 0xffffff)
|
||||||
subtitleColor = UIColor(rgb: UInt32(bitPattern: innerColor)).withMultiplied(hue: 1.0, saturation: 1.02, brightness: 1.25).mixedWith(UIColor.white, alpha: 0.3)
|
subtitleColor = UIColor(rgb: UInt32(bitPattern: innerColor)).withMultiplied(hue: 1.0, saturation: 1.02, brightness: 1.25).mixedWith(UIColor.white, alpha: 0.3)
|
||||||
case let .pattern(name, file, _):
|
case let .pattern(name, file, _):
|
||||||
symbolValue = name
|
symbolValue = name
|
||||||
|
|||||||
@ -1441,14 +1441,31 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
let sideInset: CGFloat = floor((availableSize.width - fillingSize) * 0.5) + 16.0
|
let sideInset: CGFloat = floor((availableSize.width - fillingSize) * 0.5) + 16.0
|
||||||
|
|
||||||
|
let context = component.context
|
||||||
let balanceSize = self.balanceOverlay.update(
|
let balanceSize = self.balanceOverlay.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
component: AnyComponent(
|
component: AnyComponent(
|
||||||
StarsBalanceOverlayComponent(
|
StarsBalanceOverlayComponent(
|
||||||
context: component.context,
|
context: component.context,
|
||||||
theme: environment.theme,
|
theme: environment.theme,
|
||||||
action: {
|
action: { [weak self] in
|
||||||
|
guard let self, let starsContext = context.starsContext, let navigationController = self.environment?.controller()?.navigationController as? NavigationController else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.environment?.controller()?.dismiss()
|
||||||
|
|
||||||
|
let _ = (context.engine.payments.starsTopUpOptions()
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).startStandalone(next: { options in
|
||||||
|
let controller = context.sharedContext.makeStarsPurchaseScreen(
|
||||||
|
context: context,
|
||||||
|
starsContext: starsContext,
|
||||||
|
options: options,
|
||||||
|
purpose: .generic,
|
||||||
|
completion: { _ in }
|
||||||
|
)
|
||||||
|
navigationController.pushViewController(controller)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|||||||
@ -311,10 +311,10 @@ public final class ChatUserInfoItemNode: ListViewItemNode, ASGestureRecognizerDe
|
|||||||
} else {
|
} else {
|
||||||
var countryName = ""
|
var countryName = ""
|
||||||
let countriesConfiguration = item.context.currentCountriesConfiguration.with { $0 }
|
let countriesConfiguration = item.context.currentCountriesConfiguration.with { $0 }
|
||||||
if let country = countriesConfiguration.countries.first(where: { $0.id == phoneCountry }) {
|
if phoneCountry == "FT" {
|
||||||
countryName = country.localizedName ?? country.name
|
|
||||||
} else if phoneCountry == "FT" {
|
|
||||||
countryName = item.presentationData.strings.Chat_NonContactUser_AnonymousNumber
|
countryName = item.presentationData.strings.Chat_NonContactUser_AnonymousNumber
|
||||||
|
} else if let country = countriesConfiguration.countries.first(where: { $0.id == phoneCountry }) {
|
||||||
|
countryName = country.localizedName ?? country.name
|
||||||
} else if phoneCountry == "TS" {
|
} else if phoneCountry == "TS" {
|
||||||
countryName = "Test"
|
countryName = "Test"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -177,7 +177,9 @@ public final class EmojiKeyboardItemLayer: MultiAnimationRenderTarget {
|
|||||||
|
|
||||||
switch content {
|
switch content {
|
||||||
case let .animation(animationData):
|
case let .animation(animationData):
|
||||||
let animationDataResource = animationData.resource._parse()
|
guard let animationDataResource = animationData.resource._parse() else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let loadAnimation: () -> Void = { [weak self] in
|
let loadAnimation: () -> Void = { [weak self] in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
|
|||||||
@ -65,12 +65,15 @@ public final class EntityKeyboardAnimationData: Equatable {
|
|||||||
case stickerPackThumbnail(id: Int64, accessHash: Int64, info: StickerPackCollectionInfo.Accessor)
|
case stickerPackThumbnail(id: Int64, accessHash: Int64, info: StickerPackCollectionInfo.Accessor)
|
||||||
case file(PartialMediaReference?, TelegramMediaFile.Accessor)
|
case file(PartialMediaReference?, TelegramMediaFile.Accessor)
|
||||||
|
|
||||||
func _parse() -> MediaResourceReference {
|
func _parse() -> MediaResourceReference? {
|
||||||
switch self {
|
switch self {
|
||||||
case let .resource(resource):
|
case let .resource(resource):
|
||||||
return resource
|
return resource
|
||||||
case let .stickerPackThumbnail(id, accessHash, info):
|
case let .stickerPackThumbnail(id, accessHash, info):
|
||||||
return .stickerPackThumbnail(stickerPack: .id(id: id, accessHash: accessHash), resource: info._parse().thumbnail!.resource)
|
guard let thumbnail = info._parse().thumbnail else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return .stickerPackThumbnail(stickerPack: .id(id: id, accessHash: accessHash), resource: thumbnail.resource)
|
||||||
case let .file(partialReference, file):
|
case let .file(partialReference, file):
|
||||||
let file = file._parse()
|
let file = file._parse()
|
||||||
if let partialReference {
|
if let partialReference {
|
||||||
@ -1742,7 +1745,9 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
component.animationRenderer.setFrameIndex(itemId: animationData.resource._parse().resource.id.stringRepresentation, size: itemLayer.pixelSize, frameIndex: sourceItem.frameIndex, placeholder: sourceItem.placeholder)
|
if let resource = animationData.resource._parse() {
|
||||||
|
component.animationRenderer.setFrameIndex(itemId: resource.resource.id.stringRepresentation, size: itemLayer.pixelSize, frameIndex: sourceItem.frameIndex, placeholder: sourceItem.placeholder)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let distance = itemLayer.position.y - itemLayout.frame(groupIndex: 0, itemIndex: 0).midY
|
let distance = itemLayer.position.y - itemLayout.frame(groupIndex: 0, itemIndex: 0).midY
|
||||||
let maxDistance = self.bounds.height
|
let maxDistance = self.bounds.height
|
||||||
|
|||||||
@ -259,10 +259,10 @@ public func giftTransferAlertController(context: AccountContext, gift: StarGift.
|
|||||||
let text: String
|
let text: String
|
||||||
let buttonText: String
|
let buttonText: String
|
||||||
if transferStars > 0 {
|
if transferStars > 0 {
|
||||||
text = strings.Gift_Transfer_Confirmation_Text("\(gift.title) #\(gift.number)", peer.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder), strings.Gift_Transfer_Confirmation_Text_Stars(Int32(transferStars))).string
|
text = strings.Gift_Transfer_Confirmation_Text("\(gift.title) #\(presentationStringsFormattedNumber(gift.number, presentationData.dateTimeFormat.groupingSeparator))", peer.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder), strings.Gift_Transfer_Confirmation_Text_Stars(Int32(transferStars))).string
|
||||||
buttonText = "\(strings.Gift_Transfer_Confirmation_Transfer) $ \(transferStars)"
|
buttonText = "\(strings.Gift_Transfer_Confirmation_Transfer) $ \(transferStars)"
|
||||||
} else {
|
} else {
|
||||||
text = strings.Gift_Transfer_Confirmation_TextFree("\(gift.title) #\(gift.number)", peer.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder)).string
|
text = strings.Gift_Transfer_Confirmation_TextFree("\(gift.title) #\(presentationStringsFormattedNumber(gift.number, presentationData.dateTimeFormat.groupingSeparator))", peer.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder)).string
|
||||||
buttonText = strings.Gift_Transfer_Confirmation_TransferFree
|
buttonText = strings.Gift_Transfer_Confirmation_TransferFree
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -635,7 +635,8 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||||||
if case .wearPreview = component.subject {
|
if case .wearPreview = component.subject {
|
||||||
giftTitle = uniqueGift.title
|
giftTitle = uniqueGift.title
|
||||||
} else {
|
} else {
|
||||||
giftTitle = "\(uniqueGift.title) #\(uniqueGift.number)"
|
|
||||||
|
giftTitle = "\(uniqueGift.title) #\(presentationStringsFormattedNumber(uniqueGift.number, environment.dateTimeFormat.groupingSeparator))"
|
||||||
}
|
}
|
||||||
|
|
||||||
let wearTitle = wearTitle.update(
|
let wearTitle = wearTitle.update(
|
||||||
@ -1018,7 +1019,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||||||
var descriptionText: String
|
var descriptionText: String
|
||||||
if let uniqueGift {
|
if let uniqueGift {
|
||||||
titleString = uniqueGift.title
|
titleString = uniqueGift.title
|
||||||
descriptionText = "\(strings.Gift_Unique_Collectible) #\(uniqueGift.number)"
|
descriptionText = "\(strings.Gift_Unique_Collectible) #\(presentationStringsFormattedNumber(uniqueGift.number, environment.dateTimeFormat.groupingSeparator))"
|
||||||
} else if soldOut {
|
} else if soldOut {
|
||||||
descriptionText = strings.Gift_View_UnavailableDescription
|
descriptionText = strings.Gift_View_UnavailableDescription
|
||||||
} else if upgraded {
|
} else if upgraded {
|
||||||
@ -1480,7 +1481,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||||||
if isWearing {
|
if isWearing {
|
||||||
state.commitTakeOff()
|
state.commitTakeOff()
|
||||||
|
|
||||||
component.showAttributeInfo(statusTag, strings.Gift_View_TookOff("\(uniqueGift.title) #\(uniqueGift.number)").string)
|
component.showAttributeInfo(statusTag, strings.Gift_View_TookOff("\(uniqueGift.title) #\(presentationStringsFormattedNumber(uniqueGift.number, environment.dateTimeFormat.groupingSeparator))").string)
|
||||||
} else {
|
} else {
|
||||||
if let controller = controller() as? GiftViewScreen {
|
if let controller = controller() as? GiftViewScreen {
|
||||||
controller.dismissAllTooltips()
|
controller.dismissAllTooltips()
|
||||||
@ -1507,7 +1508,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||||||
state.requestWearPreview()
|
state.requestWearPreview()
|
||||||
} else {
|
} else {
|
||||||
state.commitWear(uniqueGift)
|
state.commitWear(uniqueGift)
|
||||||
component.showAttributeInfo(statusTag, strings.Gift_View_PutOn("\(uniqueGift.title) #\(uniqueGift.number)").string)
|
component.showAttributeInfo(statusTag, strings.Gift_View_PutOn("\(uniqueGift.title) #\(presentationStringsFormattedNumber(uniqueGift.number, environment.dateTimeFormat.groupingSeparator))").string)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -2090,7 +2091,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||||||
component.cancel(true)
|
component.cancel(true)
|
||||||
} else {
|
} else {
|
||||||
Queue.mainQueue().after(0.2) {
|
Queue.mainQueue().after(0.2) {
|
||||||
component.showAttributeInfo(statusTag, strings.Gift_View_PutOn("\(uniqueGift.title) #\(uniqueGift.number)").string)
|
component.showAttributeInfo(statusTag, strings.Gift_View_PutOn("\(uniqueGift.title) #\(presentationStringsFormattedNumber(uniqueGift.number, environment.dateTimeFormat.groupingSeparator))").string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2637,7 +2638,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
|||||||
giftsPeerId = peerId
|
giftsPeerId = peerId
|
||||||
text = added ? presentationData.strings.Gift_Displayed_ChannelText : presentationData.strings.Gift_Hidden_ChannelText
|
text = added ? presentationData.strings.Gift_Displayed_ChannelText : presentationData.strings.Gift_Hidden_ChannelText
|
||||||
} else {
|
} else {
|
||||||
giftsPeerId = arguments.peerId
|
giftsPeerId = context.account.peerId
|
||||||
text = added ? presentationData.strings.Gift_Displayed_NewText : presentationData.strings.Gift_Hidden_NewText
|
text = added ? presentationData.strings.Gift_Displayed_NewText : presentationData.strings.Gift_Hidden_NewText
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3091,15 +3092,32 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
|||||||
super.containerLayoutUpdated(layout, transition: transition)
|
super.containerLayoutUpdated(layout, transition: transition)
|
||||||
|
|
||||||
if self.showBalance {
|
if self.showBalance {
|
||||||
|
let context = self.context
|
||||||
let insets = layout.insets(options: .statusBar)
|
let insets = layout.insets(options: .statusBar)
|
||||||
let balanceSize = self.balanceOverlay.update(
|
let balanceSize = self.balanceOverlay.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
component: AnyComponent(
|
component: AnyComponent(
|
||||||
StarsBalanceOverlayComponent(
|
StarsBalanceOverlayComponent(
|
||||||
context: self.context,
|
context: context,
|
||||||
theme: self.context.sharedContext.currentPresentationData.with { $0 }.theme,
|
theme: context.sharedContext.currentPresentationData.with { $0 }.theme,
|
||||||
action: {
|
action: { [weak self] in
|
||||||
|
guard let self, let starsContext = context.starsContext, let navigationController = self.navigationController as? NavigationController else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.dismissAnimated()
|
||||||
|
|
||||||
|
let _ = (context.engine.payments.starsTopUpOptions()
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).startStandalone(next: { options in
|
||||||
|
let controller = context.sharedContext.makeStarsPurchaseScreen(
|
||||||
|
context: context,
|
||||||
|
starsContext: starsContext,
|
||||||
|
options: options,
|
||||||
|
purpose: .generic,
|
||||||
|
completion: { _ in }
|
||||||
|
)
|
||||||
|
navigationController.pushViewController(controller)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|||||||
@ -274,7 +274,7 @@ public func giftWithdrawAlertController(context: AccountContext, gift: StarGift.
|
|||||||
let strings = presentationData.strings
|
let strings = presentationData.strings
|
||||||
|
|
||||||
let title = strings.Gift_Withdraw_Title
|
let title = strings.Gift_Withdraw_Title
|
||||||
let text = strings.Gift_Withdraw_Text("\(gift.title) #\(gift.number)").string
|
let text = strings.Gift_Withdraw_Text("\(gift.title) #\(presentationStringsFormattedNumber(gift.number, presentationData.dateTimeFormat.groupingSeparator))").string
|
||||||
let buttonText = strings.Gift_Withdraw_Proceed
|
let buttonText = strings.Gift_Withdraw_Proceed
|
||||||
|
|
||||||
var dismissImpl: ((Bool) -> Void)?
|
var dismissImpl: ((Bool) -> Void)?
|
||||||
|
|||||||
@ -681,7 +681,7 @@ public final class MessageInputPanelComponent: Component {
|
|||||||
if self.contextQueryPeer == nil, let peerId = component.chatLocation?.peerId {
|
if self.contextQueryPeer == nil, let peerId = component.chatLocation?.peerId {
|
||||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
||||||
guard let self, peer?.addressName != nil else {
|
guard let self, let peer, case .channel = peer, peer.addressName != nil else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.contextQueryPeer = peer
|
self.contextQueryPeer = peer
|
||||||
|
|||||||
@ -25,10 +25,10 @@ public final class MessagePriceItem: ListViewItem, ItemListItem {
|
|||||||
let value: Int64
|
let value: Int64
|
||||||
let price: String
|
let price: String
|
||||||
public let sectionId: ItemListSectionId
|
public let sectionId: ItemListSectionId
|
||||||
let updated: (Int64) -> Void
|
let updated: (Int64, Bool) -> Void
|
||||||
let openPremiumInfo: (() -> Void)?
|
let openPremiumInfo: (() -> Void)?
|
||||||
|
|
||||||
public init(theme: PresentationTheme, strings: PresentationStrings, isEnabled: Bool, minValue: Int64, maxValue: Int64, value: Int64, price: String, sectionId: ItemListSectionId, updated: @escaping (Int64) -> Void, openPremiumInfo: (() -> Void)? = nil) {
|
public init(theme: PresentationTheme, strings: PresentationStrings, isEnabled: Bool, minValue: Int64, maxValue: Int64, value: Int64, price: String, sectionId: ItemListSectionId, updated: @escaping (Int64, Bool) -> Void, openPremiumInfo: (() -> Void)? = nil) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
self.isEnabled = isEnabled
|
self.isEnabled = isEnabled
|
||||||
@ -259,7 +259,7 @@ private class MessagePriceItemNode: ListViewItemNode {
|
|||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.item = item
|
strongSelf.item = item
|
||||||
strongSelf.layoutParams = params
|
strongSelf.layoutParams = params
|
||||||
|
|
||||||
strongSelf.backgroundNode.backgroundColor = item.theme.list.itemBlocksBackgroundColor
|
strongSelf.backgroundNode.backgroundColor = item.theme.list.itemBlocksBackgroundColor
|
||||||
strongSelf.topStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
|
strongSelf.topStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
|
||||||
strongSelf.bottomStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
|
strongSelf.bottomStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
|
||||||
@ -342,6 +342,13 @@ private class MessagePriceItemNode: ListViewItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sliderView.frame = CGRect(origin: CGPoint(x: params.leftInset + 18.0, y: 36.0), size: CGSize(width: params.width - params.leftInset - params.rightInset - 18.0 * 2.0, height: 44.0))
|
sliderView.frame = CGRect(origin: CGPoint(x: params.leftInset + 18.0, y: 36.0), size: CGSize(width: params.width - params.leftInset - params.rightInset - 18.0 * 2.0, height: 44.0))
|
||||||
|
|
||||||
|
sliderView.interactionEnded = { [weak self] in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.item?.updated(Int64(self.amount.realValue), true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
strongSelf.lockIconNode.isHidden = item.isEnabled
|
strongSelf.lockIconNode.isHidden = item.isEnabled
|
||||||
@ -436,7 +443,7 @@ private class MessagePriceItemNode: ListViewItemNode {
|
|||||||
}
|
}
|
||||||
self.amount = updatedAmount
|
self.amount = updatedAmount
|
||||||
|
|
||||||
self.item?.updated(Int64(self.amount.realValue))
|
self.item?.updated(Int64(self.amount.realValue), false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -579,7 +579,7 @@ private class GiftIconLayer: SimpleLayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func layoutSublayers() {
|
override func layoutSublayers() {
|
||||||
self.shadowLayer.frame = CGRect(origin: .zero, size: self.bounds.size).insetBy(dx: -4.0, dy: -4.0)
|
self.shadowLayer.frame = CGRect(origin: .zero, size: self.bounds.size).insetBy(dx: -8.0, dy: -8.0)
|
||||||
self.animationLayer.frame = CGRect(origin: .zero, size: self.bounds.size)
|
self.animationLayer.frame = CGRect(origin: .zero, size: self.bounds.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -255,6 +255,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
self.buttonsContainerNode.clipsToBounds = true
|
self.buttonsContainerNode.clipsToBounds = true
|
||||||
|
|
||||||
self.buttonsBackgroundNode = NavigationBackgroundNode(color: .clear, enableBlur: true, enableSaturation: false)
|
self.buttonsBackgroundNode = NavigationBackgroundNode(color: .clear, enableBlur: true, enableSaturation: false)
|
||||||
|
self.buttonsBackgroundNode.isUserInteractionEnabled = false
|
||||||
self.buttonsContainerNode.addSubnode(self.buttonsBackgroundNode)
|
self.buttonsContainerNode.addSubnode(self.buttonsBackgroundNode)
|
||||||
self.buttonsMaskView = UIView()
|
self.buttonsMaskView = UIView()
|
||||||
self.buttonsBackgroundNode.view.mask = self.buttonsMaskView
|
self.buttonsBackgroundNode.view.mask = self.buttonsMaskView
|
||||||
|
|||||||
@ -3728,7 +3728,11 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
}, openAgeRestrictedMessageMedia: { _, _ in
|
}, openAgeRestrictedMessageMedia: { _, _ in
|
||||||
}, playMessageEffect: { _ in
|
}, playMessageEffect: { _ in
|
||||||
}, editMessageFactCheck: { _ in
|
}, editMessageFactCheck: { _ in
|
||||||
}, sendGift: { _ in
|
}, sendGift: { [weak self] _ in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.openPremiumGift()
|
||||||
}, openUniqueGift: { _ in
|
}, openUniqueGift: { _ in
|
||||||
}, openMessageFeeException: {
|
}, openMessageFeeException: {
|
||||||
}, requestMessageUpdate: { _, _ in
|
}, requestMessageUpdate: { _, _ in
|
||||||
@ -12703,6 +12707,12 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||||||
self.starsContext = nil
|
self.starsContext = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isMyProfile, let profileGiftsContext {
|
||||||
|
profileGiftsContext.updateFilter(.All)
|
||||||
|
profileGiftsContext.updateSorting(.date)
|
||||||
|
profileGiftsContext.reload()
|
||||||
|
}
|
||||||
|
|
||||||
self.presentationData = updatedPresentationData?.0 ?? context.sharedContext.currentPresentationData.with { $0 }
|
self.presentationData = updatedPresentationData?.0 ?? context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
let baseNavigationBarPresentationData = NavigationBarPresentationData(presentationData: self.presentationData)
|
let baseNavigationBarPresentationData = NavigationBarPresentationData(presentationData: self.presentationData)
|
||||||
|
|||||||
@ -120,7 +120,7 @@ private final class GiftContextPreviewComponent: Component {
|
|||||||
let subtitleSize = self.subtitle.update(
|
let subtitleSize = self.subtitle.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
component: AnyComponent(MultilineTextComponent(text: .plain(
|
component: AnyComponent(MultilineTextComponent(text: .plain(
|
||||||
NSAttributedString(string: "\(environment.strings.Gift_Unique_Collectible) #\(uniqueGift.number)", font: Font.regular(13.0), textColor: vibrantColor)
|
NSAttributedString(string: "\(environment.strings.Gift_Unique_Collectible) #\(presentationStringsFormattedNumber(uniqueGift.number, environment.dateTimeFormat.groupingSeparator))", font: Font.regular(13.0), textColor: vibrantColor)
|
||||||
))),
|
))),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: availableSize
|
containerSize: availableSize
|
||||||
|
|||||||
@ -240,6 +240,9 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func beginReordering() {
|
public func beginReordering() {
|
||||||
|
self.profileGifts.updateFilter(.All)
|
||||||
|
self.profileGifts.updateSorting(.date)
|
||||||
|
|
||||||
if let parentController = self.parentController as? PeerInfoScreen {
|
if let parentController = self.parentController as? PeerInfoScreen {
|
||||||
parentController.togglePaneIsReordering(isReordering: true)
|
parentController.togglePaneIsReordering(isReordering: true)
|
||||||
} else {
|
} else {
|
||||||
@ -469,7 +472,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if self.isReordering {
|
if self.isReordering {
|
||||||
if !product.pinnedToTop, let reference = product.reference, let items = self.starsProducts {
|
if case .unique = product.gift, !product.pinnedToTop, let reference = product.reference, let items = self.starsProducts {
|
||||||
if self.pinnedReferences.count >= self.maxPinnedCount {
|
if self.pinnedReferences.count >= self.maxPinnedCount {
|
||||||
self.parentController?.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.PeerInfo_Gifts_ToastPinLimit_Text(Int32(self.maxPinnedCount)), timeout: nil, customUndoText: nil), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
self.parentController?.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.PeerInfo_Gifts_ToastPinLimit_Text(Int32(self.maxPinnedCount)), timeout: nil, customUndoText: nil), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||||
return
|
return
|
||||||
@ -564,7 +567,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
itemFrame = itemFrame.size.centered(around: reorderingItem.position)
|
itemFrame = itemFrame.size.centered(around: reorderingItem.position)
|
||||||
isReordering = true
|
isReordering = true
|
||||||
}
|
}
|
||||||
if itemView.layer.animation(forKey: "position") != nil && !isReordering {
|
if self.isReordering, itemView.layer.animation(forKey: "position") != nil && !isReordering {
|
||||||
} else {
|
} else {
|
||||||
itemTransition.setFrame(view: itemView, frame: itemFrame)
|
itemTransition.setFrame(view: itemView, frame: itemFrame)
|
||||||
}
|
}
|
||||||
@ -612,8 +615,6 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
var bottomScrollInset: CGFloat = 0.0
|
var bottomScrollInset: CGFloat = 0.0
|
||||||
var contentHeight = ceil(CGFloat(starsProducts.count) / 3.0) * (starsOptionSize.height + optionSpacing) - optionSpacing + topInset + 16.0
|
var contentHeight = ceil(CGFloat(starsProducts.count) / 3.0) * (starsOptionSize.height + optionSpacing) - optionSpacing + topInset + 16.0
|
||||||
|
|
||||||
let transition = ComponentTransition.immediate
|
|
||||||
|
|
||||||
let size = params.size
|
let size = params.size
|
||||||
let sideInset = params.sideInset
|
let sideInset = params.sideInset
|
||||||
let bottomInset = params.bottomInset
|
let bottomInset = params.bottomInset
|
||||||
@ -681,8 +682,9 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
scrollOffset -= bottomPanelHeight
|
scrollOffset -= bottomPanelHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
transition.setFrame(view: panelButton.view, frame: CGRect(origin: CGPoint(x: buttonSideInset, y: size.height - bottomInset - buttonSize.height - scrollOffset), size: buttonSize))
|
let panelTransition = ComponentTransition.immediate
|
||||||
transition.setAlpha(view: panelButton.view, alpha: panelAlpha)
|
panelTransition.setFrame(view: panelButton.view, frame: CGRect(origin: CGPoint(x: buttonSideInset, y: size.height - bottomInset - buttonSize.height - scrollOffset), size: buttonSize))
|
||||||
|
panelTransition.setAlpha(view: panelButton.view, alpha: panelAlpha)
|
||||||
let _ = panelButton.updateLayout(width: buttonSize.width, transition: .immediate)
|
let _ = panelButton.updateLayout(width: buttonSize.width, transition: .immediate)
|
||||||
|
|
||||||
if self.canManage {
|
if self.canManage {
|
||||||
@ -753,16 +755,16 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
self.view.addSubview(panelCheckView)
|
self.view.addSubview(panelCheckView)
|
||||||
}
|
}
|
||||||
panelCheckView.frame = CGRect(origin: CGPoint(x: floor((size.width - panelCheckSize.width) / 2.0), y: size.height - bottomInset - panelCheckSize.height - 11.0 - scrollOffset), size: panelCheckSize)
|
panelCheckView.frame = CGRect(origin: CGPoint(x: floor((size.width - panelCheckSize.width) / 2.0), y: size.height - bottomInset - panelCheckSize.height - 11.0 - scrollOffset), size: panelCheckSize)
|
||||||
transition.setAlpha(view: panelCheckView, alpha: panelAlpha)
|
panelTransition.setAlpha(view: panelCheckView, alpha: panelAlpha)
|
||||||
}
|
}
|
||||||
panelButton.isHidden = true
|
panelButton.isHidden = true
|
||||||
}
|
}
|
||||||
|
|
||||||
transition.setFrame(view: panelBackground.view, frame: CGRect(x: 0.0, y: size.height - bottomPanelHeight - scrollOffset, width: size.width, height: bottomPanelHeight))
|
panelTransition.setFrame(view: panelBackground.view, frame: CGRect(x: 0.0, y: size.height - bottomPanelHeight - scrollOffset, width: size.width, height: bottomPanelHeight))
|
||||||
transition.setAlpha(view: panelBackground.view, alpha: panelAlpha)
|
panelTransition.setAlpha(view: panelBackground.view, alpha: panelAlpha)
|
||||||
panelBackground.update(size: CGSize(width: size.width, height: bottomPanelHeight), transition: transition.containedViewLayoutTransition)
|
panelBackground.update(size: CGSize(width: size.width, height: bottomPanelHeight), transition: transition.containedViewLayoutTransition)
|
||||||
transition.setFrame(view: panelSeparator.view, frame: CGRect(x: 0.0, y: size.height - bottomPanelHeight - scrollOffset, width: size.width, height: UIScreenPixel))
|
panelTransition.setFrame(view: panelSeparator.view, frame: CGRect(x: 0.0, y: size.height - bottomPanelHeight - scrollOffset, width: size.width, height: UIScreenPixel))
|
||||||
transition.setAlpha(view: panelSeparator.view, alpha: panelAlpha)
|
panelTransition.setAlpha(view: panelSeparator.view, alpha: panelAlpha)
|
||||||
|
|
||||||
let fadeTransition = ComponentTransition.easeInOut(duration: 0.25)
|
let fadeTransition = ComponentTransition.easeInOut(duration: 0.25)
|
||||||
if self.resultsAreEmpty {
|
if self.resultsAreEmpty {
|
||||||
@ -776,8 +778,8 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
|
|
||||||
self.emptyResultsClippingView.isHidden = false
|
self.emptyResultsClippingView.isHidden = false
|
||||||
|
|
||||||
transition.setFrame(view: self.emptyResultsClippingView, frame: CGRect(origin: CGPoint(x: 0.0, y: 48.0), size: self.scrollNode.frame.size))
|
panelTransition.setFrame(view: self.emptyResultsClippingView, frame: CGRect(origin: CGPoint(x: 0.0, y: 48.0), size: self.scrollNode.frame.size))
|
||||||
transition.setBounds(view: self.emptyResultsClippingView, bounds: CGRect(origin: CGPoint(x: 0.0, y: 48.0), size: self.scrollNode.frame.size))
|
panelTransition.setBounds(view: self.emptyResultsClippingView, bounds: CGRect(origin: CGPoint(x: 0.0, y: 48.0), size: self.scrollNode.frame.size))
|
||||||
|
|
||||||
let emptyResultsTitleSize = self.emptyResultsTitle.update(
|
let emptyResultsTitleSize = self.emptyResultsTitle.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
@ -840,7 +842,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
view.playOnce()
|
view.playOnce()
|
||||||
}
|
}
|
||||||
view.bounds = CGRect(origin: .zero, size: emptyResultsAnimationFrame.size)
|
view.bounds = CGRect(origin: .zero, size: emptyResultsAnimationFrame.size)
|
||||||
transition.setPosition(view: view, position: emptyResultsAnimationFrame.center)
|
panelTransition.setPosition(view: view, position: emptyResultsAnimationFrame.center)
|
||||||
}
|
}
|
||||||
if let view = self.emptyResultsTitle.view {
|
if let view = self.emptyResultsTitle.view {
|
||||||
if view.superview == nil {
|
if view.superview == nil {
|
||||||
@ -849,7 +851,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
self.emptyResultsClippingView.addSubview(view)
|
self.emptyResultsClippingView.addSubview(view)
|
||||||
}
|
}
|
||||||
view.bounds = CGRect(origin: .zero, size: emptyResultsTitleFrame.size)
|
view.bounds = CGRect(origin: .zero, size: emptyResultsTitleFrame.size)
|
||||||
transition.setPosition(view: view, position: emptyResultsTitleFrame.center)
|
panelTransition.setPosition(view: view, position: emptyResultsTitleFrame.center)
|
||||||
}
|
}
|
||||||
if let view = self.emptyResultsAction.view {
|
if let view = self.emptyResultsAction.view {
|
||||||
if view.superview == nil {
|
if view.superview == nil {
|
||||||
@ -858,7 +860,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
self.emptyResultsClippingView.addSubview(view)
|
self.emptyResultsClippingView.addSubview(view)
|
||||||
}
|
}
|
||||||
view.bounds = CGRect(origin: .zero, size: emptyResultsActionFrame.size)
|
view.bounds = CGRect(origin: .zero, size: emptyResultsActionFrame.size)
|
||||||
transition.setPosition(view: view, position: emptyResultsActionFrame.center)
|
panelTransition.setPosition(view: view, position: emptyResultsActionFrame.center)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let view = self.emptyResultsAnimation.view {
|
if let view = self.emptyResultsAnimation.view {
|
||||||
@ -879,7 +881,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.peerId == self.context.account.peerId {
|
if self.peerId == self.context.account.peerId, !self.resultsAreEmpty {
|
||||||
let footerText: ComponentView<Empty>
|
let footerText: ComponentView<Empty>
|
||||||
if let current = self.footerText {
|
if let current = self.footerText {
|
||||||
footerText = current
|
footerText = current
|
||||||
@ -941,21 +943,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
self.chatControllerInteraction.navigationController()?.pushViewController(controller)
|
self.chatControllerInteraction.navigationController()?.pushViewController(controller)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Birthday(id: self.peerId))
|
self.chatControllerInteraction.sendGift(self.peerId)
|
||||||
|> deliverOnMainQueue).start(next: { birthday in
|
|
||||||
var hasBirthday = false
|
|
||||||
if let birthday {
|
|
||||||
hasBirthday = hasBirthdayToday(birthday: birthday)
|
|
||||||
}
|
|
||||||
let controller = self.context.sharedContext.makeGiftOptionsController(
|
|
||||||
context: self.context,
|
|
||||||
peerId: self.peerId,
|
|
||||||
premiumOptions: [],
|
|
||||||
hasBirthday: hasBirthday,
|
|
||||||
completion: nil
|
|
||||||
)
|
|
||||||
self.chatControllerInteraction.navigationController()?.pushViewController(controller)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -424,7 +424,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
|||||||
isPaidMessage = true
|
isPaidMessage = true
|
||||||
titleText = strings.Stars_Transaction_PaidMessage(transaction.paidMessageCount ?? 1)
|
titleText = strings.Stars_Transaction_PaidMessage(transaction.paidMessageCount ?? 1)
|
||||||
countOnTop = true
|
countOnTop = true
|
||||||
descriptionText = strings.Stars_Transaction_PaidMessage_Text(formatPermille(starrefCommissionPermille)).string
|
descriptionText = strings.Stars_Transaction_PaidMessage_Text(formatPermille(1000 - starrefCommissionPermille)).string
|
||||||
} else if transaction.starrefPeerId == nil {
|
} else if transaction.starrefPeerId == nil {
|
||||||
titleText = strings.StarsTransaction_TitleCommission(formatPermille(starrefCommissionPermille)).string
|
titleText = strings.StarsTransaction_TitleCommission(formatPermille(starrefCommissionPermille)).string
|
||||||
countOnTop = false
|
countOnTop = false
|
||||||
|
|||||||
@ -29,6 +29,7 @@ final class StarsStatisticsScreenComponent: Component {
|
|||||||
let peerId: EnginePeer.Id
|
let peerId: EnginePeer.Id
|
||||||
let revenueContext: StarsRevenueStatsContext
|
let revenueContext: StarsRevenueStatsContext
|
||||||
let openTransaction: (StarsContext.State.Transaction) -> Void
|
let openTransaction: (StarsContext.State.Transaction) -> Void
|
||||||
|
let buy: () -> Void
|
||||||
let withdraw: () -> Void
|
let withdraw: () -> Void
|
||||||
let showTimeoutTooltip: (Int32) -> Void
|
let showTimeoutTooltip: (Int32) -> Void
|
||||||
let buyAds: () -> Void
|
let buyAds: () -> Void
|
||||||
@ -38,6 +39,7 @@ final class StarsStatisticsScreenComponent: Component {
|
|||||||
peerId: EnginePeer.Id,
|
peerId: EnginePeer.Id,
|
||||||
revenueContext: StarsRevenueStatsContext,
|
revenueContext: StarsRevenueStatsContext,
|
||||||
openTransaction: @escaping (StarsContext.State.Transaction) -> Void,
|
openTransaction: @escaping (StarsContext.State.Transaction) -> Void,
|
||||||
|
buy: @escaping () -> Void,
|
||||||
withdraw: @escaping () -> Void,
|
withdraw: @escaping () -> Void,
|
||||||
showTimeoutTooltip: @escaping (Int32) -> Void,
|
showTimeoutTooltip: @escaping (Int32) -> Void,
|
||||||
buyAds: @escaping () -> Void
|
buyAds: @escaping () -> Void
|
||||||
@ -46,6 +48,7 @@ final class StarsStatisticsScreenComponent: Component {
|
|||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
self.revenueContext = revenueContext
|
self.revenueContext = revenueContext
|
||||||
self.openTransaction = openTransaction
|
self.openTransaction = openTransaction
|
||||||
|
self.buy = buy
|
||||||
self.withdraw = withdraw
|
self.withdraw = withdraw
|
||||||
self.showTimeoutTooltip = showTimeoutTooltip
|
self.showTimeoutTooltip = showTimeoutTooltip
|
||||||
self.buyAds = buyAds
|
self.buyAds = buyAds
|
||||||
@ -508,7 +511,7 @@ final class StarsStatisticsScreenComponent: Component {
|
|||||||
)),
|
)),
|
||||||
footer: AnyComponent(MultilineTextComponent(
|
footer: AnyComponent(MultilineTextComponent(
|
||||||
text: .plain(NSAttributedString(
|
text: .plain(NSAttributedString(
|
||||||
string: strings.Stars_BotRevenue_Proceeds_Info,
|
string: component.peerId == component.context.account.peerId ? strings.Stars_AccountRevenue_Proceeds_Info : strings.Stars_BotRevenue_Proceeds_Info,
|
||||||
font: Font.regular(13.0),
|
font: Font.regular(13.0),
|
||||||
textColor: environment.theme.list.freeTextColor
|
textColor: environment.theme.list.freeTextColor
|
||||||
)),
|
)),
|
||||||
@ -558,8 +561,8 @@ final class StarsStatisticsScreenComponent: Component {
|
|||||||
return (TelegramTextAttributes.URL, contents)
|
return (TelegramTextAttributes.URL, contents)
|
||||||
})
|
})
|
||||||
|
|
||||||
let balanceInfoString = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString(strings.Stars_BotRevenue_Withdraw_Info, attributes: termsMarkdownAttributes, textAlignment: .natural
|
let balanceRawString = component.peerId == component.context.account.peerId ? strings.Stars_AccountRevenue_Withdraw_Info : strings.Stars_BotRevenue_Withdraw_Info
|
||||||
))
|
let balanceInfoString = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString(balanceRawString, attributes: termsMarkdownAttributes, textAlignment: .natural))
|
||||||
if self.cachedChevronImage == nil || self.cachedChevronImage?.1 !== environment.theme {
|
if self.cachedChevronImage == nil || self.cachedChevronImage?.1 !== environment.theme {
|
||||||
self.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Contact List/SubtitleArrow"), color: environment.theme.list.itemAccentColor)!, environment.theme)
|
self.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Contact List/SubtitleArrow"), color: environment.theme.list.itemAccentColor)!, environment.theme)
|
||||||
}
|
}
|
||||||
@ -567,37 +570,54 @@ final class StarsStatisticsScreenComponent: Component {
|
|||||||
balanceInfoString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: balanceInfoString.string))
|
balanceInfoString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: balanceInfoString.string))
|
||||||
}
|
}
|
||||||
|
|
||||||
let balanceSize = self.balanceView.update(
|
var balanceItems: [AnyComponentWithIdentity<Empty>] = []
|
||||||
transition: .immediate,
|
if component.peerId == component.context.account.peerId {
|
||||||
component: AnyComponent(ListSectionComponent(
|
let withdrawEnabled = self.starsState?.balances.withdrawEnabled ?? false
|
||||||
theme: environment.theme,
|
balanceItems = [
|
||||||
header: AnyComponent(MultilineTextComponent(
|
AnyComponentWithIdentity(id: 0, component: AnyComponent(
|
||||||
text: .plain(NSAttributedString(
|
StarsBalanceComponent(
|
||||||
string: strings.Stars_BotRevenue_Withdraw_Balance.uppercased(),
|
theme: environment.theme,
|
||||||
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
|
strings: strings,
|
||||||
textColor: environment.theme.list.freeTextColor
|
dateTimeFormat: environment.dateTimeFormat,
|
||||||
)),
|
count: self.starsState?.balances.availableBalance ?? StarsAmount.zero,
|
||||||
maximumNumberOfLines: 0
|
rate: self.starsState?.usdRate ?? 0,
|
||||||
)),
|
actionTitle: strings.Stars_Intro_BuyShort,
|
||||||
footer: AnyComponent(MultilineTextComponent(
|
actionAvailable: true,
|
||||||
text: .plain(balanceInfoString),
|
actionIsEnabled: true,
|
||||||
maximumNumberOfLines: 0,
|
actionIcon: PresentationResourcesItemList.itemListRoundTopupIcon(environment.theme),
|
||||||
highlightColor: environment.theme.list.itemAccentColor.withAlphaComponent(0.1),
|
action: { [weak self] in
|
||||||
highlightInset: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: -8.0),
|
guard let self, let component = self.component else {
|
||||||
highlightAction: { attributes in
|
return
|
||||||
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] {
|
}
|
||||||
return NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)
|
component.buy()
|
||||||
} else {
|
},
|
||||||
return nil
|
secondaryActionTitle: withdrawEnabled ? strings.Stars_Intro_Withdraw : nil,
|
||||||
|
secondaryActionIcon: PresentationResourcesItemList.itemListRoundWithdrawIcon(environment.theme),
|
||||||
|
secondaryActionCooldownUntilTimestamp: self.starsState?.balances.nextWithdrawalTimestamp,
|
||||||
|
secondaryAction: { [weak self] in
|
||||||
|
guard let self, let component = self.component else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var remainingCooldownSeconds: Int32 = 0
|
||||||
|
if let cooldownUntilTimestamp = self.starsState?.balances.nextWithdrawalTimestamp {
|
||||||
|
remainingCooldownSeconds = cooldownUntilTimestamp - Int32(Date().timeIntervalSince1970)
|
||||||
|
remainingCooldownSeconds = max(0, remainingCooldownSeconds)
|
||||||
|
|
||||||
|
if remainingCooldownSeconds > 0 {
|
||||||
|
component.showTimeoutTooltip(cooldownUntilTimestamp)
|
||||||
|
} else {
|
||||||
|
component.withdraw()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
component.withdraw()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
)
|
||||||
tapAction: { [weak self] attributes, _ in
|
))
|
||||||
if let controller = self?.controller?() as? StarsStatisticsScreen, let navigationController = controller.navigationController as? NavigationController {
|
]
|
||||||
component.context.sharedContext.openExternalUrl(context: component.context, urlContext: .generic, url: strings.Stars_BotRevenue_Withdraw_Info_URL, forceExternal: false, presentationData: presentationData, navigationController: navigationController, dismissInput: {})
|
} else {
|
||||||
}
|
balanceItems = [
|
||||||
}
|
AnyComponentWithIdentity(id: 0, component: AnyComponent(
|
||||||
)),
|
|
||||||
items: [AnyComponentWithIdentity(id: 0, component: AnyComponent(
|
|
||||||
StarsBalanceComponent(
|
StarsBalanceComponent(
|
||||||
theme: environment.theme,
|
theme: environment.theme,
|
||||||
strings: strings,
|
strings: strings,
|
||||||
@ -634,7 +654,41 @@ final class StarsStatisticsScreenComponent: Component {
|
|||||||
component.buyAds()
|
component.buyAds()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
))]
|
))
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
let balanceSize = self.balanceView.update(
|
||||||
|
transition: .immediate,
|
||||||
|
component: AnyComponent(ListSectionComponent(
|
||||||
|
theme: environment.theme,
|
||||||
|
header: AnyComponent(MultilineTextComponent(
|
||||||
|
text: .plain(NSAttributedString(
|
||||||
|
string: strings.Stars_BotRevenue_Withdraw_Balance.uppercased(),
|
||||||
|
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
|
||||||
|
textColor: environment.theme.list.freeTextColor
|
||||||
|
)),
|
||||||
|
maximumNumberOfLines: 0
|
||||||
|
)),
|
||||||
|
footer: AnyComponent(MultilineTextComponent(
|
||||||
|
text: .plain(balanceInfoString),
|
||||||
|
maximumNumberOfLines: 0,
|
||||||
|
highlightColor: environment.theme.list.itemAccentColor.withAlphaComponent(0.1),
|
||||||
|
highlightInset: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: -8.0),
|
||||||
|
highlightAction: { attributes in
|
||||||
|
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] {
|
||||||
|
return NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tapAction: { [weak self] attributes, _ in
|
||||||
|
if let controller = self?.controller?() as? StarsStatisticsScreen, let navigationController = controller.navigationController as? NavigationController {
|
||||||
|
component.context.sharedContext.openExternalUrl(context: component.context, urlContext: .generic, url: strings.Stars_BotRevenue_Withdraw_Info_URL, forceExternal: false, presentationData: presentationData, navigationController: navigationController, dismissInput: {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
items: balanceItems
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: CGSize(width: availableSize.width - sideInsets, height: availableSize.height)
|
containerSize: CGSize(width: availableSize.width - sideInsets, height: availableSize.height)
|
||||||
@ -799,11 +853,14 @@ public final class StarsStatisticsScreen: ViewControllerComponentContainer {
|
|||||||
private weak var tooltipScreen: UndoOverlayController?
|
private weak var tooltipScreen: UndoOverlayController?
|
||||||
private var timer: Foundation.Timer?
|
private var timer: Foundation.Timer?
|
||||||
|
|
||||||
|
private let options = Promise<[StarsTopUpOption]>()
|
||||||
|
|
||||||
public init(context: AccountContext, peerId: EnginePeer.Id, revenueContext: StarsRevenueStatsContext) {
|
public init(context: AccountContext, peerId: EnginePeer.Id, revenueContext: StarsRevenueStatsContext) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
self.revenueContext = revenueContext
|
self.revenueContext = revenueContext
|
||||||
|
|
||||||
|
var buyImpl: (() -> Void)?
|
||||||
var withdrawImpl: (() -> Void)?
|
var withdrawImpl: (() -> Void)?
|
||||||
var buyAdsImpl: (() -> Void)?
|
var buyAdsImpl: (() -> Void)?
|
||||||
var showTimeoutTooltipImpl: ((Int32) -> Void)?
|
var showTimeoutTooltipImpl: ((Int32) -> Void)?
|
||||||
@ -815,6 +872,9 @@ public final class StarsStatisticsScreen: ViewControllerComponentContainer {
|
|||||||
openTransaction: { transaction in
|
openTransaction: { transaction in
|
||||||
openTransactionImpl?(transaction)
|
openTransactionImpl?(transaction)
|
||||||
},
|
},
|
||||||
|
buy: {
|
||||||
|
buyImpl?()
|
||||||
|
},
|
||||||
withdraw: {
|
withdraw: {
|
||||||
withdrawImpl?()
|
withdrawImpl?()
|
||||||
},
|
},
|
||||||
@ -842,6 +902,46 @@ public final class StarsStatisticsScreen: ViewControllerComponentContainer {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if peerId == context.account.peerId {
|
||||||
|
self.options.set(.single([]) |> then(context.engine.payments.starsTopUpOptions()))
|
||||||
|
}
|
||||||
|
|
||||||
|
buyImpl = { [weak self] in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let _ = (self.options.get()
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] options in
|
||||||
|
guard let self, let starsContext = context.starsContext else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let controller = context.sharedContext.makeStarsPurchaseScreen(context: context, starsContext: starsContext, options: options, purpose: .generic, completion: { [weak self] stars in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
starsContext.add(balance: StarsAmount(value: stars, nanos: 0))
|
||||||
|
|
||||||
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
let resultController = UndoOverlayController(
|
||||||
|
presentationData: presentationData,
|
||||||
|
content: .universal(
|
||||||
|
animation: "StarsBuy",
|
||||||
|
scale: 0.066,
|
||||||
|
colors: [:],
|
||||||
|
title: presentationData.strings.Stars_Intro_PurchasedTitle,
|
||||||
|
text: presentationData.strings.Stars_Intro_PurchasedText(presentationData.strings.Stars_Intro_PurchasedText_Stars(Int32(stars))).string,
|
||||||
|
customUndoText: nil,
|
||||||
|
timeout: nil
|
||||||
|
),
|
||||||
|
elevatedLayout: false,
|
||||||
|
action: { _ in return true})
|
||||||
|
self.present(resultController, in: .window(.root))
|
||||||
|
})
|
||||||
|
self.push(controller)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
withdrawImpl = { [weak self] in
|
withdrawImpl = { [weak self] in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
|
|||||||
@ -312,7 +312,7 @@ final class StarsTransactionsListPanelComponent: Component {
|
|||||||
itemSubtitle = environment.strings.Stars_Intro_Transaction_PaidMessage(item.paidMessageCount ?? 1)
|
itemSubtitle = environment.strings.Stars_Intro_Transaction_PaidMessage(item.paidMessageCount ?? 1)
|
||||||
} else if let starGift = item.starGift {
|
} else if let starGift = item.starGift {
|
||||||
if item.flags.contains(.isStarGiftUpgrade), case let .unique(gift) = starGift {
|
if item.flags.contains(.isStarGiftUpgrade), case let .unique(gift) = starGift {
|
||||||
itemTitle = "\(gift.title) #\(gift.number)"
|
itemTitle = "\(gift.title) #\(presentationStringsFormattedNumber(gift.number, environment.dateTimeFormat.groupingSeparator))"
|
||||||
itemSubtitle = environment.strings.Stars_Intro_Transaction_GiftUpgrade
|
itemSubtitle = environment.strings.Stars_Intro_Transaction_GiftUpgrade
|
||||||
uniqueGift = gift
|
uniqueGift = gift
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -630,7 +630,7 @@ final class StarsTransactionsScreenComponent: Component {
|
|||||||
contentHeight += descriptionSize.height
|
contentHeight += descriptionSize.height
|
||||||
contentHeight += 29.0
|
contentHeight += 29.0
|
||||||
|
|
||||||
let withdrawAvailable = self.revenueState?.balances.withdrawEnabled ?? false
|
let withdrawAvailable = (self.revenueState?.balances.overallRevenue.value ?? 0) > 0
|
||||||
|
|
||||||
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: component.context.currentAppConfiguration.with { $0 })
|
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: component.context.currentAppConfiguration.with { $0 })
|
||||||
let balanceSize = self.balanceView.update(
|
let balanceSize = self.balanceView.update(
|
||||||
@ -656,26 +656,13 @@ final class StarsTransactionsScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
component.buy()
|
component.buy()
|
||||||
},
|
},
|
||||||
secondaryActionTitle: withdrawAvailable ? environment.strings.Stars_Intro_Withdraw : nil,
|
secondaryActionTitle: withdrawAvailable ? environment.strings.Stars_Intro_Stats : nil,
|
||||||
secondaryActionIcon: withdrawAvailable ? PresentationResourcesItemList.itemListRoundWithdrawIcon(environment.theme) : nil,
|
secondaryActionIcon: withdrawAvailable ? PresentationResourcesItemList.itemListStatsIcon(environment.theme) : nil,
|
||||||
secondaryActionCooldownUntilTimestamp: self.revenueState?.balances.nextWithdrawalTimestamp,
|
|
||||||
secondaryAction: withdrawAvailable ? { [weak self] in
|
secondaryAction: withdrawAvailable ? { [weak self] in
|
||||||
guard let self, let component = self.component else {
|
guard let self, let component = self.component else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var remainingCooldownSeconds: Int32 = 0
|
component.withdraw()
|
||||||
if let cooldownUntilTimestamp = self.revenueState?.balances.nextWithdrawalTimestamp {
|
|
||||||
remainingCooldownSeconds = cooldownUntilTimestamp - Int32(Date().timeIntervalSince1970)
|
|
||||||
remainingCooldownSeconds = max(0, remainingCooldownSeconds)
|
|
||||||
|
|
||||||
if remainingCooldownSeconds > 0 {
|
|
||||||
component.showTimeoutTooltip(cooldownUntilTimestamp)
|
|
||||||
} else {
|
|
||||||
component.withdraw()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
component.withdraw()
|
|
||||||
}
|
|
||||||
} : nil,
|
} : nil,
|
||||||
additionalAction: (premiumConfiguration.starsGiftsPurchaseAvailable && !premiumConfiguration.isPremiumDisabled) ? AnyComponent(
|
additionalAction: (premiumConfiguration.starsGiftsPurchaseAvailable && !premiumConfiguration.isPremiumDisabled) ? AnyComponent(
|
||||||
Button(
|
Button(
|
||||||
@ -739,7 +726,7 @@ final class StarsTransactionsScreenComponent: Component {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
let _ = (component.context.sharedContext.makeAffiliateProgramSetupScreenInitialData(context: component.context, peerId: component.context.account.peerId, mode: .connectedPrograms)
|
let _ = (component.context.sharedContext.makeAffiliateProgramSetupScreenInitialData(context: component.context, peerId: component.context.account.peerId, mode: .connectedPrograms)
|
||||||
|> deliverOnMainQueue).startStandalone(next: { [weak self] initialData in
|
|> deliverOnMainQueue).startStandalone(next: { [weak self] initialData in
|
||||||
guard let self, let component = self.component else {
|
guard let self, let component = self.component else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1236,48 +1223,52 @@ public final class StarsTransactionsScreen: ViewControllerComponentContainer {
|
|||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let _ = (context.engine.peers.checkStarsRevenueWithdrawalAvailability()
|
|
||||||
|> deliverOnMainQueue).start(error: { [weak self] error in
|
let controller = self.context.sharedContext.makeStarsStatisticsScreen(context: context, peerId: context.account.peerId, revenueContext: self.starsRevenueStatsContext)
|
||||||
guard let self else {
|
self.push(controller)
|
||||||
return
|
|
||||||
}
|
// let _ = (context.engine.peers.checkStarsRevenueWithdrawalAvailability()
|
||||||
switch error {
|
// |> deliverOnMainQueue).start(error: { [weak self] error in
|
||||||
case .serverProvided:
|
// guard let self else {
|
||||||
return
|
// return
|
||||||
case .requestPassword:
|
// }
|
||||||
let _ = (self.starsRevenueStatsContext.state
|
// switch error {
|
||||||
|> take(1)
|
// case .serverProvided:
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] state in
|
// return
|
||||||
guard let self else {
|
// case .requestPassword:
|
||||||
return
|
// let _ = (self.starsRevenueStatsContext.state
|
||||||
}
|
// |> take(1)
|
||||||
let controller = self.context.sharedContext.makeStarsWithdrawalScreen(context: context, completion: { [weak self] amount in
|
// |> deliverOnMainQueue).start(next: { [weak self] state in
|
||||||
guard let self else {
|
// guard let self else {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
let controller = confirmStarsRevenueWithdrawalController(context: context, peerId: context.account.peerId, amount: amount, present: { [weak self] c, a in
|
// let controller = self.context.sharedContext.makeStarsWithdrawalScreen(context: context, completion: { [weak self] amount in
|
||||||
self?.present(c, in: .window(.root))
|
// guard let self else {
|
||||||
}, completion: { [weak self] url in
|
// return
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
// }
|
||||||
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: url, forceExternal: true, presentationData: presentationData, navigationController: nil, dismissInput: {})
|
// let controller = confirmStarsRevenueWithdrawalController(context: context, peerId: context.account.peerId, amount: amount, present: { [weak self] c, a in
|
||||||
|
// self?.present(c, in: .window(.root))
|
||||||
Queue.mainQueue().after(2.0) {
|
// }, completion: { [weak self] url in
|
||||||
self?.starsRevenueStatsContext.reload()
|
// let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
}
|
// context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: url, forceExternal: true, presentationData: presentationData, navigationController: nil, dismissInput: {})
|
||||||
})
|
//
|
||||||
self.present(controller, in: .window(.root))
|
// Queue.mainQueue().after(2.0) {
|
||||||
})
|
// self?.starsRevenueStatsContext.reload()
|
||||||
self.push(controller)
|
// }
|
||||||
})
|
// })
|
||||||
default:
|
// self.present(controller, in: .window(.root))
|
||||||
let controller = starsRevenueWithdrawalController(context: context, peerId: context.account.peerId, amount: 0, initialError: error, present: { [weak self] c, a in
|
// })
|
||||||
self?.present(c, in: .window(.root))
|
// self.push(controller)
|
||||||
}, completion: { _ in
|
// })
|
||||||
|
// default:
|
||||||
})
|
// let controller = starsRevenueWithdrawalController(context: context, peerId: context.account.peerId, amount: 0, initialError: error, present: { [weak self] c, a in
|
||||||
self.present(controller, in: .window(.root))
|
// self?.present(c, in: .window(.root))
|
||||||
}
|
// }, completion: { _ in
|
||||||
})
|
//
|
||||||
|
// })
|
||||||
|
// self.present(controller, in: .window(.root))
|
||||||
|
// }
|
||||||
|
// })
|
||||||
}
|
}
|
||||||
|
|
||||||
showTimeoutTooltipImpl = { [weak self] cooldownUntilTimestamp in
|
showTimeoutTooltipImpl = { [weak self] cooldownUntilTimestamp in
|
||||||
|
|||||||
12
submodules/TelegramUI/Images.xcassets/Premium/Stars/Stats.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Premium/Stars/Stats.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "stats_24.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
submodules/TelegramUI/Images.xcassets/Premium/Stars/Stats.imageset/stats_24.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Premium/Stars/Stats.imageset/stats_24.pdf
vendored
Normal file
Binary file not shown.
@ -15,7 +15,7 @@ import TelegramPresentationData
|
|||||||
import TelegramNotices
|
import TelegramNotices
|
||||||
|
|
||||||
extension ChatControllerImpl {
|
extension ChatControllerImpl {
|
||||||
func presentPaidMessageAlertIfNeeded(count: Int32 = 1, forceDark: Bool = false, completion: @escaping (Bool) -> Void) {
|
func presentPaidMessageAlertIfNeeded(count: Int32 = 1, forceDark: Bool = false, alwaysAsk: Bool = false, completion: @escaping (Bool) -> Void) {
|
||||||
guard let peer = self.presentationInterfaceState.renderedPeer?.peer.flatMap(EnginePeer.init) else {
|
guard let peer = self.presentationInterfaceState.renderedPeer?.peer.flatMap(EnginePeer.init) else {
|
||||||
completion(false)
|
completion(false)
|
||||||
return
|
return
|
||||||
@ -24,11 +24,12 @@ extension ChatControllerImpl {
|
|||||||
let totalAmount = sendPaidMessageStars.value * Int64(count)
|
let totalAmount = sendPaidMessageStars.value * Int64(count)
|
||||||
|
|
||||||
let _ = (ApplicationSpecificNotice.dismissedPaidMessageWarningNamespace(accountManager: self.context.sharedContext.accountManager, peerId: peer.id)
|
let _ = (ApplicationSpecificNotice.dismissedPaidMessageWarningNamespace(accountManager: self.context.sharedContext.accountManager, peerId: peer.id)
|
||||||
|
|> take(1)
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] dismissedAmount in
|
|> deliverOnMainQueue).start(next: { [weak self] dismissedAmount in
|
||||||
guard let self, let starsContext = self.context.starsContext else {
|
guard let self, let starsContext = self.context.starsContext else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if let dismissedAmount, dismissedAmount == sendPaidMessageStars.value, let currentState = starsContext.currentState, currentState.balance.value > totalAmount {
|
if !alwaysAsk, let dismissedAmount, dismissedAmount == sendPaidMessageStars.value, let currentState = starsContext.currentState, currentState.balance.value > totalAmount {
|
||||||
if count < 3 && totalAmount < 100 {
|
if count < 3 && totalAmount < 100 {
|
||||||
completion(false)
|
completion(false)
|
||||||
} else {
|
} else {
|
||||||
@ -52,6 +53,7 @@ extension ChatControllerImpl {
|
|||||||
count: count,
|
count: count,
|
||||||
amount: sendPaidMessageStars,
|
amount: sendPaidMessageStars,
|
||||||
totalAmount: nil,
|
totalAmount: nil,
|
||||||
|
hasCheck: !alwaysAsk,
|
||||||
navigationController: self.navigationController as? NavigationController,
|
navigationController: self.navigationController as? NavigationController,
|
||||||
completion: { [weak self] dontAskAgain in
|
completion: { [weak self] dontAskAgain in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
|
|||||||
@ -3140,19 +3140,29 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
actions.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_MessageDialogRetry, icon: { theme in
|
actions.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_MessageDialogRetry, icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Resend"), color: theme.actionSheet.primaryTextColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Resend"), color: theme.actionSheet.primaryTextColor)
|
||||||
}, action: { [weak self] _, f in
|
}, action: { [weak self] _, f in
|
||||||
if let strongSelf = self {
|
if let self {
|
||||||
let _ = resendMessages(account: strongSelf.context.account, messageIds: selectedGroup.map({ $0.id })).startStandalone()
|
self.presentPaidMessageAlertIfNeeded(count: Int32(selectedGroup.count), alwaysAsk: true, completion: { [weak self] _ in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let _ = resendMessages(account: self.context.account, messageIds: selectedGroup.map({ $0.id })).startStandalone()
|
||||||
|
})
|
||||||
|
f(self.presentationInterfaceState.sendPaidMessageStars == nil ? .dismissWithoutContent : .default)
|
||||||
}
|
}
|
||||||
f(.dismissWithoutContent)
|
|
||||||
})))
|
})))
|
||||||
if totalGroupCount != 1 {
|
if totalGroupCount != 1 {
|
||||||
actions.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_MessageDialogRetryAll(totalGroupCount).string, icon: { theme in
|
actions.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_MessageDialogRetryAll(totalGroupCount).string, icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Resend"), color: theme.actionSheet.primaryTextColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Resend"), color: theme.actionSheet.primaryTextColor)
|
||||||
}, action: { [weak self] _, f in
|
}, action: { [weak self] _, f in
|
||||||
if let strongSelf = self {
|
if let self {
|
||||||
let _ = resendMessages(account: strongSelf.context.account, messageIds: messages.map({ $0.id })).startStandalone()
|
self.presentPaidMessageAlertIfNeeded(count: Int32(messages.count), alwaysAsk: true, completion: { [weak self] _ in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let _ = resendMessages(account: self.context.account, messageIds: messages.map({ $0.id })).startStandalone()
|
||||||
|
})
|
||||||
|
f(self.presentationInterfaceState.sendPaidMessageStars == nil ? .dismissWithoutContent : .default)
|
||||||
}
|
}
|
||||||
f(.dismissWithoutContent)
|
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
actions.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_ContextMenuDelete, textColor: .destructive, icon: { theme in
|
actions.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_ContextMenuDelete, textColor: .destructive, icon: { theme in
|
||||||
|
|||||||
@ -620,7 +620,7 @@ extension ChatControllerImpl {
|
|||||||
if let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer, let starsContext = context.starsContext {
|
if let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer, let starsContext = context.starsContext {
|
||||||
let premiumGiftOptions = strongSelf.presentationInterfaceState.premiumGiftOptions
|
let premiumGiftOptions = strongSelf.presentationInterfaceState.premiumGiftOptions
|
||||||
if !premiumGiftOptions.isEmpty {
|
if !premiumGiftOptions.isEmpty {
|
||||||
let controller = PremiumGiftAttachmentScreen(context: context, starsContext: starsContext, peerId: peer.id, premiumOptions: premiumGiftOptions, hasBirthday: true, completion: { [weak self] in
|
let controller = PremiumGiftAttachmentScreen(context: context, starsContext: starsContext, peerId: peer.id, premiumOptions: premiumGiftOptions, hasBirthday: strongSelf.presentationInterfaceState.hasBirthdayToday, completion: { [weak self] in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -146,6 +146,9 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
|||||||
))
|
))
|
||||||
} else if chatSelection.disableChannels || chatSelection.disableBots {
|
} else if chatSelection.disableChannels || chatSelection.disableBots {
|
||||||
var categories: ChatListFilterPeerCategories = [.contacts, .nonContacts, .groups, .bots, .channels]
|
var categories: ChatListFilterPeerCategories = [.contacts, .nonContacts, .groups, .bots, .channels]
|
||||||
|
if chatSelection.disableContacts {
|
||||||
|
categories.remove(.contacts)
|
||||||
|
}
|
||||||
if chatSelection.disableChannels {
|
if chatSelection.disableChannels {
|
||||||
categories.remove(.channels)
|
categories.remove(.channels)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -971,6 +971,11 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
if groupCallController.view.superview == nil {
|
if groupCallController.view.superview == nil {
|
||||||
(mainWindow.viewController as? NavigationController)?.pushViewController(groupCallController)
|
(mainWindow.viewController as? NavigationController)?.pushViewController(groupCallController)
|
||||||
}
|
}
|
||||||
|
} else if let streamController = self.streamController {
|
||||||
|
mainWindow.hostView.containerView.endEditing(true)
|
||||||
|
if streamController.view.superview == nil {
|
||||||
|
(mainWindow.viewController as? NavigationController)?.pushViewController(streamController)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1357,8 +1362,23 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
let streamController = MediaStreamComponentController(call: group)
|
let streamController = MediaStreamComponentController(call: group)
|
||||||
streamController.navigationPresentation = .flatModal
|
streamController.navigationPresentation = .flatModal
|
||||||
streamController.parentNavigationController = navigationController
|
streamController.parentNavigationController = navigationController
|
||||||
|
|
||||||
|
let thisCallIsOnScreenPromise = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||||
|
streamController.onViewDidAppear = {
|
||||||
|
thisCallIsOnScreenPromise.set(true)
|
||||||
|
}
|
||||||
|
streamController.onViewDidDisappear = {
|
||||||
|
thisCallIsOnScreenPromise.set(false)
|
||||||
|
}
|
||||||
|
|
||||||
self.streamController = streamController
|
self.streamController = streamController
|
||||||
|
|
||||||
|
self.mainWindow?.hostView.containerView.endEditing(true)
|
||||||
|
|
||||||
|
thisCallIsOnScreenPromise.set(true)
|
||||||
|
self.hasGroupCallOnScreenPromise.set(thisCallIsOnScreenPromise.get())
|
||||||
|
beginDisplayingCallStatusBar.set(.single(Void()))
|
||||||
|
|
||||||
navigationController.pushViewController(streamController)
|
navigationController.pushViewController(streamController)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1786,6 +1806,11 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
mainWindow.hostView.containerView.endEditing(true)
|
mainWindow.hostView.containerView.endEditing(true)
|
||||||
(mainWindow.viewController as? NavigationController)?.pushViewController(groupCallController)
|
(mainWindow.viewController as? NavigationController)?.pushViewController(groupCallController)
|
||||||
}
|
}
|
||||||
|
} else if let streamController = self.streamController {
|
||||||
|
if streamController.isNodeLoaded && streamController.view.superview == nil {
|
||||||
|
mainWindow.hostView.containerView.endEditing(true)
|
||||||
|
(mainWindow.viewController as? NavigationController)?.pushViewController(streamController)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2905,7 +2930,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
Queue.mainQueue().after(0.3) {
|
Queue.mainQueue().after(0.3) {
|
||||||
let tooltipController = UndoOverlayController(
|
let tooltipController = UndoOverlayController(
|
||||||
presentationData: presentationData,
|
presentationData: presentationData,
|
||||||
content: .forward(savedMessages: false, text: presentationData.strings.Gift_Transfer_Success("\(gift.title) #\(gift.number)", peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string),
|
content: .forward(savedMessages: false, text: presentationData.strings.Gift_Transfer_Success("\(gift.title) #\(presentationStringsFormattedNumber(gift.number, presentationData.dateTimeFormat.groupingSeparator))", peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string),
|
||||||
elevatedLayout: false,
|
elevatedLayout: false,
|
||||||
action: { _ in return true }
|
action: { _ in return true }
|
||||||
)
|
)
|
||||||
|
|||||||
@ -65,10 +65,10 @@ function tgBrowserHandleMutations(mutations) {
|
|||||||
if (mutation.addedNodes && mutation.addedNodes.length > 0) {
|
if (mutation.addedNodes && mutation.addedNodes.length > 0) {
|
||||||
mutation.addedNodes.forEach((newNode) => {
|
mutation.addedNodes.forEach((newNode) => {
|
||||||
if (newNode.tagName === 'VIDEO') {
|
if (newNode.tagName === 'VIDEO') {
|
||||||
disableWebkitEnterFullscreen(newNode);
|
tgBrowserDisableWebkitEnterFullscreen(newNode);
|
||||||
}
|
}
|
||||||
if (newNode.querySelectorAll) {
|
if (newNode.querySelectorAll) {
|
||||||
newNode.querySelectorAll('video').forEach(disableWebkitEnterFullscreen);
|
newNode.querySelectorAll('video').forEach(tgBrowserDisableWebkitEnterFullscreen);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user