diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index aa41cba7d2..9028bc3ed9 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -8705,7 +8705,9 @@ Sorry for the inconvenience."; "Conversation.Translation.DoNotTranslate" = "Do Not Translate %@"; "Conversation.Translation.Hide" = "Hide"; "Conversation.Translation.AddedToDoNotTranslateText" = "**%@** is added to the Do Not Translate list."; -"Conversation.Translation.TranslationBarHiddenText" = "Translation bar is now hidden for this channel."; +"Conversation.Translation.TranslationBarHiddenChatText" = "Translation bar is now hidden for this chat."; +"Conversation.Translation.TranslationBarHiddenGroupText" = "Translation bar is now hidden for this group."; +"Conversation.Translation.TranslationBarHiddenChannelText" = "Translation bar is now hidden for this channel."; "ProfilePhoto.SetEmoji" = "Set Emoji"; diff --git a/submodules/AccountContext/Sources/ChatController.swift b/submodules/AccountContext/Sources/ChatController.swift index 5259b30474..e9a9bc820a 100644 --- a/submodules/AccountContext/Sources/ChatController.swift +++ b/submodules/AccountContext/Sources/ChatController.swift @@ -618,7 +618,7 @@ public protocol ChatController: ViewController { func beginMessageSearch(_ query: String) func displayPromoAnnouncement(text: String) - func updateIsPushed(_ isPushed: Bool) + func updatePushedTransition(_ fraction: CGFloat, transition: ContainedViewLayoutTransition) func hintPlayNextOutgoingGift() diff --git a/submodules/AvatarVideoNode/Sources/AvatarVideoNode.swift b/submodules/AvatarVideoNode/Sources/AvatarVideoNode.swift index 784abdacf3..acd11ff715 100644 --- a/submodules/AvatarVideoNode/Sources/AvatarVideoNode.swift +++ b/submodules/AvatarVideoNode/Sources/AvatarVideoNode.swift @@ -31,6 +31,7 @@ public final class AvatarVideoNode: ASDisplayNode { private var itemLayer: EmojiPagerContentComponent.View.ItemLayer? private var useAnimationNode = false private var animationNode: AnimatedStickerNode? + private let stickerFetchedDisposable = MetaDisposable() private var videoNode: UniversalVideoNode? private var videoContent: NativeVideoContent? @@ -56,6 +57,7 @@ public final class AvatarVideoNode: ASDisplayNode { deinit { self.fileDisposable?.dispose() + self.stickerFetchedDisposable.dispose() self.playbackStartDisposable.dispose() } @@ -75,6 +77,8 @@ public final class AvatarVideoNode: ASDisplayNode { } if self.useAnimationNode { + self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, userLocation: .other, fileReference: stickerPackFileReference(animationFile), resource: chatMessageStickerResource(file: animationFile, small: false)).start()) + let animationNode = DefaultAnimatedStickerNodeImpl() animationNode.autoplay = false self.animationNode = animationNode @@ -125,10 +129,10 @@ public final class AvatarVideoNode: ASDisplayNode { } } itemLayer.layerTintColor = UIColor.white.cgColor - itemLayer.isVisibleForAnimations = self.visibility self.itemLayer = itemLayer self.backgroundNode.layer.addSublayer(itemLayer) } + self.updateVisibility(self.visibility) if let (size, cornerRadius) = self.validLayout { self.updateLayout(size: size, cornerRadius: cornerRadius, transition: .immediate) @@ -141,7 +145,8 @@ public final class AvatarVideoNode: ASDisplayNode { } self.emojiMarkup = markup self.internalSize = size - //self.useAnimationNode = useAnimationNode + self.useAnimationNode = useAnimationNode + self.didSetupAnimation = false let colors = markup.backgroundColors.map { UInt32(bitPattern: $0) } if colors.count == 1 { @@ -197,15 +202,19 @@ public final class AvatarVideoNode: ASDisplayNode { } } + private var didSetupAnimation = false private var visibility = false public func updateVisibility(_ isVisible: Bool) { self.visibility = isVisible if isVisible, let animationNode = self.animationNode, let file = self.animationFile { - let pathPrefix = self.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(file.resource.id) - let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512) - let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 384.0, height: 384.0)) - let source = AnimatedStickerResourceSource(account: self.context.account, resource: file.resource, isVideo: file.isVideoSticker || file.mimeType == "video/webm") - animationNode.setup(source: source, width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .direct(cachePathPrefix: pathPrefix)) + if !self.didSetupAnimation { + self.didSetupAnimation = true + let pathPrefix = self.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(file.resource.id) + let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512) + let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 384.0, height: 384.0)) + let source = AnimatedStickerResourceSource(account: self.context.account, resource: file.resource, isVideo: file.isVideoSticker || file.mimeType == "video/webm") + animationNode.setup(source: source, width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .direct(cachePathPrefix: pathPrefix)) + } } self.animationNode?.visibility = isVisible if isVisible, let videoContent = self.videoContent, self.videoLoopCount != maxVideoLoopCount { diff --git a/submodules/GalleryUI/Sources/GalleryController.swift b/submodules/GalleryUI/Sources/GalleryController.swift index 0a0a2151fc..aca341401f 100644 --- a/submodules/GalleryUI/Sources/GalleryController.swift +++ b/submodules/GalleryUI/Sources/GalleryController.swift @@ -1003,6 +1003,10 @@ public class GalleryController: ViewController, StandalonePresentableController, } } + if let chatController = self.baseNavigationController?.topViewController as? ChatController { + chatController.updatePushedTransition(0.0, transition: .animated(duration: 0.45, curve: .customSpring(damping: 180.0, initialVelocity: 0.0))) + } + if let centralItemNode = self.galleryNode.pager.centralItemNode(), let presentationArguments = self.presentationArguments as? GalleryControllerPresentationArguments { let message = self.entries[centralItemNode.index].message if let (media, _) = mediaForMessage(message: message), let transitionArguments = presentationArguments.transitionArguments(message.id, media), !forceAway { diff --git a/submodules/GalleryUI/Sources/GalleryControllerNode.swift b/submodules/GalleryUI/Sources/GalleryControllerNode.swift index 6c30bd7a04..4069f0fa68 100644 --- a/submodules/GalleryUI/Sources/GalleryControllerNode.swift +++ b/submodules/GalleryUI/Sources/GalleryControllerNode.swift @@ -364,15 +364,11 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture } if let chatController = self.baseNavigationController()?.topViewController as? ChatController { - chatController.updateIsPushed(true) + chatController.updatePushedTransition(1.0, transition: .animated(duration: 0.45, curve: .customSpring(damping: 180.0, initialVelocity: 0.0))) } } - open func animateOut(animateContent: Bool, completion: @escaping () -> Void) { - if let chatController = self.baseNavigationController()?.topViewController as? ChatController { - chatController.updateIsPushed(false) - } - + open func animateOut(animateContent: Bool, completion: @escaping () -> Void) { self.isDismissed = true self.pager.isScrollEnabled = false @@ -389,9 +385,9 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture if let backgroundColor = self.backgroundNode.backgroundColor { let updatedColor = backgroundColor.withAlphaComponent(0.0) self.backgroundNode.backgroundColor = updatedColor - self.backgroundNode.layer.animate(from: backgroundColor.cgColor, to: updatedColor.cgColor, keyPath: "backgroundColor", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: 0.15) + self.backgroundNode.layer.animate(from: backgroundColor.cgColor, to: updatedColor.cgColor, keyPath: "backgroundColor", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: 0.1) } - UIView.animate(withDuration: 0.25, animations: { + UIView.animate(withDuration: 0.1, animations: { self.statusBar?.alpha = 0.0 self.navigationBar?.alpha = 0.0 self.footerNode.alpha = 0.0 @@ -422,7 +418,7 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture } open func scrollViewDidScroll(_ scrollView: UIScrollView) { - if self.isDismissed { + guard !self.isDismissed else { return } let distanceFromEquilibrium = scrollView.contentOffset.y - scrollView.contentSize.height / 3.0 @@ -450,6 +446,11 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture self.updateDismissTransition(transition) self.updateDistanceFromEquilibrium(distanceFromEquilibrium) + if scrollView.isDragging, let chatController = self.baseNavigationController()?.topViewController as? ChatController { + let transition = 1.0 - min(1.0, max(0.0, abs(distanceFromEquilibrium) / 150.0)) + chatController.updatePushedTransition(transition, transition: .immediate) + } + if let overlayNode = self.overlayNode { overlayNode.alpha = transition } @@ -477,6 +478,10 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture } } + if let chatController = self.baseNavigationController()?.topViewController as? ChatController { + chatController.updatePushedTransition(0.0, transition: .animated(duration: 0.45, curve: .customSpring(damping: 180.0, initialVelocity: 0.0))) + } + if let centralItemNode = self.pager.centralItemNode(), let (transitionNodeForCentralItem, addToTransitionSurface) = self.transitionDataForCentralItem?(), let node = transitionNodeForCentralItem { contentAnimationCompleted = false centralItemNode.animateOut(to: node, addToTransitionSurface: addToTransitionSurface, completion: { diff --git a/submodules/SettingsUI/Sources/Language Selection/LocalizationListControllerNode.swift b/submodules/SettingsUI/Sources/Language Selection/LocalizationListControllerNode.swift index facfef46ac..0f163c559f 100644 --- a/submodules/SettingsUI/Sources/Language Selection/LocalizationListControllerNode.swift +++ b/submodules/SettingsUI/Sources/Language Selection/LocalizationListControllerNode.swift @@ -488,7 +488,16 @@ final class LocalizationListControllerNode: ViewControllerTracingNode { var value = "" if ignoredLanguages.count > 1 { - value = ignoredLanguages.joined(separator: ", ") + var ignoredLanguagesSet = Set() + var filteredIgnoredLanguages: [String] = [] + for language in ignoredLanguages { + if ignoredLanguagesSet.contains(language) { + continue + } + ignoredLanguagesSet.insert(language) + filteredIgnoredLanguages.append(language) + } + value = filteredIgnoredLanguages.joined(separator: ", ") } else if let code = ignoredLanguages.first { let enLocale = Locale(identifier: "en") if let title = enLocale.localizedString(forLanguageCode: code) { diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 6a43524d3a..02afe176e8 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -6730,14 +6730,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G threadData = .single(nil) } - if peerId.namespace == Namespaces.Peer.CloudChannel { - let baseLanguageCode = self.presentationData.strings.baseLanguageCode + if peerId.namespace != Namespaces.Peer.SecretChat && self.subject != .scheduledMessages { + var baseLanguageCode = self.presentationData.strings.baseLanguageCode + if baseLanguageCode.contains("-") { + baseLanguageCode = baseLanguageCode.components(separatedBy: "-").first ?? baseLanguageCode + } let isPremium = self.context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId)) |> map { peer -> Bool in return peer?.isPremium ?? false } |> distinctUntilChanged - let isHidden = self.context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.TranslationHidden(id: self.context.account.peerId)) + let isHidden = self.context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.TranslationHidden(id: peerId)) |> distinctUntilChanged self.translationStateDisposable = (combineLatest( queue: .concurrentDefaultQueue(), @@ -10125,10 +10128,25 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return } let context = strongSelf.context + let presentationData = strongSelf.presentationData let _ = context.engine.messages.togglePeerMessagesTranslationHidden(peerId: peerId, hidden: true).start() - let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } - strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .image(image: generateTintedImage(image: UIImage(bundleImageName: "Chat/Title Panels/Translate"), color: .white)!, title: nil, text: presentationData.strings.Conversation_Translation_TranslationBarHiddenText, round: false, undoText: presentationData.strings.Undo_Undo), elevatedLayout: false, animateInAsReplacement: false, action: { action in + var text: String = "" + if let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer { + if peer is TelegramGroup { + text = presentationData.strings.Conversation_Translation_TranslationBarHiddenGroupText + } else if let peer = peer as? TelegramChannel { + switch peer.info { + case .group: + text = presentationData.strings.Conversation_Translation_TranslationBarHiddenGroupText + case .broadcast: + text = presentationData.strings.Conversation_Translation_TranslationBarHiddenChannelText + } + } else { + text = presentationData.strings.Conversation_Translation_TranslationBarHiddenChatText + } + } + strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .image(image: generateTintedImage(image: UIImage(bundleImageName: "Chat/Title Panels/Translate"), color: .white)!, title: nil, text: text, round: false, undoText: presentationData.strings.Undo_Undo), elevatedLayout: false, animateInAsReplacement: false, action: { action in if case .undo = action { let _ = context.engine.messages.togglePeerMessagesTranslationHidden(peerId: peerId, hidden: false).start() } @@ -18185,9 +18203,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.chatDisplayNode.historyNodeContainer.layer.addShakeAnimation(amplitude: -6.0, decay: true) } - public func updateIsPushed(_ isPushed: Bool) { - let scale: CGFloat = isPushed ? 0.94 : 1.0 - let transition = ContainedViewLayoutTransition.animated(duration: 0.45, curve: .customSpring(damping: 180.0, initialVelocity: 0.0)) + public func updatePushedTransition(_ fraction: CGFloat, transition: ContainedViewLayoutTransition) { + let scale: CGFloat = 1.0 - 0.06 * fraction transition.updateTransformScale(node: self.chatDisplayNode.historyNodeContainer, scale: scale) } diff --git a/submodules/TelegramUI/Sources/ChatTranslationPanelNode.swift b/submodules/TelegramUI/Sources/ChatTranslationPanelNode.swift index 12303a1e80..0c90682b14 100644 --- a/submodules/TelegramUI/Sources/ChatTranslationPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTranslationPanelNode.swift @@ -122,7 +122,7 @@ final class ChatTranslationPanelNode: ASDisplayNode { self.buttonTextNode.attributedText = NSAttributedString(string: buttonText, font: Font.regular(17.0), textColor: interfaceState.theme.rootController.navigationBar.accentTextColor) } - let panelHeight: CGFloat = 44.0 + let panelHeight: CGFloat = 40.0 let contentRightInset: CGFloat = 14.0 + rightInset diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index c988f455b1..6cdcca48ab 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -7052,7 +7052,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate subscriber.putCompletion() } else if let strongSelf = self, let progress = next as? NSNumber { Queue.mainQueue().async { - strongSelf.state = strongSelf.state.withAvatarUploadProgress(CGFloat(progress.floatValue * 0.25)) + strongSelf.state = strongSelf.state.withAvatarUploadProgress(CGFloat(progress.floatValue * 0.45)) if let (layout, navigationHeight) = strongSelf.validLayout { strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false) } @@ -7132,7 +7132,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate case .complete: strongSelf.state = strongSelf.state.withUpdatingAvatar(nil).withAvatarUploadProgress(nil) case let .progress(value): - strongSelf.state = strongSelf.state.withAvatarUploadProgress(CGFloat(0.25 + value * 0.75)) + strongSelf.state = strongSelf.state.withAvatarUploadProgress(CGFloat(0.45 + value * 0.55)) } if let (layout, navigationHeight) = strongSelf.validLayout { strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false) diff --git a/submodules/TelegramUIPreferences/Sources/PostboxKeys.swift b/submodules/TelegramUIPreferences/Sources/PostboxKeys.swift index eda2f2d1d9..f53c296037 100644 --- a/submodules/TelegramUIPreferences/Sources/PostboxKeys.swift +++ b/submodules/TelegramUIPreferences/Sources/PostboxKeys.swift @@ -73,7 +73,7 @@ private enum ApplicationSpecificItemCacheCollectionIdValues: Int8 { case visualMediaStoredState = 5 case cachedImageRecognizedContent = 6 case pendingInAppPurchaseState = 7 - case translationState = 9 + case translationState = 10 } public struct ApplicationSpecificItemCacheCollectionId { diff --git a/submodules/TranslateUI/Sources/ChatTranslation.swift b/submodules/TranslateUI/Sources/ChatTranslation.swift index 131572cb04..97b69f05ab 100644 --- a/submodules/TranslateUI/Sources/ChatTranslation.swift +++ b/submodules/TranslateUI/Sources/ChatTranslation.swift @@ -143,12 +143,11 @@ public func chatTranslationState(context: AccountContext, peerId: EnginePeer.Id) return .single(nil) } - var dontTranslateLanguages: [String] = [] + var dontTranslateLanguages = Set() if let ignoredLanguages = settings.ignoredLanguages { - dontTranslateLanguages = ignoredLanguages - } else { - dontTranslateLanguages = [baseLang] + dontTranslateLanguages = Set(ignoredLanguages) } + dontTranslateLanguages.insert(baseLang) return cachedChatTranslationState(engine: context.engine, peerId: peerId) |> mapToSignal { cached in @@ -184,7 +183,7 @@ public func chatTranslationState(context: AccountContext, peerId: EnginePeer.Id) let filteredLanguages = hypotheses.filter { supportedTranslationLanguages.contains($0.key.rawValue) }.sorted(by: { $0.value > $1.value }) if let language = filteredLanguages.first(where: { supportedTranslationLanguages.contains($0.key.rawValue) }) { let fromLang = language.key.rawValue - fromLangs[fromLang] = (fromLangs[fromLang] ?? 0) + 1 + fromLangs[fromLang] = (fromLangs[fromLang] ?? 0) + message.text.count } count += 1 }