diff --git a/submodules/TelegramCore/Sources/ApiUtils/ApiGroupOrChannel.swift b/submodules/TelegramCore/Sources/ApiUtils/ApiGroupOrChannel.swift index 122d2f95a5..dc9280893c 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/ApiGroupOrChannel.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/ApiGroupOrChannel.swift @@ -131,6 +131,9 @@ func parseTelegramGroupOrChannel(chat: Api.Chat) -> Peer? { if (flags & Int32(1 << 30)) != 0 { channelFlags.insert(.isForum) } + if (flags2 & Int32(1 << 15)) != 0 { + channelFlags.insert(.autoTranslateEnabled) + } var storiesHidden: Bool? if flags2 & (1 << 2) == 0 { // stories_hidden_min diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChannel.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChannel.swift index 77c9b3d4ca..6fb4634d4f 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChannel.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChannel.swift @@ -181,6 +181,7 @@ public struct TelegramChannelFlags: OptionSet { public static let joinToSend = TelegramChannelFlags(rawValue: 1 << 9) public static let requestToJoin = TelegramChannelFlags(rawValue: 1 << 10) public static let isForum = TelegramChannelFlags(rawValue: 1 << 11) + public static let autoTranslateEnabled = TelegramChannelFlags(rawValue: 1 << 12) } public final class TelegramChannel: Peer, Equatable { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Data/PeersData.swift b/submodules/TelegramCore/Sources/TelegramEngine/Data/PeersData.swift index f5738a162c..36f3679bed 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Data/PeersData.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Data/PeersData.swift @@ -2467,5 +2467,32 @@ public extension TelegramEngine.EngineData.Item { } } } + + public struct AutoTranslateEnabled: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem { + public typealias Result = Bool + + fileprivate var id: EnginePeer.Id + public var mapKey: EnginePeer.Id { + return self.id + } + + public init(id: EnginePeer.Id) { + self.id = id + } + + var key: PostboxViewKey { + return .peer(peerId: self.id, components: []) + } + + func extract(view: PostboxView) -> Result { + guard let view = view as? PeerView else { + preconditionFailure() + } + if let channel = peerViewMainPeer(view) as? TelegramChannel { + return channel.flags.contains(.autoTranslateEnabled) + } + return false + } + } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift index 9330c8db39..9abcd3c23f 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift @@ -179,7 +179,6 @@ public enum BotPaymentFormRequestError { case alreadyActive case noPaymentNeeded case disallowedStarGift - case starGiftResellTooEarly(Int32) } extension BotPaymentInvoice { @@ -483,11 +482,6 @@ func _internal_fetchBotPaymentForm(accountPeerId: PeerId, postbox: Postbox, netw return .fail(.noPaymentNeeded) } else if error.errorDescription == "USER_DISALLOWED_STARGIFTS" { return .fail(.disallowedStarGift) - } else if error.errorDescription.hasPrefix("STARGIFT_RESELL_TOO_EARLY_") { - let timeout = String(error.errorDescription[error.errorDescription.index(error.errorDescription.startIndex, offsetBy: "STARGIFT_RESELL_TOO_EARLY_".count)...]) - if let value = Int32(timeout) { - return .fail(.starGiftResellTooEarly(value)) - } } return .fail(.generic) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift index 17370fa667..1cdbf93064 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift @@ -847,7 +847,6 @@ public enum TransferStarGiftError { public enum BuyStarGiftError { case generic - case starGiftResellTooEarly(Int32) } public enum UpdateStarGiftPriceError { @@ -855,7 +854,6 @@ public enum UpdateStarGiftPriceError { case starGiftResellTooEarly(Int32) } - public enum UpgradeStarGiftError { case generic } @@ -865,12 +863,7 @@ func _internal_buyStarGift(account: Account, slug: String, peerId: EnginePeer.Id return _internal_fetchBotPaymentForm(accountPeerId: account.peerId, postbox: account.postbox, network: account.network, source: source, themeParams: nil) |> map(Optional.init) |> `catch` { error -> Signal in - switch error { - case let .starGiftResellTooEarly(value): - return .fail(.starGiftResellTooEarly(value)) - default: - return .fail(.generic) - } + return .fail(.generic) } |> mapToSignal { paymentForm in if let paymentForm { @@ -2360,10 +2353,10 @@ func _internal_updateStarGiftResalePrice(account: Account, reference: StarGiftRe return account.network.request(Api.functions.payments.updateStarGiftPrice(stargift: starGift, resellStars: price ?? 0)) |> mapError { error -> UpdateStarGiftPriceError in if error.errorDescription.hasPrefix("STARGIFT_RESELL_TOO_EARLY_") { - let timeout = String(error.errorDescription[error.errorDescription.index(error.errorDescription.startIndex, offsetBy: "STARGIFT_RESELL_TOO_EARLY_".count)...]) - if let value = Int32(timeout) { - return .starGiftResellTooEarly(value) - } + let timeout = String(error.errorDescription[error.errorDescription.index(error.errorDescription.startIndex, offsetBy: "STARGIFT_RESELL_TOO_EARLY_".count)...]) + if let value = Int32(timeout) { + return .starGiftResellTooEarly(value) + } } return .generic } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/AutoTranslate.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/AutoTranslate.swift new file mode 100644 index 0000000000..cd513ab5f1 --- /dev/null +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/AutoTranslate.swift @@ -0,0 +1,19 @@ +import Foundation +import Postbox +import SwiftSignalKit +import TelegramApi +import MtProtoKit + +func _internal_toggleAutoTranslation(account: Account, peerId: PeerId, enabled: Bool) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) { + return account.network.request(Api.functions.channels.toggleAutotranslation(channel: inputChannel, enabled: enabled ? .boolTrue : .boolFalse)) |> `catch` { _ in .complete() } |> map { updates -> Void in + account.stateManager.addUpdates(updates) + } + } else { + return .complete() + } + } + |> switchToLatest + |> ignoreValues +} diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift index a8b746b691..06ac1460c1 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift @@ -1693,6 +1693,10 @@ public extension TelegramEngine { let _ = _internal_removeChatManagingBot(account: self.account, chatId: chatId).startStandalone() } + public func toggleAutoTranslation(peerId: EnginePeer.Id, enabled: Bool) -> Signal { + return _internal_toggleAutoTranslation(account: self.account, peerId: peerId, enabled: enabled) + } + public func resolveMessageLink(slug: String) -> Signal { return self.account.network.request(Api.functions.account.resolveBusinessChatLink(slug: slug)) |> map(Optional.init) diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift index 7e4eac1d55..418b8257c4 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift @@ -8155,7 +8155,9 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID let trimmedValues = values.withUpdatedVideoTrimRange(start ..< min(start + storyMaxVideoDuration, originalDuration)) var editingItem = EditingItem(asset: asset) - editingItem.caption = self.node.getCaption() + if i == 0 { + editingItem.caption = self.node.getCaption() + } editingItem.values = trimmedValues multipleItems.append(editingItem) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index fc4b92105e..dca4602cbf 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -2007,7 +2007,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese return result } -private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatLocation: ChatLocation, context: AccountContext, presentationData: PresentationData, interaction: PeerInfoInteraction) -> [(AnyHashable, [PeerInfoScreenItem])] { +private func editingItems(data: PeerInfoScreenData?, boostStatus: ChannelBoostStatus?, state: PeerInfoState, chatLocation: ChatLocation, context: AccountContext, presentationData: PresentationData, interaction: PeerInfoInteraction) -> [(AnyHashable, [PeerInfoScreenItem])] { enum Section: Int, CaseIterable { case notifications case groupLocation @@ -2276,11 +2276,12 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL interaction.editingOpenNameColorSetup() })) + let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 }) var isLocked = true - if let approximateBoostLevel = channel.approximateBoostLevel, approximateBoostLevel >= 3 { + if let boostLevel = boostStatus?.level, boostLevel >= BoostSubject.autoTranslate.requiredLevel(group: false, context: context, configuration: premiumConfiguration) { isLocked = false } - items[.peerSettings]!.append(PeerInfoScreenSwitchItem(id: ItemPeerAutoTranslate, text: presentationData.strings.Channel_Info_AutoTranslate, value: false, icon: UIImage(bundleImageName: "Settings/Menu/AutoTranslate"), isLocked: isLocked, toggled: { value in + items[.peerSettings]!.append(PeerInfoScreenSwitchItem(id: ItemPeerAutoTranslate, text: presentationData.strings.Channel_Info_AutoTranslate, value: channel.flags.contains(.autoTranslateEnabled), icon: UIImage(bundleImageName: "Settings/Menu/AutoTranslate"), isLocked: isLocked, toggled: { value in if isLocked { interaction.displayAutoTranslateLocked() } else { @@ -9157,7 +9158,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro } private func toggleAutoTranslate(isEnabled: Bool) { - + self.activeActionDisposable.set(self.context.engine.peers.toggleAutoTranslation(peerId: self.peerId, enabled: isEnabled).start()) } private func displayAutoTranslateLocked() { @@ -11918,7 +11919,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro } var validEditingSections: [AnyHashable] = [] - let editItems = (self.isSettings || self.isMyProfile) ? settingsEditingItems(data: self.data, state: self.state, context: self.context, presentationData: self.presentationData, interaction: self.interaction, isMyProfile: self.isMyProfile) : editingItems(data: self.data, state: self.state, chatLocation: self.chatLocation, context: self.context, presentationData: self.presentationData, interaction: self.interaction) + let editItems = (self.isSettings || self.isMyProfile) ? settingsEditingItems(data: self.data, state: self.state, context: self.context, presentationData: self.presentationData, interaction: self.interaction, isMyProfile: self.isMyProfile) : editingItems(data: self.data, boostStatus: self.boostStatus, state: self.state, chatLocation: self.chatLocation, context: self.context, presentationData: self.presentationData, interaction: self.interaction) for (sectionId, sectionItems) in editItems { var insets = UIEdgeInsets() diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift index b724c12034..a665b1b70d 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift @@ -675,17 +675,22 @@ extension ChatControllerImpl { let isHidden = self.context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.TranslationHidden(id: peerId)) |> distinctUntilChanged + + let hasAutoTranslate = self.context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.AutoTranslateEnabled(id: peerId)) + |> distinctUntilChanged + self.translationStateDisposable = (combineLatest( queue: .concurrentDefaultQueue(), isPremium, isHidden, + hasAutoTranslate, ApplicationSpecificNotice.translationSuggestion(accountManager: self.context.sharedContext.accountManager) - ) |> mapToSignal { isPremium, isHidden, counterAndTimestamp -> Signal in + ) |> mapToSignal { isPremium, isHidden, hasAutoTranslate, counterAndTimestamp -> Signal in var maybeSuggestPremium = false if counterAndTimestamp.0 >= 3 { maybeSuggestPremium = true } - if (isPremium || maybeSuggestPremium) && !isHidden { + if (isPremium || maybeSuggestPremium || hasAutoTranslate) && !isHidden { return chatTranslationState(context: context, peerId: peerId) |> map { translationState -> ChatPresentationTranslationState? in if let translationState, !translationState.fromLang.isEmpty && (translationState.fromLang != baseLanguageCode || translationState.isEnabled) { diff --git a/submodules/TranslateUI/Sources/ChatTranslation.swift b/submodules/TranslateUI/Sources/ChatTranslation.swift index f6bdf92ec2..9111cbf26e 100644 --- a/submodules/TranslateUI/Sources/ChatTranslation.swift +++ b/submodules/TranslateUI/Sources/ChatTranslation.swift @@ -180,10 +180,17 @@ public func chatTranslationState(context: AccountContext, peerId: EnginePeer.Id) baseLang = String(baseLang.dropLast(rawSuffix.count)) } - return context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.translationSettings]) - |> mapToSignal { sharedData in - let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.translationSettings]?.get(TranslationSettings.self) ?? TranslationSettings.defaultSettings - if !settings.translateChats { + + + return combineLatest( + context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.translationSettings]) + |> map { sharedData -> TranslationSettings in + return sharedData.entries[ApplicationSpecificSharedDataKeys.translationSettings]?.get(TranslationSettings.self) ?? TranslationSettings.defaultSettings + }, + context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.AutoTranslateEnabled(id: peerId)) + ) + |> mapToSignal { settings, autoTranslateEnabled in + if !settings.translateChats && !autoTranslateEnabled { return .single(nil) } @@ -286,12 +293,22 @@ public func chatTranslationState(context: AccountContext, peerId: EnginePeer.Id) if loggingEnabled { Logger.shared.log("ChatTranslation", "Ended with: \(fromLang)") } + + let isEnabled: Bool + if let currentIsEnabled = cached?.isEnabled { + isEnabled = currentIsEnabled + } else if autoTranslateEnabled { + isEnabled = true + } else { + isEnabled = false + } + let state = ChatTranslationState( baseLang: baseLang, fromLang: fromLang, timestamp: currentTime, toLang: cached?.toLang, - isEnabled: cached?.isEnabled ?? false + isEnabled: isEnabled ) let _ = updateChatTranslationState(engine: context.engine, peerId: peerId, state: state).start() if !dontTranslateLanguages.contains(fromLang) {