diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index d976d86b22..b448c97a1b 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -1638,7 +1638,10 @@ public final class ChatListNode: ListView { } else { self.push?(NewSessionInfoScreen(context: self.context, newSessionReview: newSessionReview)) + //#if DEBUG + //#else let _ = self.context.engine.privacy.terminateAnotherSession(id: newSessionReview.id).start() + //#endif } }, openChatFolderUpdates: { [weak self] in guard let self else { diff --git a/submodules/Display/Source/NavigationBar.swift b/submodules/Display/Source/NavigationBar.swift index 5a4fe019be..489396a9ff 100644 --- a/submodules/Display/Source/NavigationBar.swift +++ b/submodules/Display/Source/NavigationBar.swift @@ -143,6 +143,10 @@ public final class NavigationBackgroundNode: ASDisplayNode { public var effectView: UIVisualEffectView? private let backgroundNode: ASDisplayNode + + public var backgroundView: UIView { + return self.backgroundNode.view + } private var validLayout: (CGSize, CGFloat)? diff --git a/submodules/Display/Source/UIKitUtils.swift b/submodules/Display/Source/UIKitUtils.swift index 5b1b2fd80d..6d68a70581 100644 --- a/submodules/Display/Source/UIKitUtils.swift +++ b/submodules/Display/Source/UIKitUtils.swift @@ -757,6 +757,10 @@ public extension CALayer { static func blur() -> NSObject? { return makeBlurFilter() } + + static func luminanceToAlpha() -> NSObject? { + return makeLuminanceToAlphaFilter() + } } public extension CALayer { diff --git a/submodules/ReactionSelectionNode/Sources/ReactionContextBackgroundNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionContextBackgroundNode.swift index 7a35effcd8..58ce8f1d51 100644 --- a/submodules/ReactionSelectionNode/Sources/ReactionContextBackgroundNode.swift +++ b/submodules/ReactionSelectionNode/Sources/ReactionContextBackgroundNode.swift @@ -151,6 +151,7 @@ final class ReactionContextBackgroundNode: ASDisplayNode { } self.backgroundView.updateColor(color: theme.contextMenu.backgroundColor, transition: .immediate) + //self.backgroundView.updateColor(color: UIColor(white: 1.0, alpha: 0.0), forceKeepBlur: true, transition: .immediate) let shadowColor = UIColor(white: 0.0, alpha: 0.4) diff --git a/submodules/TelegramCore/Sources/State/ChannelBoost.swift b/submodules/TelegramCore/Sources/State/ChannelBoost.swift new file mode 100644 index 0000000000..a317de7ec7 --- /dev/null +++ b/submodules/TelegramCore/Sources/State/ChannelBoost.swift @@ -0,0 +1,117 @@ +import Foundation +import TelegramApi +import Postbox +import SwiftSignalKit + +public final class ChannelBoostStatus: Equatable { + public let level: Int + public let boosts: Int + public let nextLevelBoosts: Int? + + public init(level: Int, boosts: Int, nextLevelBoosts: Int?) { + self.level = level + self.boosts = boosts + self.nextLevelBoosts = nextLevelBoosts + } + + public static func ==(lhs: ChannelBoostStatus, rhs: ChannelBoostStatus) -> Bool { + if lhs.level != rhs.level { + return false + } + if lhs.boosts != rhs.boosts { + return false + } + if lhs.nextLevelBoosts != rhs.nextLevelBoosts { + return false + } + return true + } +} + +func _internal_getChannelBoostStatus(account: Account, peerId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Api.InputPeer? in + return transaction.getPeer(peerId).flatMap(apiInputPeer) + } + |> mapToSignal { inputPeer -> Signal in + guard let inputPeer = inputPeer else { + return .single(nil) + } + return account.network.request(Api.functions.stories.getBoostsStatus(peer: inputPeer)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> map { result -> ChannelBoostStatus? in + guard let result = result else { + return nil + } + + switch result { + case let .boostsStatus(_, level, boosts, nextLevelBoosts): + return ChannelBoostStatus(level: Int(level), boosts: Int(boosts), nextLevelBoosts: nextLevelBoosts.flatMap(Int.init)) + } + } + } +} + +public enum CanApplyBoostStatus { + public enum ErrorReason { + case generic + case premiumRequired + case floodWait + case peerBoostAlreadyActive + } + + case ok + case replace(currentBoost: EnginePeer) + case error(ErrorReason) +} + +func _internal_canApplyChannelBoost(account: Account, peerId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Api.InputPeer? in + return transaction.getPeer(peerId).flatMap(apiInputPeer) + } + |> mapToSignal { inputPeer -> Signal in + guard let inputPeer = inputPeer else { + return .single(nil) + } + return account.network.request(Api.functions.stories.canApplyBoost(peer: inputPeer), automaticFloodWait: false) + |> map { result -> (Api.stories.CanApplyBoostResult?, CanApplyBoostStatus.ErrorReason?) in + return (result, nil) + } + |> `catch` { error -> Signal<(Api.stories.CanApplyBoostResult?, CanApplyBoostStatus.ErrorReason?), NoError> in + let reason: CanApplyBoostStatus.ErrorReason + if error.errorDescription == "PREMIUM_ACCOUNT_REQUIRED" { + reason = .premiumRequired + } else if error.errorDescription.hasPrefix("FLOOD_WAIT_") { + reason = .floodWait + } else if error.errorDescription == "SAME_BOOST_ALREADY_ACTIVE" { + reason = .peerBoostAlreadyActive + } else { + reason = .generic + } + + return .single((nil, reason)) + } + |> mapToSignal { result, errorReason -> Signal in + guard let result = result else { + return .single(.error(errorReason ?? .generic)) + } + + return account.postbox.transaction { transaction -> CanApplyBoostStatus? in + switch result { + case .canApplyBoostOk: + return .ok + case let .canApplyBoostReplace(currentBoost, chats): + updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: AccumulatedPeers(transaction: transaction, chats: chats, users: [])) + + if let peer = transaction.getPeer(currentBoost.peerId) { + return .replace(currentBoost: EnginePeer(peer)) + } else { + return nil + } + } + } + } + } +} diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Stories.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Stories.swift index c3744cd87a..4978eca03b 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Stories.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Stories.swift @@ -1279,28 +1279,45 @@ public enum StoriesUploadAvailability { case expiringLimit case premiumRequired case unknownLimit + case channelBoostRequired } -func _internal_checkStoriesUploadAvailability(account: Account) -> Signal { - return account.network.request(Api.functions.stories.canSendStory(peer: .inputPeerSelf)) - |> map { result -> StoriesUploadAvailability in - if result == .boolTrue { - return .available - } else { - return .unknownLimit +func _internal_checkStoriesUploadAvailability(account: Account, target: Stories.PendingTarget) -> Signal { + return account.postbox.transaction { transaction -> Api.InputPeer? in + switch target { + case .myStories: + return .inputPeerSelf + case let .peer(peerId): + return transaction.getPeer(peerId).flatMap(apiInputPeer) } } - |> `catch` { error -> Signal in - if error.errorDescription.hasPrefix("STORY_SEND_FLOOD_WEEKLY_") { - return .single(.weeklyLimit) - } else if error.errorDescription.hasPrefix("STORY_SEND_FLOOD_MONTHLY_") { - return .single(.monthlyLimit) - } else if error.errorDescription.hasPrefix("PREMIUM_ACCOUNT_REQUIRED") { - return .single(.premiumRequired) - } else if error.errorDescription.hasPrefix("STORIES_TOO_MUCH") { - return .single(.expiringLimit) + |> mapToSignal { inputPeer -> Signal in + guard let inputPeer = inputPeer else { + return .single(.unknownLimit) + } + + return account.network.request(Api.functions.stories.canSendStory(peer: inputPeer)) + |> map { result -> StoriesUploadAvailability in + if result == .boolTrue { + return .available + } else { + return .unknownLimit + } + } + |> `catch` { error -> Signal in + if error.errorDescription.hasPrefix("STORY_SEND_FLOOD_WEEKLY_") { + return .single(.weeklyLimit) + } else if error.errorDescription.hasPrefix("STORY_SEND_FLOOD_MONTHLY_") { + return .single(.monthlyLimit) + } else if error.errorDescription.hasPrefix("PREMIUM_ACCOUNT_REQUIRED") { + return .single(.premiumRequired) + } else if error.errorDescription.hasPrefix("STORIES_TOO_MUCH") { + return .single(.expiringLimit) + } else if error.errorDescription.hasPrefix("BOOSTS_REQUIRED") { + return .single(.channelBoostRequired) + } + return .single(.unknownLimit) } - return .single(.unknownLimit) } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift index 74873df0db..18aca8e45a 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift @@ -1213,8 +1213,8 @@ public extension TelegramEngine { return _internal_editStoryPrivacy(account: self.account, id: id, privacy: privacy) } - public func checkStoriesUploadAvailability() -> Signal { - return _internal_checkStoriesUploadAvailability(account: self.account) + public func checkStoriesUploadAvailability(target: Stories.PendingTarget) -> Signal { + return _internal_checkStoriesUploadAvailability(account: self.account, target: target) } public func deleteStories(peerId: EnginePeer.Id, ids: [Int32]) -> Signal { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift index ebbcad7d1d..99668adc64 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift @@ -1188,6 +1188,14 @@ public extension TelegramEngine { public func updatePeerStoriesHidden(id: PeerId, isHidden: Bool) { let _ = _internal_updatePeerStoriesHidden(account: self.account, id: id, isHidden: isHidden).start() } + + public func getChannelBoostStatus(peerId: EnginePeer.Id) -> Signal { + return _internal_getChannelBoostStatus(account: self.account, peerId: peerId) + } + + public func canApplyChannelBoost(peerId: EnginePeer.Id) -> Signal { + return _internal_canApplyChannelBoost(account: self.account, peerId: peerId) + } } } diff --git a/submodules/TelegramUI/Components/CameraScreen/Sources/CameraScreen.swift b/submodules/TelegramUI/Components/CameraScreen/Sources/CameraScreen.swift index 12ecfd9e54..fbe0b3ea5e 100644 --- a/submodules/TelegramUI/Components/CameraScreen/Sources/CameraScreen.swift +++ b/submodules/TelegramUI/Components/CameraScreen/Sources/CameraScreen.swift @@ -2410,7 +2410,7 @@ public class CameraScreen: ViewController { self.requestAudioSession() - self.postingAvailabilityPromise.set(self.context.engine.messages.checkStoriesUploadAvailability()) + self.postingAvailabilityPromise.set(self.context.engine.messages.checkStoriesUploadAvailability(target: .myStories)) } required public init(coder: NSCoder) { diff --git a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.h b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.h index 607d748fad..3f535a8407 100644 --- a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.h +++ b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.h @@ -26,3 +26,4 @@ void applySmoothRoundedCornersImpl(CALayer * _Nonnull layer); UIView * _Nullable makePortalView(bool matchPosition); NSObject * _Nullable makeBlurFilter(); +NSObject * _Nullable makeLuminanceToAlphaFilter(); diff --git a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.m b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.m index ecea0b1e92..3cf8dd34e1 100644 --- a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.m +++ b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.m @@ -210,3 +210,7 @@ UIView * _Nullable makePortalView(bool matchPosition) { NSObject * _Nullable makeBlurFilter() { return [(id)NSClassFromString(@"CAFilter") filterWithName:@"gaussianBlur"]; } + +NSObject * _Nullable makeLuminanceToAlphaFilter() { + return [(id)NSClassFromString(@"CAFilter") filterWithName:@"luminanceToAlpha"]; +}