diff --git a/submodules/PeerInfoUI/Sources/ChannelAdminsController.swift b/submodules/PeerInfoUI/Sources/ChannelAdminsController.swift index 0e97f1f4f4..2289970d80 100644 --- a/submodules/PeerInfoUI/Sources/ChannelAdminsController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelAdminsController.swift @@ -496,8 +496,8 @@ private func channelAdminsControllerEntries(presentationData: PresentationData, if !isGroup && peer.hasPermission(.sendSomething) { entries.append(.signMessages(presentationData.theme, presentationData.strings.Channel_SignMessages, signMessagesEnabled, showAuthorProfilesEnabled)) - entries.append(.showAuthorProfiles(presentationData.theme, presentationData.strings.Channel_ShowAuthors, showAuthorProfilesEnabled, signMessagesEnabled)) if signMessagesEnabled { + entries.append(.showAuthorProfiles(presentationData.theme, presentationData.strings.Channel_ShowAuthors, showAuthorProfilesEnabled, signMessagesEnabled)) entries.append(.signMessagesInfo(presentationData.theme, presentationData.strings.Channel_ShowAuthorsFooter)) } } diff --git a/submodules/TelegramCore/Sources/PendingMessages/EnqueueMessage.swift b/submodules/TelegramCore/Sources/PendingMessages/EnqueueMessage.swift index 4a04ad0d1e..ea326708b0 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/EnqueueMessage.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/EnqueueMessage.swift @@ -742,11 +742,16 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId, if messageNamespace != Namespaces.Message.ScheduledLocal && messageNamespace != Namespaces.Message.QuickReplyLocal { attributes.append(ViewCountMessageAttribute(count: 1)) } - if info.flags.contains(.messagesShouldHaveSignatures) { - attributes.append(AuthorSignatureMessageAttribute(signature: accountPeer.debugDisplayTitle)) - } if info.flags.contains(.messagesShouldHaveProfiles) { - authorId = account.peerId + if sendAsPeer == nil { + authorId = account.peerId + } + } + if info.flags.contains(.messagesShouldHaveSignatures) { + if let sendAsPeer, sendAsPeer.id == peerId { + } else { + attributes.append(AuthorSignatureMessageAttribute(signature: accountPeer.debugDisplayTitle)) + } } case .group: break diff --git a/submodules/TelegramCore/Sources/State/AccountStateManager.swift b/submodules/TelegramCore/Sources/State/AccountStateManager.swift index f2f7f5321f..1ae6baf6ea 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManager.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManager.swift @@ -292,6 +292,11 @@ public final class AccountStateManager { return self.botPreviewUpdatesPipe.signal() } + fileprivate let forceSendPendingStarsReactionPipe = ValuePipe() + public var forceSendPendingStarsReaction: Signal { + return self.forceSendPendingStarsReactionPipe.signal() + } + private var updatedWebpageContexts: [MediaId: UpdatedWebpageSubscriberContext] = [:] private var updatedPeersNearbyContext = UpdatedPeersNearbySubscriberContext() private var updatedRevenueBalancesContext = UpdatedRevenueBalancesSubscriberContext() @@ -1873,11 +1878,25 @@ public final class AccountStateManager { } } + var forceSendPendingStarsReaction: Signal { + return self.impl.signalWith { impl, subscriber in + return impl.forceSendPendingStarsReaction.start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion) + } + } + + func forceSendPendingStarsReaction(messageId: MessageId) { + self.impl.with { impl in + impl.forceSendPendingStarsReactionPipe.putNext(messageId) + } + } + var updateConfigRequested: (() -> Void)? var isPremiumUpdated: (() -> Void)? let messagesRemovedContext = MessagesRemovedContext() + public weak var starsContext: StarsContext? + init( accountPeerId: PeerId, accountManager: AccountManager, diff --git a/submodules/TelegramCore/Sources/State/MessageReactions.swift b/submodules/TelegramCore/Sources/State/MessageReactions.swift index 97ea3f2d53..9aa3c8f31a 100644 --- a/submodules/TelegramCore/Sources/State/MessageReactions.swift +++ b/submodules/TelegramCore/Sources/State/MessageReactions.swift @@ -220,6 +220,12 @@ func cancelPendingSendStarsReactionInteractively(account: Account, messageId: Me |> ignoreValues } +func _internal_forceSendPendingSendStarsReaction(account: Account, messageId: MessageId) -> Signal { + account.stateManager.forceSendPendingStarsReaction(messageId: messageId) + + return .complete() +} + func _internal_updateStarsReactionIsAnonymous(account: Account, messageId: MessageId, isAnonymous: Bool) -> Signal { return account.postbox.transaction { transaction -> Api.InputPeer? in transaction.updateMessage(messageId, update: { currentMessage in @@ -388,6 +394,9 @@ private func requestSendStarsReaction(postbox: Postbox, network: Network, stateM return .generic } |> mapToSignal { result -> Signal in + stateManager.starsContext?.add(balance: Int64(-count), addTransaction: false) + //stateManager.starsContext?.load(force: true) + return postbox.transaction { transaction -> Void in transaction.setPendingMessageAction(type: .sendStarsReaction, id: messageId, action: UpdateMessageReactionsAction()) transaction.updateMessage(messageId, update: { currentMessage in @@ -568,8 +577,20 @@ func managedApplyPendingMessageStarsReactionsActions(postbox: Postbox, network: let signal = withTakenStarsAction(postbox: postbox, type: .sendStarsReaction, id: entry.id, { transaction, entry -> Signal in if let entry = entry { if let _ = entry.action as? SendStarsReactionsAction { - return synchronizeMessageStarsReactions(transaction: transaction, postbox: postbox, network: network, stateManager: stateManager, id: entry.id) - |> delay(5.0, queue: .mainQueue()) + let triggerSignal: Signal = stateManager.forceSendPendingStarsReaction + |> filter { + $0 == entry.id + } + |> map { _ -> Void in + return Void() + } + |> take(1) + |> timeout(5.0, queue: .mainQueue(), alternate: .single(Void())) + + return triggerSignal + |> mapToSignal { _ -> Signal in + return synchronizeMessageStarsReactions(transaction: transaction, postbox: postbox, network: network, stateManager: stateManager, id: entry.id) + } } else { assertionFailure() } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift index 3031c0b69a..8979290338 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift @@ -342,6 +342,10 @@ public extension TelegramEngine { let _ = cancelPendingSendStarsReactionInteractively(account: self.account, messageId: id).startStandalone() } + public func forceSendPendingSendStarsReaction(id: EngineMessage.Id) { + let _ = _internal_forceSendPendingSendStarsReaction(account: self.account, messageId: id).startStandalone() + } + public func updateStarsReactionIsAnonymous(id: EngineMessage.Id, isAnonymous: Bool) -> Signal { return _internal_updateStarsReactionIsAnonymous(account: self.account, messageId: id, isAnonymous: isAnonymous) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift index 714e87683e..3a8fabd8e2 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift @@ -338,14 +338,16 @@ private final class StarsContextImpl { })) } - func add(balance: Int64) { + func add(balance: Int64, addTransaction: Bool) { guard let state = self._state else { return } var transactions = state.transactions - transactions.insert(.init(flags: [.isLocal], id: "\(arc4random())", count: balance, date: Int32(Date().timeIntervalSince1970), peer: .appStore, title: nil, description: nil, photo: nil, transactionDate: nil, transactionUrl: nil, paidMessageId: nil, media: [], subscriptionPeriod: nil), at: 0) + if addTransaction { + transactions.insert(.init(flags: [.isLocal], id: "\(arc4random())", count: balance, date: Int32(Date().timeIntervalSince1970), peer: .appStore, title: nil, description: nil, photo: nil, transactionDate: nil, transactionUrl: nil, paidMessageId: nil, media: [], subscriptionPeriod: nil), at: 0) + } - self.updateState(StarsContext.State(flags: [.isPendingBalance], balance: state.balance + balance, subscriptions: state.subscriptions, canLoadMoreSubscriptions: state.canLoadMoreSubscriptions, transactions: transactions, canLoadMoreTransactions: state.canLoadMoreTransactions, isLoading: state.isLoading)) + self.updateState(StarsContext.State(flags: [.isPendingBalance], balance: max(0, state.balance + balance), subscriptions: state.subscriptions, canLoadMoreSubscriptions: state.canLoadMoreSubscriptions, transactions: transactions, canLoadMoreTransactions: state.canLoadMoreTransactions, isLoading: state.isLoading)) } fileprivate func updateBalance(_ balance: Int64, transactions: [StarsContext.State.Transaction]?) { @@ -696,9 +698,9 @@ public final class StarsContext { return state } - public func add(balance: Int64) { + public func add(balance: Int64, addTransaction: Bool = true) { self.impl.with { - $0.add(balance: balance) + $0.add(balance: balance, addTransaction: addTransaction) } } diff --git a/submodules/TelegramCore/Sources/Utils/MessageUtils.swift b/submodules/TelegramCore/Sources/Utils/MessageUtils.swift index 0239fa5ea3..acc484da19 100644 --- a/submodules/TelegramCore/Sources/Utils/MessageUtils.swift +++ b/submodules/TelegramCore/Sources/Utils/MessageUtils.swift @@ -344,10 +344,8 @@ public extension Message { return false } } else if self.author?.id == accountPeerId { - if let channel = self.peers[self.id.peerId] as? TelegramChannel, case let .broadcast(info) = channel.info { - if !info.flags.contains(.messagesShouldHaveProfiles) { - return true - } + if let channel = self.peers[self.id.peerId] as? TelegramChannel, case .broadcast = channel.info { + return true } return false } else if self.flags.contains(.Incoming) { diff --git a/submodules/TelegramUI/Components/Chat/ChatSendStarsScreen/Sources/ChatSendStarsScreen.swift b/submodules/TelegramUI/Components/Chat/ChatSendStarsScreen/Sources/ChatSendStarsScreen.swift index b4820d474b..2085326af0 100644 --- a/submodules/TelegramUI/Components/Chat/ChatSendStarsScreen/Sources/ChatSendStarsScreen.swift +++ b/submodules/TelegramUI/Components/Chat/ChatSendStarsScreen/Sources/ChatSendStarsScreen.swift @@ -958,6 +958,7 @@ private final class ChatSendStarsScreenComponent: Component { private var topOffsetDistance: CGFloat? + private var balance: Int64? private var amount: Int64 = 1 private var isAnonymous: Bool = false private var cachedStarImage: (UIImage, PresentationTheme)? @@ -965,6 +966,8 @@ private final class ChatSendStarsScreenComponent: Component { private var isPastTopCutoff: Bool? + private var balanceDisposable: Disposable? + override init(frame: CGRect) { self.bottomOverscrollLimit = 200.0 @@ -1019,6 +1022,10 @@ private final class ChatSendStarsScreenComponent: Component { fatalError("init(coder:) has not been implemented") } + deinit { + self.balanceDisposable?.dispose() + } + func scrollViewDidScroll(_ scrollView: UIScrollView) { if !self.ignoreScrolling { self.updateScrolling(transition: .immediate) @@ -1127,10 +1134,26 @@ private final class ChatSendStarsScreenComponent: Component { let sideInset: CGFloat = 16.0 if self.component == nil { + self.balance = component.balance self.amount = 50 if let myTopPeer = component.myTopPeer { self.isAnonymous = myTopPeer.isAnonymous } + + if let starsContext = component.context.starsContext { + self.balanceDisposable = (starsContext.state + |> deliverOnMainQueue).startStrict(next: { [weak self] state in + guard let self else { + return + } + if let state { + if self.balance != state.balance { + self.balance = state.balance + self.state?.updated(transition: .immediate) + } + } + }) + } } self.component = component @@ -1335,7 +1358,7 @@ private final class ChatSendStarsScreenComponent: Component { context: component.context, theme: environment.theme, strings: environment.strings, - balance: component.balance + balance: self.balance )), environment: {}, containerSize: CGSize(width: 120.0, height: 100.0) @@ -1751,7 +1774,7 @@ private final class ChatSendStarsScreenComponent: Component { guard let self, let component = self.component else { return } - guard let balance = component.balance else { + guard let balance = self.balance else { return } diff --git a/submodules/TelegramUI/Components/SpaceWarpView/BUILD b/submodules/TelegramUI/Components/SpaceWarpView/BUILD index bfa7fe65eb..2118beea58 100644 --- a/submodules/TelegramUI/Components/SpaceWarpView/BUILD +++ b/submodules/TelegramUI/Components/SpaceWarpView/BUILD @@ -14,6 +14,7 @@ swift_library( "//submodules/AsyncDisplayKit", "//submodules/ComponentFlow", "//submodules/TelegramUI/Components/SpaceWarpView/STCMeshView", + "//submodules/UIKitRuntimeUtils", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/SpaceWarpView/Sources/SpaceWarpView.swift b/submodules/TelegramUI/Components/SpaceWarpView/Sources/SpaceWarpView.swift index 07db642530..e9f6392579 100644 --- a/submodules/TelegramUI/Components/SpaceWarpView/Sources/SpaceWarpView.swift +++ b/submodules/TelegramUI/Components/SpaceWarpView/Sources/SpaceWarpView.swift @@ -4,6 +4,7 @@ import Display import AsyncDisplayKit import ComponentFlow import STCMeshView +import UIKitRuntimeUtils private final class FPSView: UIView { private var lastTimestamp: Double? @@ -327,6 +328,49 @@ private final class MaskGridLayer: SimpleLayer { } } +private final class PrivateContentLayerRestoreContext { + final class Reference { + weak var layer: CALayer? + + init(layer: CALayer) { + self.layer = layer + } + } + + private static func collectPrivateContentLayers(layer: CALayer, into references: inout [Reference]) { + if getLayerDisableScreenshots(layer) { + references.append(Reference(layer: layer)) + } + if let sublayers = layer.sublayers { + for sublayer in sublayers { + collectPrivateContentLayers(layer: sublayer, into: &references) + } + } + } + + private let references: [Reference] + + init(rootLayer: CALayer) { + var references: [Reference] = [] + PrivateContentLayerRestoreContext.collectPrivateContentLayers(layer: rootLayer, into: &references) + self.references = references + + for reference in self.references { + if let layer = reference.layer { + setLayerDisableScreenshots(layer, false) + } + } + } + + func restore() { + for reference in self.references { + if let layer = reference.layer { + setLayerDisableScreenshots(layer, true) + } + } + } +} + open class SpaceWarpNodeImpl: ASDisplayNode, SpaceWarpNode { private final class Shockwave { let startPoint: CGPoint @@ -346,6 +390,8 @@ open class SpaceWarpNodeImpl: ASDisplayNode, SpaceWarpNode { private var currentCloneView: UIView? private var meshView: STCMeshView? + private var privateContentRestoreContext: PrivateContentLayerRestoreContext? + private var gradientLayer: SimpleGradientLayer? private var gradientMaskLayer: MaskGridLayer? @@ -382,7 +428,25 @@ open class SpaceWarpNodeImpl: ASDisplayNode, SpaceWarpNode { #endif } + public static func supportsHierarchy(layer: CALayer) -> Bool { + if getLayerDisableScreenshots(layer) { + return false + } + if let sublayers = layer.sublayers { + for sublayer in sublayers { + if !supportsHierarchy(layer: sublayer) { + return false + } + } + } + return true + } + public func triggerRipple(at point: CGPoint) { + if !SpaceWarpNodeImpl.supportsHierarchy(layer: self.contentNodeSource.view.layer) { + return + } + self.shockwaves.append(Shockwave(startPoint: point)) if self.shockwaves.count > 8 { self.shockwaves.removeFirst() @@ -480,9 +544,18 @@ open class SpaceWarpNodeImpl: ASDisplayNode, SpaceWarpNode { gradientMaskLayer.removeFromSuperlayer() } + if let privateContentRestoreContext = self.privateContentRestoreContext { + self.privateContentRestoreContext = nil + privateContentRestoreContext.restore() + } + return } + if self.privateContentRestoreContext == nil { + self.privateContentRestoreContext = PrivateContentLayerRestoreContext(rootLayer: self.contentNodeSource.view.layer) + } + self.backgroundView.isHidden = false self.contentNodeSource.clipsToBounds = true self.contentNodeSource.layer.cornerRadius = cornerRadius diff --git a/submodules/TelegramUI/Sources/AccountContext.swift b/submodules/TelegramUI/Sources/AccountContext.swift index 57272623f8..25f96e9251 100644 --- a/submodules/TelegramUI/Sources/AccountContext.swift +++ b/submodules/TelegramUI/Sources/AccountContext.swift @@ -304,6 +304,8 @@ public final class AccountContextImpl: AccountContext { self.starsContext = nil } + self.account.stateManager.starsContext = self.starsContext + if let locationManager = self.sharedContextImpl.locationManager, sharedContext.applicationBindings.isMainApp && !temp { self.peersNearbyManager = PeersNearbyManagerImpl(account: account, engine: self.engine, locationManager: locationManager, inForeground: sharedContext.applicationBindings.applicationInForeground) } else { diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift index 62abaaa005..69699a5913 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift @@ -294,6 +294,24 @@ extension ChatControllerImpl { if !hasAnonymousPeer { allPeers?.insert(SendAsPeer(peer: channel, subscribers: 0, isPremiumRequired: false), at: 0) } + } else if let channel = peerViewMainPeer(peerView) as? TelegramChannel, case let .broadcast(info) = channel.info, info.flags.contains(.messagesShouldHaveProfiles) { + allPeers = peers + + var hasAnonymousPeer = false + var hasSelfPeer = false + for peer in peers { + if peer.peer.id == channel.id { + hasAnonymousPeer = true + } else if peer.peer.id == strongSelf.context.account.peerId { + hasSelfPeer = true + } + } + if !hasSelfPeer { + allPeers?.insert(currentAccountPeer, at: 0) + } + if !hasAnonymousPeer { + allPeers?.insert(SendAsPeer(peer: channel, subscribers: 0, isPremiumRequired: false), at: 0) + } } else { allPeers = peers.filter { $0.peer.id != peerViewMainPeer(peerView)?.id } allPeers?.insert(currentAccountPeer, at: 0) @@ -3978,6 +3996,8 @@ extension ChatControllerImpl { let defaultMyPeerId: PeerId if let channel = strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer as? TelegramChannel, case .group = channel.info, channel.hasPermission(.canBeAnonymous) { defaultMyPeerId = channel.id + } else if let channel = strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer as? TelegramChannel, case let .broadcast(info) = channel.info, info.flags.contains(.messagesShouldHaveProfiles) { + defaultMyPeerId = channel.id } else { defaultMyPeerId = strongSelf.context.account.peerId } diff --git a/submodules/TelegramUI/Sources/ChatControllerOpenMessageReactionContextMenu.swift b/submodules/TelegramUI/Sources/ChatControllerOpenMessageReactionContextMenu.swift index ed92d13607..310ce9af8e 100644 --- a/submodules/TelegramUI/Sources/ChatControllerOpenMessageReactionContextMenu.swift +++ b/submodules/TelegramUI/Sources/ChatControllerOpenMessageReactionContextMenu.swift @@ -369,6 +369,12 @@ extension ChatControllerImpl { } func openMessageSendStarsScreen(message: Message) { + if let current = self.currentSendStarsUndoController { + self.currentSendStarsUndoController = nil + current.dismiss() + } + self.context.engine.messages.forceSendPendingSendStarsReaction(id: message.id) + let reactionsAttribute = mergedMessageReactions(attributes: message.attributes, isTags: false) let _ = (ChatSendStarsScreen.initialData(context: self.context, peerId: message.id.peerId, messageId: message.id, topPeers: reactionsAttribute?.topPeers ?? []) |> deliverOnMainQueue).start(next: { [weak self] initialData in diff --git a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.h b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.h index 96934adf5a..6443717eeb 100644 --- a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.h +++ b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.h @@ -32,4 +32,6 @@ NSObject * _Nullable makeLuminanceToAlphaFilter(); NSObject * _Nullable makeMonochromeFilter(); void setLayerDisableScreenshots(CALayer * _Nonnull layer, bool disableScreenshots); +bool getLayerDisableScreenshots(CALayer * _Nonnull layer); + void setLayerContentsMaskMode(CALayer * _Nonnull layer, bool maskMode); diff --git a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.m b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.m index 714d7032bd..fe257ac664 100644 --- a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.m +++ b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.m @@ -1,5 +1,7 @@ #import "UIKitUtils.h" +#import + #import #if TARGET_IPHONE_SIMULATOR @@ -236,6 +238,7 @@ NSObject * _Nullable makeMonochromeFilter() { return [(id)NSClassFromString(@"CAFilter") filterWithName:@"colorMonochrome"]; } +static const void *layerDisableScreenshotsKey = &layerDisableScreenshotsKey; void setLayerDisableScreenshots(CALayer * _Nonnull layer, bool disableScreenshots) { static UITextField *textField = nil; @@ -264,6 +267,17 @@ void setLayerDisableScreenshots(CALayer * _Nonnull layer, bool disableScreenshot textField.secureTextEntry = false; } [secureView setValue:previousLayer forKey:@"layer"]; + + [layer setAssociatedObject:@(disableScreenshots) forKey:layerDisableScreenshotsKey associationPolicy:NSObjectAssociationPolicyRetain]; +} + +bool getLayerDisableScreenshots(CALayer * _Nonnull layer) { + id result = [layer associatedObjectForKey:layerDisableScreenshotsKey]; + if ([result respondsToSelector:@selector(boolValue)]) { + return [(NSNumber *)result boolValue]; + } else { + return false; + } } void setLayerContentsMaskMode(CALayer * _Nonnull layer, bool maskMode) {