From 156c84e4f75b7781a35d539dd9d27a32cfed36de Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 16 Apr 2024 18:43:14 +0400 Subject: [PATCH 01/11] Clean up --- .../StatisticsUI/Sources/CpmSliderItem.swift | 322 ------------------ 1 file changed, 322 deletions(-) delete mode 100644 submodules/StatisticsUI/Sources/CpmSliderItem.swift diff --git a/submodules/StatisticsUI/Sources/CpmSliderItem.swift b/submodules/StatisticsUI/Sources/CpmSliderItem.swift deleted file mode 100644 index 81862904a3..0000000000 --- a/submodules/StatisticsUI/Sources/CpmSliderItem.swift +++ /dev/null @@ -1,322 +0,0 @@ -import Foundation -import UIKit -import Display -import AsyncDisplayKit -import SwiftSignalKit -import TelegramCore -import TelegramUIPreferences -import TelegramPresentationData -import LegacyComponents -import ItemListUI -import PresentationDataUtils -import EmojiTextAttachmentView -import TextFormat -import AccountContext -import UIKitRuntimeUtils - -final class CpmSliderItem: ListViewItem, ItemListItem { - let context: AccountContext - let theme: PresentationTheme - let strings: PresentationStrings - let value: Int32 - let animatedEmoji: TelegramMediaFile? - let sectionId: ItemListSectionId - let updated: (Int32) -> Void - - init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, value: Int32, enabled: Bool, animatedEmoji: TelegramMediaFile?, sectionId: ItemListSectionId, updated: @escaping (Int32) -> Void) { - self.context = context - self.theme = theme - self.strings = strings - self.value = value - self.animatedEmoji = animatedEmoji - self.sectionId = sectionId - self.updated = updated - } - - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, (ListViewItemApply) -> Void)) -> Void) { - async { - let node = CpmSliderItemNode() - let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) - - node.contentSize = layout.contentSize - node.insets = layout.insets - - Queue.mainQueue().async { - completion(node, { - return (nil, { _ in apply() }) - }) - } - } - } - - func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) { - Queue.mainQueue().async { - if let nodeValue = node() as? CpmSliderItemNode { - let makeLayout = nodeValue.asyncLayout() - - async { - let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) - Queue.mainQueue().async { - completion(layout, { _ in - apply() - }) - } - } - } - } - } -} - -private let allowedValues: [Int32] = [1, 2, 3, 4, 5] - -class CpmSliderItemNode: ListViewItemNode { - private let backgroundNode: ASDisplayNode - private let topStripeNode: ASDisplayNode - private let bottomStripeNode: ASDisplayNode - private let maskNode: ASImageNode - - private let minTextNode: TextNode - private let maxTextNode: TextNode - private let textNode: TextNode - private var sliderView: TGPhotoEditorSliderView? - private var animatedEmojiLayer: InlineStickerItemLayer? - private var maxAnimatedEmojiLayer: InlineStickerItemLayer? - - private var item: CpmSliderItem? - private var layoutParams: ListViewItemLayoutParams? - private var reportedValue: Int32? - - init() { - self.backgroundNode = ASDisplayNode() - self.backgroundNode.isLayerBacked = true - - self.maskNode = ASImageNode() - - self.topStripeNode = ASDisplayNode() - self.topStripeNode.isLayerBacked = true - - self.bottomStripeNode = ASDisplayNode() - self.bottomStripeNode.isLayerBacked = true - - self.textNode = TextNode() - self.textNode.isUserInteractionEnabled = false - self.textNode.displaysAsynchronously = false - - self.minTextNode = TextNode() - self.minTextNode.isUserInteractionEnabled = false - self.minTextNode.displaysAsynchronously = false - - self.maxTextNode = TextNode() - self.maxTextNode.isUserInteractionEnabled = false - self.maxTextNode.displaysAsynchronously = false - - super.init(layerBacked: false, dynamicBounce: false) - - self.addSubnode(self.textNode) - self.addSubnode(self.minTextNode) - self.addSubnode(self.maxTextNode) - } - - override func didLoad() { - super.didLoad() - - self.view.disablesInteractiveTransitionGestureRecognizer = true - - let sliderView = TGPhotoEditorSliderView() - sliderView.enablePanHandling = true - sliderView.trackCornerRadius = 2.0 - sliderView.lineSize = 4.0 - sliderView.dotSize = 5.0 - sliderView.minimumValue = 0.0 - sliderView.maximumValue = 1.0 - sliderView.startValue = 0.0 - sliderView.displayEdges = true - sliderView.disablesInteractiveTransitionGestureRecognizer = true - if let item = self.item, let params = self.layoutParams { - sliderView.value = CGFloat(item.value) / 50.0 - sliderView.backgroundColor = item.theme.list.itemBlocksBackgroundColor - sliderView.backColor = item.theme.list.itemSwitchColors.frameColor - sliderView.startColor = item.theme.list.itemSwitchColors.frameColor - sliderView.trackColor = item.theme.list.itemAccentColor - sliderView.knobImage = PresentationResourcesItemList.knobImage(item.theme) - - sliderView.frame = CGRect(origin: CGPoint(x: params.leftInset + 15.0, y: 37.0), size: CGSize(width: params.width - params.leftInset - params.rightInset - 15.0 * 2.0, height: 44.0)) - sliderView.hitTestEdgeInsets = UIEdgeInsets(top: -sliderView.frame.minX, left: 0.0, bottom: 0.0, right: -sliderView.frame.minX) - } - self.view.addSubview(sliderView) - sliderView.addTarget(self, action: #selector(self.sliderValueChanged), for: .valueChanged) - self.sliderView = sliderView - } - - func asyncLayout() -> (_ item: CpmSliderItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) { - let currentItem = self.item - let makeTextLayout = TextNode.asyncLayout(self.textNode) - let makeMinTextLayout = TextNode.asyncLayout(self.minTextNode) - let makeMaxTextLayout = TextNode.asyncLayout(self.maxTextNode) - - return { item, params, neighbors in - var themeUpdated = false - if currentItem?.theme !== item.theme { - themeUpdated = true - } - - let contentSize: CGSize - let insets: UIEdgeInsets - let separatorHeight = UIScreenPixel - - //TODO:localize - let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.value == 0 ? "No Ads" : "\(item.value) CPM", font: Font.regular(17.0), textColor: item.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .center, lineSpacing: 0.0, cutout: nil, insets: UIEdgeInsets())) - - let (minTextLayout, minTextApply) = makeMinTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "No Ads", font: Font.regular(13.0), textColor: item.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .center, lineSpacing: 0.0, cutout: nil, insets: UIEdgeInsets())) - - let (maxTextLayout, maxTextApply) = makeMaxTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "50 CPM", font: Font.regular(13.0), textColor: item.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .center, lineSpacing: 0.0, cutout: nil, insets: UIEdgeInsets())) - - contentSize = CGSize(width: params.width, height: 88.0) - insets = itemListNeighborsGroupedInsets(neighbors, params) - - let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets) - let layoutSize = layout.size - - return (layout, { [weak self] in - if let strongSelf = self { - strongSelf.item = item - strongSelf.layoutParams = params - - strongSelf.backgroundNode.backgroundColor = item.theme.list.itemBlocksBackgroundColor - strongSelf.topStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor - strongSelf.bottomStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor - - if strongSelf.backgroundNode.supernode == nil { - strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0) - } - if strongSelf.topStripeNode.supernode == nil { - strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1) - } - if strongSelf.bottomStripeNode.supernode == nil { - strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) - } - if strongSelf.maskNode.supernode == nil { - strongSelf.insertSubnode(strongSelf.maskNode, at: 3) - } - let hasCorners = itemListHasRoundedBlockLayout(params) - var hasTopCorners = false - var hasBottomCorners = false - switch neighbors.top { - case .sameSection(false): - strongSelf.topStripeNode.isHidden = true - default: - hasTopCorners = true - strongSelf.topStripeNode.isHidden = hasCorners - } - let bottomStripeInset: CGFloat - let bottomStripeOffset: CGFloat - switch neighbors.bottom { - case .sameSection(false): - bottomStripeInset = 0.0 - bottomStripeOffset = -separatorHeight - strongSelf.bottomStripeNode.isHidden = false - default: - bottomStripeInset = 0.0 - hasBottomCorners = true - strongSelf.bottomStripeNode.isHidden = hasCorners - bottomStripeOffset = 0.0 - } - - strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil - - strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight))) - strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0) - strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight)) - strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight)) - - let _ = textApply() - let textFrame = CGRect(origin: CGPoint(x: floor((params.width - textLayout.size.width) / 2.0), y: 12.0), size: textLayout.size) - strongSelf.textNode.frame = textFrame - - if let animatedEmoji = item.animatedEmoji { - let itemSize = floorToScreenPixels(17.0 * 20.0 / 17.0) - - var itemFrame = CGRect(origin: CGPoint(x: textFrame.minX - itemSize / 2.0 - 1.0, y: textFrame.midY), size: CGSize()).insetBy(dx: -itemSize / 2.0, dy: -itemSize / 2.0) - itemFrame.origin.x = floorToScreenPixels(itemFrame.origin.x) - itemFrame.origin.y = floorToScreenPixels(itemFrame.origin.y) - - let itemLayer: InlineStickerItemLayer - if let current = strongSelf.animatedEmojiLayer { - itemLayer = current - } else { - let pointSize = floor(itemSize * 1.3) - itemLayer = InlineStickerItemLayer(context: item.context, userLocation: .other, attemptSynchronousLoad: true, emoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: animatedEmoji.fileId.id, file: animatedEmoji, custom: nil), file: animatedEmoji, cache: item.context.animationCache, renderer: item.context.animationRenderer, placeholderColor: item.theme.list.mediaPlaceholderColor, pointSize: CGSize(width: pointSize, height: pointSize), dynamicColor: nil) - strongSelf.animatedEmojiLayer = itemLayer - strongSelf.layer.addSublayer(itemLayer) - - itemLayer.isVisibleForAnimations = true - } - itemLayer.frame = itemFrame - } - - let _ = minTextApply() - strongSelf.minTextNode.frame = CGRect(origin: CGPoint(x: params.leftInset + 16.0, y: 16.0), size: minTextLayout.size) - - let _ = maxTextApply() - let maxTextFrame = CGRect(origin: CGPoint(x: params.width - params.rightInset - 16.0 - maxTextLayout.size.width, y: 16.0), size: maxTextLayout.size) - strongSelf.maxTextNode.frame = maxTextFrame - - if let animatedEmoji = item.animatedEmoji { - let itemSize = floorToScreenPixels(13.0 * 20.0 / 17.0) - - var itemFrame = CGRect(origin: CGPoint(x: maxTextFrame.minX - itemSize / 2.0 - 1.0, y: maxTextFrame.midY), size: CGSize()).insetBy(dx: -itemSize / 2.0, dy: -itemSize / 2.0) - itemFrame.origin.x = floorToScreenPixels(itemFrame.origin.x) - itemFrame.origin.y = floorToScreenPixels(itemFrame.origin.y) - - let itemLayer: InlineStickerItemLayer - if let current = strongSelf.maxAnimatedEmojiLayer { - itemLayer = current - } else { - let pointSize = floor(itemSize * 1.3) - itemLayer = InlineStickerItemLayer(context: item.context, userLocation: .other, attemptSynchronousLoad: true, emoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: animatedEmoji.fileId.id, file: animatedEmoji, custom: nil), file: animatedEmoji, cache: item.context.animationCache, renderer: item.context.animationRenderer, placeholderColor: item.theme.list.mediaPlaceholderColor, pointSize: CGSize(width: pointSize, height: pointSize), dynamicColor: nil) - strongSelf.maxAnimatedEmojiLayer = itemLayer - strongSelf.layer.addSublayer(itemLayer) - - itemLayer.isVisibleForAnimations = true - - if let filter = makeMonochromeFilter() { - filter.setValue([1.0, 1.0, 1.0, 1.0] as [NSNumber], forKey: "inputColor") - filter.setValue(1.0 as NSNumber, forKey: "inputAmount") - itemLayer.filters = [filter] - } - } - itemLayer.frame = itemFrame - } - - if let sliderView = strongSelf.sliderView { - if themeUpdated { - sliderView.backgroundColor = item.theme.list.itemBlocksBackgroundColor - sliderView.backColor = item.theme.list.itemSwitchColors.frameColor - sliderView.startColor = item.theme.list.itemSwitchColors.frameColor - sliderView.trackColor = item.theme.list.itemAccentColor - sliderView.knobImage = PresentationResourcesItemList.knobImage(item.theme) - } - - sliderView.frame = CGRect(origin: CGPoint(x: params.leftInset + 15.0, y: 37.0), size: CGSize(width: params.width - params.leftInset - params.rightInset - 15.0 * 2.0, height: 44.0)) - sliderView.hitTestEdgeInsets = UIEdgeInsets(top: -sliderView.frame.minX, left: 0.0, bottom: 0.0, right: -sliderView.frame.minX) - } - } - }) - } - } - - override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) { - self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4) - } - - override func animateRemoved(_ currentTimestamp: Double, duration: Double) { - self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) - } - - @objc func sliderValueChanged() { - guard let item = self.item, let sliderView = self.sliderView else { - return - } - item.updated(Int32(sliderView.value * 50.0)) - } -} From 6766f1358c688d26492f164d21118a1c7ad9f9fa Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 17 Apr 2024 01:49:15 +0400 Subject: [PATCH 02/11] Live location improvements --- .../Sources/LiveLocationManager.swift | 4 +-- .../ChatMessageLiveLocationTimerNode.swift | 2 ++ .../Sources/LocationViewController.swift | 30 +++++++++++-------- .../Sources/LocationViewControllerNode.swift | 24 +++++++-------- .../PendingMessages/RequestEditMessage.swift | 6 ++-- .../Messages/TelegramEngineMessages.swift | 4 +-- .../MediaEditorVideoFFMpegWriter.swift | 2 +- 7 files changed, 40 insertions(+), 32 deletions(-) diff --git a/submodules/LiveLocationManager/Sources/LiveLocationManager.swift b/submodules/LiveLocationManager/Sources/LiveLocationManager.swift index 7b98aec08e..4187f3b491 100644 --- a/submodules/LiveLocationManager/Sources/LiveLocationManager.swift +++ b/submodules/LiveLocationManager/Sources/LiveLocationManager.swift @@ -177,7 +177,7 @@ public final class LiveLocationManagerImpl: LiveLocationManager { let addedStopped = stopMessageIds.subtracting(self.stopMessageIds) self.stopMessageIds = stopMessageIds for id in addedStopped { - self.editMessageDisposables.set((self.engine.messages.requestEditLiveLocation(messageId: id, stop: true, coordinate: nil, heading: nil, proximityNotificationRadius: nil) + self.editMessageDisposables.set((self.engine.messages.requestEditLiveLocation(messageId: id, stop: true, coordinate: nil, heading: nil, proximityNotificationRadius: nil, extendPeriod: nil) |> deliverOn(self.queue)).start(completed: { [weak self] in if let strongSelf = self { strongSelf.editMessageDisposables.set(nil, forKey: id) @@ -232,7 +232,7 @@ public final class LiveLocationManagerImpl: LiveLocationManager { let ids = self.broadcastToMessageIds let remainingIds = Atomic>(value: Set(ids.keys)) for id in ids.keys { - self.editMessageDisposables.set((self.engine.messages.requestEditLiveLocation(messageId: id, stop: false, coordinate: (latitude: coordinate.latitude, longitude: coordinate.longitude, accuracyRadius: Int32(accuracyRadius)), heading: heading.flatMap { Int32($0) }, proximityNotificationRadius: nil) + self.editMessageDisposables.set((self.engine.messages.requestEditLiveLocation(messageId: id, stop: false, coordinate: (latitude: coordinate.latitude, longitude: coordinate.longitude, accuracyRadius: Int32(accuracyRadius)), heading: heading.flatMap { Int32($0) }, proximityNotificationRadius: nil, extendPeriod: nil) |> deliverOn(self.queue)).start(completed: { [weak self] in if let strongSelf = self { strongSelf.editMessageDisposables.set(nil, forKey: id) diff --git a/submodules/LiveLocationTimerNode/Sources/ChatMessageLiveLocationTimerNode.swift b/submodules/LiveLocationTimerNode/Sources/ChatMessageLiveLocationTimerNode.swift index 5ec0d8be44..8151cb0a2f 100644 --- a/submodules/LiveLocationTimerNode/Sources/ChatMessageLiveLocationTimerNode.swift +++ b/submodules/LiveLocationTimerNode/Sources/ChatMessageLiveLocationTimerNode.swift @@ -63,6 +63,8 @@ public final class ChatMessageLiveLocationTimerNode: ASDisplayNode { }), selector: #selector(RadialTimeoutNodeTimer.event), userInfo: nil, repeats: true) self.animationTimer = animationTimer RunLoop.main.add(animationTimer, forMode: .common) + + self.setNeedsDisplay() } } diff --git a/submodules/LocationUI/Sources/LocationViewController.swift b/submodules/LocationUI/Sources/LocationViewController.swift index 4d3d40dfc8..35fb7bb4d4 100644 --- a/submodules/LocationUI/Sources/LocationViewController.swift +++ b/submodules/LocationUI/Sources/LocationViewController.swift @@ -47,12 +47,12 @@ class LocationViewInteraction { let share: () -> Void let setupProximityNotification: (Bool, EngineMessage.Id?) -> Void let updateSendActionHighlight: (Bool) -> Void - let sendLiveLocation: (Int32?, Bool) -> Void + let sendLiveLocation: (Int32?, Bool, EngineMessage.Id?) -> Void let stopLiveLocation: () -> Void let updateRightBarButton: (LocationViewRightBarButton) -> Void let present: (ViewController) -> Void - init(toggleMapModeSelection: @escaping () -> Void, updateMapMode: @escaping (LocationMapMode) -> Void, toggleTrackingMode: @escaping () -> Void, goToCoordinate: @escaping (CLLocationCoordinate2D) -> Void, requestDirections: @escaping (TelegramMediaMap, String?, OpenInLocationDirections) -> Void, share: @escaping () -> Void, setupProximityNotification: @escaping (Bool, EngineMessage.Id?) -> Void, updateSendActionHighlight: @escaping (Bool) -> Void, sendLiveLocation: @escaping (Int32?, Bool) -> Void, stopLiveLocation: @escaping () -> Void, updateRightBarButton: @escaping (LocationViewRightBarButton) -> Void, present: @escaping (ViewController) -> Void) { + init(toggleMapModeSelection: @escaping () -> Void, updateMapMode: @escaping (LocationMapMode) -> Void, toggleTrackingMode: @escaping () -> Void, goToCoordinate: @escaping (CLLocationCoordinate2D) -> Void, requestDirections: @escaping (TelegramMediaMap, String?, OpenInLocationDirections) -> Void, share: @escaping () -> Void, setupProximityNotification: @escaping (Bool, EngineMessage.Id?) -> Void, updateSendActionHighlight: @escaping (Bool) -> Void, sendLiveLocation: @escaping (Int32?, Bool, EngineMessage.Id?) -> Void, stopLiveLocation: @escaping () -> Void, updateRightBarButton: @escaping (LocationViewRightBarButton) -> Void, present: @escaping (ViewController) -> Void) { self.toggleMapModeSelection = toggleMapModeSelection self.updateMapMode = updateMapMode self.toggleTrackingMode = toggleTrackingMode @@ -214,7 +214,7 @@ public final class LocationViewController: ViewController { return state } - let _ = context.engine.messages.requestEditLiveLocation(messageId: messageId, stop: false, coordinate: nil, heading: nil, proximityNotificationRadius: 0).start(completed: { [weak self] in + let _ = context.engine.messages.requestEditLiveLocation(messageId: messageId, stop: false, coordinate: nil, heading: nil, proximityNotificationRadius: 0, extendPeriod: nil).start(completed: { [weak self] in guard let strongSelf = self else { return } @@ -283,7 +283,7 @@ public final class LocationViewController: ViewController { return state } - let _ = context.engine.messages.requestEditLiveLocation(messageId: messageId, stop: false, coordinate: nil, heading: nil, proximityNotificationRadius: distance).start(completed: { [weak self] in + let _ = context.engine.messages.requestEditLiveLocation(messageId: messageId, stop: false, coordinate: nil, heading: nil, proximityNotificationRadius: distance, extendPeriod: nil).start(completed: { [weak self] in guard let strongSelf = self else { return } @@ -323,7 +323,7 @@ public final class LocationViewController: ViewController { } else { strongSelf.present(textAlertController(context: strongSelf.context, updatedPresentationData: updatedPresentationData, title: strongSelf.presentationData.strings.Location_LiveLocationRequired_Title, text: strongSelf.presentationData.strings.Location_LiveLocationRequired_Description, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Location_LiveLocationRequired_ShareLocation, action: { completion() - strongSelf.interaction?.sendLiveLocation(distance, false) + strongSelf.interaction?.sendLiveLocation(distance, false, nil) }), TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {})], actionLayout: .vertical), in: .window(.root)) } completion() @@ -341,7 +341,7 @@ public final class LocationViewController: ViewController { return } strongSelf.controllerNode.updateSendActionHighlight(highlighted) - }, sendLiveLocation: { [weak self] distance, extend in + }, sendLiveLocation: { [weak self] distance, extend, messageId in guard let strongSelf = self else { return } @@ -413,12 +413,18 @@ public final class LocationViewController: ViewController { let sendLiveLocationImpl: (Int32) -> Void = { [weak controller] period in controller?.dismissAnimated() - let _ = (strongSelf.controllerNode.coordinate - |> deliverOnMainQueue).start(next: { coordinate in - params.sendLiveLocation(TelegramMediaMap(coordinate: coordinate, liveBroadcastingTimeout: period)) - }) - - strongSelf.controllerNode.showAll() + if extend { + if let messageId { + let _ = context.engine.messages.requestEditLiveLocation(messageId: messageId, stop: false, coordinate: nil, heading: nil, proximityNotificationRadius: nil, extendPeriod: period).start() + } + } else { + let _ = (strongSelf.controllerNode.coordinate + |> deliverOnMainQueue).start(next: { coordinate in + params.sendLiveLocation(TelegramMediaMap(coordinate: coordinate, liveBroadcastingTimeout: period)) + }) + + strongSelf.controllerNode.showAll() + } } controller.setItemGroups([ diff --git a/submodules/LocationUI/Sources/LocationViewControllerNode.swift b/submodules/LocationUI/Sources/LocationViewControllerNode.swift index 9ee4346514..5fa0cbcae1 100644 --- a/submodules/LocationUI/Sources/LocationViewControllerNode.swift +++ b/submodules/LocationUI/Sources/LocationViewControllerNode.swift @@ -48,14 +48,14 @@ private enum LocationViewEntryId: Hashable { private enum LocationViewEntry: Comparable, Identifiable { case info(PresentationTheme, TelegramMediaMap, String?, Double?, ExpectedTravelTime, ExpectedTravelTime, ExpectedTravelTime, Bool) - case toggleLiveLocation(PresentationTheme, String, String, Double?, Double?, Bool) + case toggleLiveLocation(PresentationTheme, String, String, Double?, Double?, Bool, EngineMessage.Id?) case liveLocation(PresentationTheme, PresentationDateTimeFormat, PresentationPersonNameOrder, EngineMessage, Double?, ExpectedTravelTime, ExpectedTravelTime, ExpectedTravelTime, Int) var stableId: LocationViewEntryId { switch self { case .info: return .info - case let .toggleLiveLocation(_, _, _, _, _, additional): + case let .toggleLiveLocation(_, _, _, _, _, additional, _): return .toggleLiveLocation(additional) case let .liveLocation(_, _, _, message, _, _, _, _, _): return .liveLocation(message.stableId) @@ -70,8 +70,8 @@ private enum LocationViewEntry: Comparable, Identifiable { } else { return false } - case let .toggleLiveLocation(lhsTheme, lhsTitle, lhsSubtitle, lhsBeginTimestamp, lhsTimeout, lhsAdditional): - if case let .toggleLiveLocation(rhsTheme, rhsTitle, rhsSubtitle, rhsBeginTimestamp, rhsTimeout, rhsAdditional) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsSubtitle == rhsSubtitle, lhsBeginTimestamp == rhsBeginTimestamp, lhsTimeout == rhsTimeout, lhsAdditional == rhsAdditional { + case let .toggleLiveLocation(lhsTheme, lhsTitle, lhsSubtitle, lhsBeginTimestamp, lhsTimeout, lhsAdditional, lhsMessageId): + if case let .toggleLiveLocation(rhsTheme, rhsTitle, rhsSubtitle, rhsBeginTimestamp, rhsTimeout, rhsAdditional, rhsMessageId) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsSubtitle == rhsSubtitle, lhsBeginTimestamp == rhsBeginTimestamp, lhsTimeout == rhsTimeout, lhsAdditional == rhsAdditional, lhsMessageId == rhsMessageId { return true } else { return false @@ -94,11 +94,11 @@ private enum LocationViewEntry: Comparable, Identifiable { case .toggleLiveLocation, .liveLocation: return true } - case let .toggleLiveLocation(_, _, _, _, _, lhsAdditional): + case let .toggleLiveLocation(_, _, _, _, _, lhsAdditional, _): switch rhs { case .info: return false - case let .toggleLiveLocation(_, _, _, _, _, rhsAdditional): + case let .toggleLiveLocation(_, _, _, _, _, rhsAdditional, _): return !lhsAdditional && rhsAdditional case .liveLocation: return true @@ -137,7 +137,7 @@ private enum LocationViewEntry: Comparable, Identifiable { }, walkingAction: { interaction?.requestDirections(location, nil, .walking) }) - case let .toggleLiveLocation(_, title, subtitle, beginTimstamp, timeout, additional): + case let .toggleLiveLocation(_, title, subtitle, beginTimstamp, timeout, additional, messageId): var beginTimeAndTimeout: (Double, Double)? if let beginTimstamp = beginTimstamp, let timeout = timeout { beginTimeAndTimeout = (beginTimstamp, timeout) @@ -160,13 +160,13 @@ private enum LocationViewEntry: Comparable, Identifiable { if additional { interaction?.stopLiveLocation() } else { - interaction?.sendLiveLocation(nil, true) + interaction?.sendLiveLocation(nil, true, messageId) } } else { interaction?.stopLiveLocation() } } else { - interaction?.sendLiveLocation(nil, false) + interaction?.sendLiveLocation(nil, false, nil) } }, highlighted: { highlight in interaction?.updateSendActionHighlight(highlight) @@ -442,10 +442,10 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan if case let .channel(channel) = subject.author, case .broadcast = channel.info, activeOwnLiveLocation == nil { } else { if let timeout, Int32(timeout) != liveLocationIndefinitePeriod { - entries.append(.toggleLiveLocation(presentationData.theme, presentationData.strings.Map_SharingLocation, presentationData.strings.Map_TapToAddTime, beginTime, timeout, false)) - entries.append(.toggleLiveLocation(presentationData.theme, title, subtitle, beginTime, timeout, true)) + entries.append(.toggleLiveLocation(presentationData.theme, presentationData.strings.Map_SharingLocation, presentationData.strings.Map_TapToAddTime, beginTime, timeout, false, activeOwnLiveLocation?.id)) + entries.append(.toggleLiveLocation(presentationData.theme, title, subtitle, beginTime, timeout, true, nil)) } else { - entries.append(.toggleLiveLocation(presentationData.theme, title, subtitle, beginTime, timeout, false)) + entries.append(.toggleLiveLocation(presentationData.theme, title, subtitle, beginTime, timeout, false, nil)) } } diff --git a/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift b/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift index 8744792086..dd0bd00b7c 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift @@ -263,7 +263,7 @@ private func requestEditMessageInternal(accountPeerId: PeerId, postbox: Postbox, } } -func _internal_requestEditLiveLocation(postbox: Postbox, network: Network, stateManager: AccountStateManager, messageId: MessageId, stop: Bool, coordinate: (latitude: Double, longitude: Double, accuracyRadius: Int32?)?, heading: Int32?, proximityNotificationRadius: Int32?) -> Signal { +func _internal_requestEditLiveLocation(postbox: Postbox, network: Network, stateManager: AccountStateManager, messageId: MessageId, stop: Bool, coordinate: (latitude: Double, longitude: Double, accuracyRadius: Int32?)?, heading: Int32?, proximityNotificationRadius: Int32?, extendPeriod: Int32?) -> Signal { return postbox.transaction { transaction -> (Api.InputPeer, TelegramMediaMap)? in guard let inputPeer = transaction.getPeer(messageId.peerId).flatMap(apiInputPeer) else { return nil @@ -305,7 +305,7 @@ func _internal_requestEditLiveLocation(postbox: Postbox, network: Network, state if let _ = proximityNotificationRadius { flags |= 1 << 3 } - inputMedia = .inputMediaGeoLive(flags: flags, geoPoint: inputGeoPoint, heading: heading, period: liveBroadcastingTimeout, proximityNotificationRadius: proximityNotificationRadius) + inputMedia = .inputMediaGeoLive(flags: flags, geoPoint: inputGeoPoint, heading: heading, period: extendPeriod.flatMap { $0 + liveBroadcastingTimeout } ?? liveBroadcastingTimeout, proximityNotificationRadius: proximityNotificationRadius) } else { inputMedia = .inputMediaGeoLive(flags: 1 << 0, geoPoint: .inputGeoPoint(flags: 0, lat: media.latitude, long: media.longitude, accuracyRadius: nil), heading: nil, period: nil, proximityNotificationRadius: nil) } @@ -319,7 +319,7 @@ func _internal_requestEditLiveLocation(postbox: Postbox, network: Network, state if let updates = updates { stateManager.addUpdates(updates) } - if coordinate == nil && proximityNotificationRadius == nil { + if coordinate == nil && proximityNotificationRadius == nil && extendPeriod == nil { return postbox.transaction { transaction -> Void in transaction.updateMessage(messageId, update: { currentMessage in var storeForwardInfo: StoreMessageForwardInfo? diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift index 3cd072ebc3..21c32fca7c 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift @@ -130,8 +130,8 @@ public extension TelegramEngine { return _internal_requestEditMessage(account: self.account, messageId: messageId, text: text, media: media, entities: entities, inlineStickers: inlineStickers, webpagePreviewAttribute: webpagePreviewAttribute, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime) } - public func requestEditLiveLocation(messageId: MessageId, stop: Bool, coordinate: (latitude: Double, longitude: Double, accuracyRadius: Int32?)?, heading: Int32?, proximityNotificationRadius: Int32?) -> Signal { - return _internal_requestEditLiveLocation(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, messageId: messageId, stop: stop, coordinate: coordinate, heading: heading, proximityNotificationRadius: proximityNotificationRadius) + public func requestEditLiveLocation(messageId: MessageId, stop: Bool, coordinate: (latitude: Double, longitude: Double, accuracyRadius: Int32?)?, heading: Int32?, proximityNotificationRadius: Int32?, extendPeriod: Int32?) -> Signal { + return _internal_requestEditLiveLocation(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, messageId: messageId, stop: stop, coordinate: coordinate, heading: heading, proximityNotificationRadius: proximityNotificationRadius, extendPeriod: extendPeriod) } public func addSecretChatMessageScreenshot(peerId: PeerId) -> Signal { diff --git a/submodules/TelegramUI/Components/MediaEditor/Sources/MediaEditorVideoFFMpegWriter.swift b/submodules/TelegramUI/Components/MediaEditor/Sources/MediaEditorVideoFFMpegWriter.swift index a7c5fd134f..9f9557616c 100644 --- a/submodules/TelegramUI/Components/MediaEditor/Sources/MediaEditorVideoFFMpegWriter.swift +++ b/submodules/TelegramUI/Components/MediaEditor/Sources/MediaEditorVideoFFMpegWriter.swift @@ -46,7 +46,7 @@ final class MediaEditorVideoFFMpegWriter: MediaEditorVideoExportWriter { } self.pool = pool - if !self.ffmpegWriter.setup(withOutputPath: outputPath, width: width, height: height, bitrate: 200 * 1000, framerate: 30) { + if !self.ffmpegWriter.setup(withOutputPath: outputPath, width: width, height: height, bitrate: 240 * 1000, framerate: 30) { self.status = .failed } } From 96cbf5c4781a7cb26e9b6afd900e6b4fbae0cebd Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 17 Apr 2024 01:50:18 +0400 Subject: [PATCH 03/11] Fix typo --- submodules/TelegramUI/Sources/ChatController.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 4c4bb60dab..e6050dcbb3 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -15521,12 +15521,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return } - let dismissWebAppContollers: () -> Void = { + let dismissWebAppControllers: () -> Void = { } switch navigation { case let .chat(textInputState, subject, peekData): - dismissWebAppContollers() + dismissWebAppControllers() if case .peer(peerId.id) = strongSelf.chatLocation { if let subject = subject, case let .message(messageSubject, _, timecode) = subject { if case let .id(messageId) = messageSubject { @@ -15544,7 +15544,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } commit() case .info: - dismissWebAppContollers() + dismissWebAppControllers() strongSelf.navigationActionDisposable.set((strongSelf.context.account.postbox.loadedPeerWithId(peerId.id) |> take(1) |> deliverOnMainQueue).startStrict(next: { [weak self] peer in @@ -15556,7 +15556,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G })) commit() case let .withBotStartPayload(startPayload): - dismissWebAppContollers() + dismissWebAppControllers() if case .peer(peerId.id) = strongSelf.chatLocation { strongSelf.startBot(startPayload.payload) } else if let navigationController = strongSelf.effectiveNavigationController { @@ -15564,7 +15564,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } commit() case let .withAttachBot(attachBotStart): - dismissWebAppContollers() + dismissWebAppControllers() if let navigationController = strongSelf.effectiveNavigationController { strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), attachBotStart: attachBotStart)) } @@ -15574,7 +15574,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G |> deliverOnMainQueue).startStandalone(next: { [weak self] peer in if let strongSelf = self, let peer { strongSelf.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, concealed: concealed, commit: { - dismissWebAppContollers() + dismissWebAppControllers() commit() }) } From 1326d63b89623e5b44446eab71902902affa3342 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 17 Apr 2024 01:58:46 +0400 Subject: [PATCH 04/11] Fix indefinite live location extension --- .../PendingMessages/RequestEditMessage.swift | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift b/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift index dd0bd00b7c..d9dd993fbf 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift @@ -305,7 +305,19 @@ func _internal_requestEditLiveLocation(postbox: Postbox, network: Network, state if let _ = proximityNotificationRadius { flags |= 1 << 3 } - inputMedia = .inputMediaGeoLive(flags: flags, geoPoint: inputGeoPoint, heading: heading, period: extendPeriod.flatMap { $0 + liveBroadcastingTimeout } ?? liveBroadcastingTimeout, proximityNotificationRadius: proximityNotificationRadius) + + let period: Int32 + if let extendPeriod { + if extendPeriod == liveLocationIndefinitePeriod { + period = extendPeriod + } else { + period = liveBroadcastingTimeout + extendPeriod + } + } else { + period = liveBroadcastingTimeout + } + + inputMedia = .inputMediaGeoLive(flags: flags, geoPoint: inputGeoPoint, heading: heading, period: period, proximityNotificationRadius: proximityNotificationRadius) } else { inputMedia = .inputMediaGeoLive(flags: 1 << 0, geoPoint: .inputGeoPoint(flags: 0, lat: media.latitude, long: media.longitude, accuracyRadius: nil), heading: nil, period: nil, proximityNotificationRadius: nil) } From 60652f34ee8ea4109a10fc4afb1bf58cf857a159 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 17 Apr 2024 16:04:23 +0400 Subject: [PATCH 05/11] Pass thread info in Recent Actions [skip ci] --- .../Peers/ChannelAdminEventLogs.swift | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChannelAdminEventLogs.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChannelAdminEventLogs.swift index 3ece75f732..4efffb59c8 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChannelAdminEventLogs.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChannelAdminEventLogs.swift @@ -181,6 +181,14 @@ func channelAdminLogEvents(accountPeerId: PeerId, postbox: Postbox, network: Net var events: [AdminLogEvent] = [] + func renderedMessage(message: StoreMessage) -> Message? { + var associatedThreadInfo: Message.AssociatedThreadInfo? + if let threadId = message.threadId, let threadInfo = transaction.getMessageHistoryThreadInfo(peerId: message.id.peerId, threadId: threadId) { + associatedThreadInfo = postbox.seedConfiguration.decodeMessageThreadInfo(threadInfo.data) + } + return locallyRenderedMessage(message: message, peers: peers, associatedThreadInfo: associatedThreadInfo) + } + for event in apiEvents { switch event { case let .channelAdminLogEvent(id, date, userId, apiAction): @@ -205,16 +213,16 @@ func channelAdminLogEvents(accountPeerId: PeerId, postbox: Postbox, network: Net case .messageEmpty: action = .updatePinned(nil) default: - if let message = StoreMessage(apiMessage: new, accountPeerId: accountPeerId, peerIsForum: peer.isForum), let rendered = locallyRenderedMessage(message: message, peers: peers) { + if let message = StoreMessage(apiMessage: new, accountPeerId: accountPeerId, peerIsForum: peer.isForum), let rendered = renderedMessage(message: message) { action = .updatePinned(rendered) } } case let .channelAdminLogEventActionEditMessage(prev, new): - if let prev = StoreMessage(apiMessage: prev, accountPeerId: accountPeerId, peerIsForum: peer.isForum), let prevRendered = locallyRenderedMessage(message: prev, peers: peers), let new = StoreMessage(apiMessage: new, accountPeerId: accountPeerId, peerIsForum: peer.isForum), let newRendered = locallyRenderedMessage(message: new, peers: peers) { + if let prev = StoreMessage(apiMessage: prev, accountPeerId: accountPeerId, peerIsForum: peer.isForum), let prevRendered = renderedMessage(message: prev), let new = StoreMessage(apiMessage: new, accountPeerId: accountPeerId, peerIsForum: peer.isForum), let newRendered = renderedMessage(message: new) { action = .editMessage(prev: prevRendered, new: newRendered) } case let .channelAdminLogEventActionDeleteMessage(message): - if let message = StoreMessage(apiMessage: message, accountPeerId: accountPeerId, peerIsForum: peer.isForum), let rendered = locallyRenderedMessage(message: message, peers: peers) { + if let message = StoreMessage(apiMessage: message, accountPeerId: accountPeerId, peerIsForum: peer.isForum), let rendered = renderedMessage(message: message) { action = .deleteMessage(rendered) } case .channelAdminLogEventActionParticipantJoin: @@ -248,7 +256,7 @@ func channelAdminLogEvents(accountPeerId: PeerId, postbox: Postbox, network: Net case let .channelAdminLogEventActionDefaultBannedRights(prevBannedRights, newBannedRights): action = .updateDefaultBannedRights(prev: TelegramChatBannedRights(apiBannedRights: prevBannedRights), new: TelegramChatBannedRights(apiBannedRights: newBannedRights)) case let .channelAdminLogEventActionStopPoll(message): - if let message = StoreMessage(apiMessage: message, accountPeerId: accountPeerId, peerIsForum: peer.isForum), let rendered = locallyRenderedMessage(message: message, peers: peers) { + if let message = StoreMessage(apiMessage: message, accountPeerId: accountPeerId, peerIsForum: peer.isForum), let rendered = renderedMessage(message: message) { action = .pollStopped(rendered) } case let .channelAdminLogEventActionChangeLinkedChat(prevValue, newValue): @@ -287,7 +295,7 @@ func channelAdminLogEvents(accountPeerId: PeerId, postbox: Postbox, network: Net case let .channelAdminLogEventActionToggleNoForwards(new): action = .toggleCopyProtection(boolFromApiValue(new)) case let .channelAdminLogEventActionSendMessage(message): - if let message = StoreMessage(apiMessage: message, accountPeerId: accountPeerId, peerIsForum: peer.isForum), let rendered = locallyRenderedMessage(message: message, peers: peers) { + if let message = StoreMessage(apiMessage: message, accountPeerId: accountPeerId, peerIsForum: peer.isForum), let rendered = renderedMessage(message: message) { action = .sendMessage(rendered) } case let .channelAdminLogEventActionChangeAvailableReactions(prevValue, newValue): From ff09220634e5300cfbd99bc9125c07482387bf6c Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 17 Apr 2024 21:04:14 +0400 Subject: [PATCH 06/11] Recent Actions improvements --- .../Telegram-iOS/en.lproj/Localizable.strings | 2 + .../BUILD | 4 +- .../Sources/CounterControllerTitleView.swift} | 6 +- submodules/SettingsUI/BUILD | 2 +- .../Themes/ThemePreviewController.swift | 10 +- submodules/TelegramUI/BUILD | 2 +- .../Sources/ChatMessageBubbleItemNode.swift | 2 +- .../Sources/ChatMessageThreadInfoNode.swift | 8 +- .../Chat/ChatRecentActionsController/BUILD | 1 + .../Sources/ChatRecentActionsController.swift | 48 ++++---- .../ChatRecentActionsControllerNode.swift | 83 +++++++++++-- .../Sources/ChatRecentActionsEmptyNode.swift | 33 ++++-- .../ChatRecentActionsHistoryTransition.swift | 40 ++++++- .../Settings/WallpaperGalleryScreen/BUILD | 2 +- .../Sources/WallpaperGalleryController.swift | 6 +- .../Chat/Recent Actions/Contents.json | 9 ++ .../Info.imageset/Contents.json | 12 ++ .../Info.imageset/question.circle.pdf | 99 ++++++++++++++++ .../Placeholder.imageset/Contents.json | 12 ++ .../Placeholder.imageset/recentactions.pdf | 110 ++++++++++++++++++ .../ContactMultiselectionController.swift | 24 ++-- submodules/WebUI/BUILD | 2 +- .../WebUI/Sources/WebAppController.swift | 8 +- 23 files changed, 440 insertions(+), 85 deletions(-) rename submodules/{CounterContollerTitleView => CounterControllerTitleView}/BUILD (83%) rename submodules/{CounterContollerTitleView/Sources/CounterContollerTitleView.swift => CounterControllerTitleView/Sources/CounterControllerTitleView.swift} (95%) create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Info.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Info.imageset/question.circle.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Placeholder.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Placeholder.imageset/recentactions.pdf diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index a960050c2a..f1aac17973 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -12089,3 +12089,5 @@ Sorry for the inconvenience."; "Map.SharingLocation" = "Sharing Location..."; "Channel.AdminLog.Settings" = "Settings"; + +"Conversation.ContextMenuBanFull" = "Ban"; diff --git a/submodules/CounterContollerTitleView/BUILD b/submodules/CounterControllerTitleView/BUILD similarity index 83% rename from submodules/CounterContollerTitleView/BUILD rename to submodules/CounterControllerTitleView/BUILD index 7ad134d009..f63f0315bb 100644 --- a/submodules/CounterContollerTitleView/BUILD +++ b/submodules/CounterControllerTitleView/BUILD @@ -1,8 +1,8 @@ load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") swift_library( - name = "CounterContollerTitleView", - module_name = "CounterContollerTitleView", + name = "CounterControllerTitleView", + module_name = "CounterControllerTitleView", srcs = glob([ "Sources/**/*.swift", ]), diff --git a/submodules/CounterContollerTitleView/Sources/CounterContollerTitleView.swift b/submodules/CounterControllerTitleView/Sources/CounterControllerTitleView.swift similarity index 95% rename from submodules/CounterContollerTitleView/Sources/CounterContollerTitleView.swift rename to submodules/CounterControllerTitleView/Sources/CounterControllerTitleView.swift index 17c9e99ac0..42d3b93faa 100644 --- a/submodules/CounterContollerTitleView/Sources/CounterContollerTitleView.swift +++ b/submodules/CounterControllerTitleView/Sources/CounterControllerTitleView.swift @@ -4,7 +4,7 @@ import Display import AsyncDisplayKit import TelegramPresentationData -public struct CounterContollerTitle: Equatable { +public struct CounterControllerTitle: Equatable { public var title: String public var counter: String @@ -14,11 +14,11 @@ public struct CounterContollerTitle: Equatable { } } -public final class CounterContollerTitleView: UIView { +public final class CounterControllerTitleView: UIView { private let titleNode: ImmediateTextNode private let subtitleNode: ImmediateTextNode - public var title: CounterContollerTitle = CounterContollerTitle(title: "", counter: "") { + public var title: CounterControllerTitle = CounterControllerTitle(title: "", counter: "") { didSet { if self.title != oldValue { self.update() diff --git a/submodules/SettingsUI/BUILD b/submodules/SettingsUI/BUILD index 228236a2bc..347920fa64 100644 --- a/submodules/SettingsUI/BUILD +++ b/submodules/SettingsUI/BUILD @@ -77,7 +77,7 @@ swift_library( "//submodules/AuthorizationUI:AuthorizationUI", "//submodules/InstantPageUI:InstantPageUI", "//submodules/CheckNode:CheckNode", - "//submodules/CounterContollerTitleView:CounterContollerTitleView", + "//submodules/CounterControllerTitleView:CounterControllerTitleView", "//submodules/GridMessageSelectionNode:GridMessageSelectionNode", "//submodules/InstantPageCache:InstantPageCache", "//submodules/AppBundle:AppBundle", diff --git a/submodules/SettingsUI/Sources/Themes/ThemePreviewController.swift b/submodules/SettingsUI/Sources/Themes/ThemePreviewController.swift index 102f847329..d000c3da2b 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemePreviewController.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemePreviewController.swift @@ -9,7 +9,7 @@ import TelegramPresentationData import TelegramUIPreferences import AccountContext import ShareController -import CounterContollerTitleView +import CounterControllerTitleView import WallpaperResources import OverlayStatusController import AppBundle @@ -139,8 +139,8 @@ public final class ThemePreviewController: ViewController { isPreview = true } - let titleView = CounterContollerTitleView(theme: self.previewTheme) - titleView.title = CounterContollerTitle(title: themeName, counter: hasInstallsCount ? " " : "") + let titleView = CounterControllerTitleView(theme: self.previewTheme) + titleView.title = CounterControllerTitle(title: themeName, counter: hasInstallsCount ? " " : "") self.navigationItem.titleView = titleView self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed)) @@ -154,8 +154,8 @@ public final class ThemePreviewController: ViewController { self.disposable = (combineLatest(self.theme.get(), self.presentationTheme.get()) |> deliverOnMainQueue).start(next: { [weak self] theme, presentationTheme in if let strongSelf = self, let theme = theme { - let titleView = CounterContollerTitleView(theme: strongSelf.previewTheme) - titleView.title = CounterContollerTitle(title: themeName, counter: hasInstallsCount ? strongSelf.presentationData.strings.Theme_UsersCount(max(1, theme.installCount ?? 0)) : "") + let titleView = CounterControllerTitleView(theme: strongSelf.previewTheme) + titleView.title = CounterControllerTitle(title: themeName, counter: hasInstallsCount ? strongSelf.presentationData.strings.Theme_UsersCount(max(1, theme.installCount ?? 0)) : "") strongSelf.navigationItem.titleView = titleView strongSelf.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationTheme: presentationTheme, presentationStrings: strongSelf.presentationData.strings)) } diff --git a/submodules/TelegramUI/BUILD b/submodules/TelegramUI/BUILD index 9a7c974d27..867c3ef62c 100644 --- a/submodules/TelegramUI/BUILD +++ b/submodules/TelegramUI/BUILD @@ -201,7 +201,7 @@ swift_library( "//submodules/QrCode:QrCode", "//submodules/WallpaperResources:WallpaperResources", "//submodules/AuthorizationUI:AuthorizationUI", - "//submodules/CounterContollerTitleView:CounterContollerTitleView", + "//submodules/CounterControllerTitleView:CounterControllerTitleView", "//submodules/GridMessageSelectionNode:GridMessageSelectionNode", "//submodules/InstantPageCache:InstantPageCache", "//submodules/PersistentStringHash:PersistentStringHash", diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift index 6f81354381..ea196dfb69 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift @@ -2366,7 +2366,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI } var hasReply = replyMessage != nil || replyForward != nil || replyStory != nil - if !isInstantVideo, case let .peer(peerId) = item.chatLocation, (peerId == replyMessage?.id.peerId || item.message.threadId == 1), let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum), item.message.associatedThreadInfo != nil { + if !isInstantVideo, case let .peer(peerId) = item.chatLocation, (peerId == replyMessage?.id.peerId || item.message.threadId == 1 || item.associatedData.isRecentActions), let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum), item.message.associatedThreadInfo != nil { if let threadId = item.message.threadId, let replyMessage = replyMessage, Int64(replyMessage.id.id) == threadId { hasReply = false } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageThreadInfoNode/Sources/ChatMessageThreadInfoNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageThreadInfoNode/Sources/ChatMessageThreadInfoNode.swift index 1fab74cb24..f8f4523fd8 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageThreadInfoNode/Sources/ChatMessageThreadInfoNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageThreadInfoNode/Sources/ChatMessageThreadInfoNode.swift @@ -481,8 +481,12 @@ public class ChatMessageThreadInfoNode: ASDisplayNode { } let titleTopicIconContent: EmojiStatusComponent.Content + var containerSize: CGSize = CGSize(width: 22.0, height: 22.0) + var iconX: CGFloat = 0.0 if arguments.threadId == 1 { titleTopicIconContent = .image(image: generalThreadIcon) + containerSize = CGSize(width: 18.0, height: 18.0) + iconX = 3.0 } else if let fileId = topicIconId, fileId != 0 { titleTopicIconContent = .animation(content: .customEmoji(fileId: fileId), size: CGSize(width: 36.0, height: 36.0), placeholderColor: arguments.presentationData.theme.theme.list.mediaPlaceholderColor, themeColor: arguments.presentationData.theme.theme.list.itemAccentColor, loopMode: .count(1)) } else { @@ -504,7 +508,7 @@ public class ChatMessageThreadInfoNode: ASDisplayNode { transition: .immediate, component: AnyComponent(titleTopicIconComponent), environment: {}, - containerSize: CGSize(width: 22.0, height: 22.0) + containerSize: containerSize ) let iconY: CGFloat @@ -514,7 +518,7 @@ public class ChatMessageThreadInfoNode: ASDisplayNode { iconY = 0.0 } - titleTopicIconView.frame = CGRect(origin: CGPoint(x: insets.left, y: insets.top + iconY), size: iconSize) + titleTopicIconView.frame = CGRect(origin: CGPoint(x: insets.left + iconX, y: insets.top + iconY), size: iconSize) } let textFrame = CGRect(origin: CGPoint(x: iconSize.width + 2.0 + insets.left, y: insets.top), size: textLayout.size) diff --git a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/BUILD b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/BUILD index 6869a58873..740cd3852d 100644 --- a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/BUILD +++ b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/BUILD @@ -48,6 +48,7 @@ swift_library( "//submodules/UndoUI", "//submodules/WallpaperBackgroundNode", "//submodules/TextFormat", + "//submodules/CounterControllerTitleView" ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsController.swift b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsController.swift index 47f0d60b62..5cbdfd5789 100644 --- a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsController.swift +++ b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsController.swift @@ -11,6 +11,7 @@ import AlertUI import PresentationDataUtils import ChatPresentationInterfaceState import ChatNavigationButton +import CounterControllerTitleView public final class ChatRecentActionsController: TelegramBaseController { private var controllerNode: ChatRecentActionsControllerNode { @@ -28,10 +29,10 @@ public final class ChatRecentActionsController: TelegramBaseController { private var presentationDataDisposable: Disposable? private var didSetPresentationData = false - private var interaction: ChatRecentActionsInteraction! private var panelInteraction: ChatPanelInterfaceInteraction! - private let titleView: ChatRecentActionsTitleView + private let titleView: CounterControllerTitleView + private var rightBarButton: ChatNavigationButton? public init(context: AccountContext, peer: Peer, adminPeerId: PeerId?) { self.context = context @@ -40,7 +41,7 @@ public final class ChatRecentActionsController: TelegramBaseController { self.presentationData = context.sharedContext.currentPresentationData.with { $0 } - self.titleView = ChatRecentActionsTitleView(color: self.presentationData.theme.rootController.navigationBar.primaryTextColor) + self.titleView = CounterControllerTitleView(theme: self.presentationData.theme) super.init(context: context, navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData), mediaAccessoryPanelVisibility: .specific(size: .compact), locationBroadcastPanelSource: .none, groupCallPanelSource: .none) @@ -48,18 +49,6 @@ public final class ChatRecentActionsController: TelegramBaseController { self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style - self.interaction = ChatRecentActionsInteraction(displayInfoAlert: { [weak self] in - if let strongSelf = self { - let text: String - if let channel = peer as? TelegramChannel, case .broadcast = channel.info { - text = strongSelf.presentationData.strings.Channel_AdminLog_InfoPanelChannelAlertText - } else { - text = strongSelf.presentationData.strings.Channel_AdminLog_InfoPanelAlertText - } - self?.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: strongSelf.presentationData.strings.Channel_AdminLog_InfoPanelAlertTitle, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) - } - }) - self.panelInteraction = ChatPanelInterfaceInteraction(setupReplyMessage: { _, _ in }, setupEditMessage: { _, _ in }, beginMessageSelection: { _, _ in @@ -181,13 +170,10 @@ public final class ChatRecentActionsController: TelegramBaseController { self.navigationItem.titleView = self.titleView - let rightButton = ChatNavigationButton(action: .search(hasTags: false), buttonItem: UIBarButtonItem(image: PresentationResourcesRootController.navigationCompactSearchIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.activateSearch))) - self.navigationItem.setRightBarButton(rightButton.buttonItem, animated: false) + let rightBarButton = ChatNavigationButton(action: .search(hasTags: false), buttonItem: UIBarButtonItem(image: PresentationResourcesRootController.navigationCompactSearchIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.activateSearch))) + self.rightBarButton = rightBarButton - self.titleView.title = self.presentationData.strings.Channel_AdminLog_TitleAllEvents - self.titleView.pressed = { [weak self] in - self?.openFilterSetup() - } + self.titleView.title = CounterControllerTitle(title: EnginePeer(peer).compactDisplayTitle, counter: self.presentationData.strings.Channel_AdminLog_TitleAllEvents) let themeEmoticon = self.context.account.postbox.peerView(id: peer.id) |> map { view -> String? in @@ -238,7 +224,7 @@ public final class ChatRecentActionsController: TelegramBaseController { } private func updateThemeAndStrings() { - self.titleView.color = self.presentationData.theme.rootController.navigationBar.primaryTextColor + self.titleView.theme = self.presentationData.theme self.updateTitle() let rightButton = ChatNavigationButton(action: .search(hasTags: false), buttonItem: UIBarButtonItem(image: PresentationResourcesRootController.navigationCompactSearchIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.activateSearch))) @@ -251,14 +237,19 @@ public final class ChatRecentActionsController: TelegramBaseController { } override public func loadDisplayNode() { - self.displayNode = ChatRecentActionsControllerNode(context: self.context, controller: self, peer: self.peer, presentationData: self.presentationData, interaction: self.interaction, pushController: { [weak self] c in + self.displayNode = ChatRecentActionsControllerNode(context: self.context, controller: self, peer: self.peer, presentationData: self.presentationData, pushController: { [weak self] c in (self?.navigationController as? NavigationController)?.pushViewController(c) }, presentController: { [weak self] c, t, a in self?.present(c, in: t, with: a, blockInteraction: true) }, getNavigationController: { [weak self] in return self?.navigationController as? NavigationController }) - + self.controllerNode.isEmptyUpdated = { [weak self] isEmpty in + guard let self, let rightBarButton = self.rightBarButton else { + return + } + self.navigationItem.setRightBarButton(isEmpty ? nil : rightBarButton.buttonItem, animated: true) + } if let adminPeerId = self.initialAdminPeerId { self.controllerNode.updateFilter(events: .all, adminPeerIds: [adminPeerId]) self.updateTitle() @@ -300,7 +291,7 @@ public final class ChatRecentActionsController: TelegramBaseController { self.updateTitle() } - private func openFilterSetup() { + func openFilterSetup() { self.present(channelRecentActionsFilterController(context: self.context, updatedPresentationData: self.updatedPresentationData, peer: self.peer, events: self.controllerNode.filter.events, adminPeerIds: self.controllerNode.filter.adminPeerIds, apply: { [weak self] events, adminPeerIds in self?.controllerNode.updateFilter(events: events, adminPeerIds: adminPeerIds) self?.updateTitle() @@ -308,10 +299,13 @@ public final class ChatRecentActionsController: TelegramBaseController { } private func updateTitle() { + let title = EnginePeer(self.peer).compactDisplayTitle + let subtitle: String if self.controllerNode.filter.isEmpty { - self.titleView.title = self.presentationData.strings.Channel_AdminLog_TitleAllEvents + subtitle = self.presentationData.strings.Channel_AdminLog_TitleAllEvents } else { - self.titleView.title = self.presentationData.strings.Channel_AdminLog_TitleSelectedEvents + subtitle = self.presentationData.strings.Channel_AdminLog_TitleSelectedEvents } + self.titleView.title = CounterControllerTitle(title: title, counter: subtitle) } } diff --git a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift index 25f00a7482..1db3236edd 100644 --- a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift @@ -49,8 +49,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { private let pushController: (ViewController) -> Void private let presentController: (ViewController, PresentationContextType, Any?) -> Void private let getNavigationController: () -> NavigationController? + var isEmptyUpdated: (Bool) -> Void = { _ in } - private let interaction: ChatRecentActionsInteraction private var controllerInteraction: ChatControllerInteraction! private let galleryHiddenMesageAndMediaDisposable = MetaDisposable() @@ -68,6 +68,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { private let panelBackgroundNode: NavigationBackgroundNode private let panelSeparatorNode: ASDisplayNode private let panelButtonNode: HighlightableButtonNode + private let panelInfoButtonNode: HighlightableButtonNode fileprivate let listNode: ListView private let loadingNode: ChatLoadingNode @@ -99,12 +100,11 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { private weak var controller: ChatRecentActionsController? - init(context: AccountContext, controller: ChatRecentActionsController, peer: Peer, presentationData: PresentationData, interaction: ChatRecentActionsInteraction, pushController: @escaping (ViewController) -> Void, presentController: @escaping (ViewController, PresentationContextType, Any?) -> Void, getNavigationController: @escaping () -> NavigationController?) { + init(context: AccountContext, controller: ChatRecentActionsController, peer: Peer, presentationData: PresentationData, pushController: @escaping (ViewController) -> Void, presentController: @escaping (ViewController, PresentationContextType, Any?) -> Void, getNavigationController: @escaping () -> NavigationController?) { self.context = context self.controller = controller self.peer = peer self.presentationData = presentationData - self.interaction = interaction self.pushController = pushController self.presentController = presentController self.getNavigationController = getNavigationController @@ -118,7 +118,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { self.panelSeparatorNode = ASDisplayNode() self.panelSeparatorNode.backgroundColor = self.presentationData.theme.chat.inputPanel.panelSeparatorColor self.panelButtonNode = HighlightableButtonNode() - self.panelButtonNode.setTitle(self.presentationData.strings.Channel_AdminLog_InfoPanelTitle, with: Font.regular(17.0), with: self.presentationData.theme.chat.inputPanel.panelControlAccentColor, for: []) + self.panelButtonNode.setTitle(self.presentationData.strings.Channel_AdminLog_Settings, with: Font.regular(17.0), with: self.presentationData.theme.chat.inputPanel.panelControlAccentColor, for: []) + self.panelInfoButtonNode = HighlightableButtonNode() self.listNode = ListView() self.listNode.dynamicBounceEnabled = false @@ -145,8 +146,10 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { self.addSubnode(self.panelBackgroundNode) self.addSubnode(self.panelSeparatorNode) self.addSubnode(self.panelButtonNode) + self.addSubnode(self.panelInfoButtonNode) - self.panelButtonNode.addTarget(self, action: #selector(self.infoButtonPressed), forControlEvents: .touchUpInside) + self.panelButtonNode.addTarget(self, action: #selector(self.settingsButtonPressed), forControlEvents: .touchUpInside) + self.panelInfoButtonNode.addTarget(self, action: #selector(self.infoButtonPressed), forControlEvents: .touchUpInside) let (adminsDisposable, _) = self.context.peerChannelMemberCategoriesContextsManager.admins(engine: self.context.engine, postbox: self.context.account.postbox, network: self.context.account.network, accountPeerId: context.account.peerId, peerId: self.peer.id, searchQuery: nil, updated: { [weak self] state in self?.adminsState = state @@ -275,7 +278,10 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { }, activateMessagePinch: { _ in }, openMessageContextActions: { _, _, _, _ in }, navigateToMessage: { _, _, _ in }, navigateToMessageStandalone: { _ in - }, navigateToThreadMessage: { _, _, _ in + }, navigateToThreadMessage: { [weak self] peerId, threadId, _ in + if let context = self?.context, let navigationController = self?.getNavigationController() { + let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: threadId, messageId: nil, navigationController: navigationController, activateInput: nil, keepStack: .always).startStandalone() + } }, tapMessage: nil, clickThroughMessage: { }, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _, _, _, _, _, _ in return false }, sendEmoji: { _, _, _ in }, sendGif: { _, _, _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _, _, _ in return false }, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _ in }, activateSwitchInline: { _, _, _ in }, openUrl: { [weak self] url in self?.openUrl(url.url) }, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { [weak self] message, associatedData in @@ -674,7 +680,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { self.panelBackgroundNode.updateColor(color: presentationData.theme.chat.inputPanel.panelBackgroundColor, transition: .immediate) self.panelSeparatorNode.backgroundColor = presentationData.theme.chat.inputPanel.panelSeparatorColor - self.panelButtonNode.setTitle(presentationData.strings.Channel_AdminLog_InfoPanelTitle, with: Font.regular(17.0), with: presentationData.theme.chat.inputPanel.panelControlAccentColor, for: []) + self.panelButtonNode.setTitle(presentationData.strings.Channel_AdminLog_Settings, with: Font.regular(17.0), with: presentationData.theme.chat.inputPanel.panelControlAccentColor, for: []) + self.panelInfoButtonNode.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Recent Actions/Info"), color: presentationData.theme.chat.inputPanel.panelControlAccentColor), for: .normal) } func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { @@ -695,7 +702,11 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { transition.updateFrame(node: self.panelBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - panelHeight), size: CGSize(width: layout.size.width, height: panelHeight))) self.panelBackgroundNode.update(size: self.panelBackgroundNode.bounds.size, transition: transition) transition.updateFrame(node: self.panelSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - panelHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel))) - transition.updateFrame(node: self.panelButtonNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - panelHeight), size: CGSize(width: layout.size.width, height: intrinsicPanelHeight))) + + let infoButtonSize = CGSize(width: 56.0, height: intrinsicPanelHeight) + transition.updateFrame(node: self.panelButtonNode, frame: CGRect(origin: CGPoint(x: insets.left + infoButtonSize.width, y: layout.size.height - panelHeight), size: CGSize(width: layout.size.width - insets.left - insets.right - infoButtonSize.width * 2.0, height: intrinsicPanelHeight))) + + transition.updateFrame(node: self.panelInfoButtonNode, frame: CGRect(origin: CGPoint(x: layout.size.width - insets.right - infoButtonSize.width, y: layout.size.height - panelHeight), size: infoButtonSize)) self.visibleAreaInset = UIEdgeInsets(top: 0.0, left: 0.0, bottom: panelHeight, right: 0.0) @@ -788,6 +799,12 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { strongSelf.listNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) } strongSelf.isLoading = isLoading + + var isEmpty = false + if strongSelf.filter.isEmpty && (transition.isEmpty || isLoading) { + isEmpty = true + } + strongSelf.isEmptyUpdated(isEmpty) } }) } else { @@ -796,8 +813,22 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { } } + @objc func settingsButtonPressed() { + self.controller?.openFilterSetup() + } + @objc func infoButtonPressed() { - self.interaction.displayInfoAlert() + guard let controller = self.controller else { + return + } + let text: String + if let channel = self.peer as? TelegramChannel, case .broadcast = channel.info { + text = self.presentationData.strings.Channel_AdminLog_InfoPanelChannelAlertText + } else { + text = self.presentationData.strings.Channel_AdminLog_InfoPanelAlertText + } + controller.present(textAlertController(context: self.context, updatedPresentationData: controller.updatedPresentationData, title: self.presentationData.strings.Channel_AdminLog_InfoPanelAlertTitle, text: text, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + } func updateSearchQuery(_ query: String) { @@ -936,6 +967,40 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { } })) ) + actions.append( + .action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_ContextMenuBanFull, textColor: .destructive, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Ban"), color: theme.contextMenu.destructiveColor) }, action: { [weak self] _, f in + if let strongSelf = self { + f(.default) + strongSelf.banDisposables.set((strongSelf.context.engine.peers.fetchChannelParticipant(peerId: strongSelf.peer.id, participantId: author.id) + |> deliverOnMainQueue).startStrict(next: { participant in + if let strongSelf = self { + let initialUserBannedRights = participant?.banInfo?.rights + strongSelf.banDisposables.set(strongSelf.context.engine.peers.removePeerMember(peerId: strongSelf.peer.id, memberId: author.id).startStandalone(), forKey: author.id) + + strongSelf.presentController(UndoOverlayController( + presentationData: strongSelf.presentationData, + content: .actionSucceeded(title: nil, text: "**\(EnginePeer(author).compactDisplayTitle)** was banned.", cancel: strongSelf.presentationData.strings.Undo_Undo, destructive: false), + elevatedLayout: false, + action: { [weak self] action in + guard let self else { + return true + } + switch action { + case .commit: + break + case .undo: + let _ = self.context.engine.peers.updateChannelMemberBannedRights(peerId: self.peer.id, memberId: author.id, rights: initialUserBannedRights).startStandalone() + default: + break + } + return true + } + ), .current, nil) + } + }), forKey: author.id) + } + })) + ) } } diff --git a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsEmptyNode.swift b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsEmptyNode.swift index 0b2e4048a3..7f61a30adc 100644 --- a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsEmptyNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsEmptyNode.swift @@ -7,14 +7,15 @@ import TelegramPresentationData import WallpaperBackgroundNode import ChatPresentationInterfaceState -private let titleFont = Font.medium(16.0) -private let textFont = Font.regular(15.0) +private let titleFont = Font.semibold(15.0) +private let textFont = Font.regular(13.0) public final class ChatRecentActionsEmptyNode: ASDisplayNode { private var theme: PresentationTheme private var chatWallpaper: TelegramWallpaper private let backgroundNode: NavigationBackgroundNode + private let iconNode: ASImageNode private let titleNode: TextNode private let textNode: TextNode @@ -34,6 +35,9 @@ public final class ChatRecentActionsEmptyNode: ASDisplayNode { self.backgroundNode = NavigationBackgroundNode(color: .clear) + self.iconNode = ASImageNode() + self.iconNode.displaysAsynchronously = false + self.titleNode = TextNode() self.titleNode.isUserInteractionEnabled = false @@ -45,6 +49,7 @@ public final class ChatRecentActionsEmptyNode: ASDisplayNode { self.allowsGroupOpacity = true self.addSubnode(self.backgroundNode) + self.addSubnode(self.iconNode) self.addSubnode(self.titleNode) self.addSubnode(self.textNode) } @@ -63,14 +68,15 @@ public final class ChatRecentActionsEmptyNode: ASDisplayNode { self.wallpaperBackgroundNode = backgroundNode self.layoutParams = (size, presentationData) + let themeUpdated = self.theme !== presentationData.theme.theme self.theme = presentationData.theme.theme self.chatWallpaper = presentationData.theme.wallpaper self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), transition: .immediate) - let insets = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 10.0, right: 10.0) + let insets = UIEdgeInsets(top: 16.0, left: 16.0, bottom: 25.0, right: 16.0) - let maxTextWidth = size.width - insets.left - insets.right - 18.0 * 2.0 + let maxTextWidth = min(196.0, size.width - insets.left - insets.right - 18.0 * 2.0) let makeTitleLayout = TextNode.asyncLayout(self.titleNode) let makeTextLayout = TextNode.asyncLayout(self.textNode) @@ -78,17 +84,28 @@ public final class ChatRecentActionsEmptyNode: ASDisplayNode { let serviceColor = serviceMessageColorComponents(theme: self.theme, wallpaper: self.chatWallpaper) let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: self.title, font: titleFont, textColor: serviceColor.primaryText), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: maxTextWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .center, lineSpacing: 0.0, cutout: nil, insets: UIEdgeInsets())) - let spacing: CGFloat = titleLayout.size.height.isZero ? 0.0 : 5.0 + let spacing: CGFloat = titleLayout.size.height.isZero ? 0.0 : 7.0 let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: self.text, font: textFont, textColor: serviceColor.primaryText), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: maxTextWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .center, lineSpacing: 0.0, cutout: nil, insets: UIEdgeInsets())) - let contentSize = CGSize(width: max(titleLayout.size.width, textLayout.size.width) + insets.left + insets.right, height: insets.top + insets.bottom + titleLayout.size.height + spacing + textLayout.size.height) + if themeUpdated || self.iconNode.image == nil { + self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Recent Actions/Placeholder"), color: serviceColor.primaryText) + } + let iconSize = self.iconNode.image?.size ?? .zero + + let contentSize = CGSize(width: max(titleLayout.size.width, textLayout.size.width) + insets.left + insets.right, height: 5.0 + insets.bottom + iconSize.height - 2.0 + titleLayout.size.height + spacing + textLayout.size.height) let backgroundFrame = CGRect(origin: CGPoint(x: floor((size.width - contentSize.width) / 2.0), y: floor((size.height - contentSize.height) / 2.0)), size: contentSize) transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame) self.backgroundNode.update(size: self.backgroundNode.bounds.size, cornerRadius: min(14.0, self.backgroundNode.bounds.height / 2.0), transition: transition) - transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX + floor((contentSize.width - titleLayout.size.width) / 2.0), y: backgroundFrame.minY + insets.top), size: titleLayout.size)) - transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX + floor((contentSize.width - textLayout.size.width) / 2.0), y: backgroundFrame.minY + insets.top + titleLayout.size.height + spacing), size: textLayout.size)) + let iconFrame = CGRect(origin: CGPoint(x: backgroundFrame.minX + floor((contentSize.width - iconSize.width) / 2.0), y: backgroundFrame.minY + 5.0), size: iconSize) + transition.updateFrame(node: self.iconNode, frame: iconFrame) + let titleFrame = CGRect(origin: CGPoint(x: backgroundFrame.minX + floor((contentSize.width - titleLayout.size.width) / 2.0), y: iconFrame.maxY - 2.0), size: titleLayout.size) + transition.updateFrame(node: self.titleNode, frame: titleFrame) + + let textFrame = CGRect(origin: CGPoint(x: backgroundFrame.minX + floor((contentSize.width - textLayout.size.width) / 2.0), y: titleFrame.maxY + spacing), size: textLayout.size) + transition.updateFrame(node: self.textNode, frame: textFrame) + let _ = titleApply() let _ = textApply() diff --git a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsHistoryTransition.swift b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsHistoryTransition.swift index cfc70b0418..37a06dddc2 100644 --- a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsHistoryTransition.swift +++ b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsHistoryTransition.swift @@ -404,6 +404,9 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { if let attribute = attribute as? TextEntitiesMessageAttribute { attributes.append(attribute) } + if let attribute = attribute as? ReplyMessageAttribute { + attributes.append(attribute) + } } for attribute in attributes { for peerId in attribute.associatedPeerIds { @@ -412,7 +415,10 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { } } } - let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) + if let peer = self.entry.peers[message.id.peerId] { + peers[peer.id] = peer + } + let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: message.threadId, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: message.associatedThreadInfo, associatedStories: [:]) return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil)) } else { var peers = SimpleDictionary() @@ -488,6 +494,9 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { if let attribute = attribute as? TextEntitiesMessageAttribute { attributes.append(attribute) } + if let attribute = attribute as? ReplyMessageAttribute { + attributes.append(attribute) + } } for attribute in attributes { for peerId in attribute.associatedPeerIds { @@ -496,7 +505,10 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { } } } - let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) + if let peer = self.entry.peers[message.id.peerId] { + peers[peer.id] = peer + } + let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: message.threadId, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: message.associatedMessages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: message.associatedThreadInfo, associatedStories: [:]) return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: !prev.text.isEmpty || !message.text.isEmpty ? .eventLogPreviousMessage(filterOriginalMessageFlags(prev)) : nil) } case let .deleteMessage(message): @@ -531,6 +543,9 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { if let attribute = attribute as? TextEntitiesMessageAttribute { attributes.append(attribute) } + if let attribute = attribute as? ReplyMessageAttribute { + attributes.append(attribute) + } } for attribute in attributes { for peerId in attribute.associatedPeerIds { @@ -549,7 +564,10 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { if let peer = self.entry.peers[self.entry.event.peerId] { peers[peer.id] = peer } - let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: message.id.id), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) + if let peer = self.entry.peers[message.id.peerId] { + peers[peer.id] = peer + } + let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: message.id.id), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: message.threadId, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: message.associatedMessages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: message.associatedThreadInfo, associatedStories: [:]) return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil)) } case .participantJoin, .participantLeave: @@ -1110,6 +1128,9 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { if let attribute = attribute as? TextEntitiesMessageAttribute { attributes.append(attribute) } + if let attribute = attribute as? ReplyMessageAttribute { + attributes.append(attribute) + } } for attribute in attributes { for peerId in attribute.associatedPeerIds { @@ -1118,7 +1139,10 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { } } } - let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.author, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) + if let peer = self.entry.peers[message.id.peerId] { + peers[peer.id] = peer + } + let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.author, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: message.associatedMessages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: message.associatedThreadInfo, associatedStories: [:]) return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: nil) } case let .linkedPeerUpdated(previous, updated): @@ -1706,6 +1730,9 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { if let attribute = attribute as? TextEntitiesMessageAttribute { attributes.append(attribute) } + if let attribute = attribute as? ReplyMessageAttribute { + attributes.append(attribute) + } } for attribute in attributes { for peerId in attribute.associatedPeerIds { @@ -1714,7 +1741,10 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { } } } - let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) + if let peer = self.entry.peers[message.id.peerId] { + peers[peer.id] = peer + } + let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: message.threadId, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: message.associatedMessages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: message.associatedThreadInfo, associatedStories: [:]) return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil)) } case let .createTopic(info): diff --git a/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/BUILD b/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/BUILD index 882bfd1377..45b7b88b4e 100644 --- a/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/BUILD +++ b/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/BUILD @@ -28,7 +28,7 @@ swift_library( "//submodules/MergeLists", "//submodules/ShareController", "//submodules/GalleryUI", - "//submodules/CounterContollerTitleView", + "//submodules/CounterControllerTitleView", "//submodules/LegacyMediaPickerUI", "//submodules/TelegramUI/Components/Settings/SettingsThemeWallpaperNode", "//submodules/TelegramUI/Components/PremiumLockButtonSubtitleComponent", diff --git a/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/Sources/WallpaperGalleryController.swift b/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/Sources/WallpaperGalleryController.swift index c306b30e67..25faa1b007 100644 --- a/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/Sources/WallpaperGalleryController.swift +++ b/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/Sources/WallpaperGalleryController.swift @@ -14,7 +14,7 @@ import AccountContext import ShareController import GalleryUI import HexColor -import CounterContollerTitleView +import CounterControllerTitleView import UndoUI import LegacyComponents import LegacyMediaPickerUI @@ -350,8 +350,8 @@ public class WallpaperGalleryController: ViewController { self.centralItemAttributesDisposable.add(self.centralItemSubtitle.get().start(next: { [weak self] subtitle in if let strongSelf = self { if let subtitle = subtitle { - let titleView = CounterContollerTitleView(theme: strongSelf.presentationData.theme) - titleView.title = CounterContollerTitle(title: strongSelf.presentationData.strings.WallpaperPreview_Title, counter: subtitle) + let titleView = CounterControllerTitleView(theme: strongSelf.presentationData.theme) + titleView.title = CounterControllerTitle(title: strongSelf.presentationData.strings.WallpaperPreview_Title, counter: subtitle) strongSelf.navigationItem.titleView = titleView strongSelf.title = nil } else { diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Contents.json new file mode 100644 index 0000000000..6e965652df --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Contents.json @@ -0,0 +1,9 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "provides-namespace" : true + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Info.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Info.imageset/Contents.json new file mode 100644 index 0000000000..cb1f2a6fcb --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Info.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "question.circle.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Info.imageset/question.circle.pdf b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Info.imageset/question.circle.pdf new file mode 100644 index 0000000000..071d47854f --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Info.imageset/question.circle.pdf @@ -0,0 +1,99 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 4.334961 4.334999 cm +0.000000 0.000000 0.000000 scn +10.665000 20.000002 m +5.509422 20.000002 1.330000 15.820580 1.330000 10.665002 c +1.330000 5.509424 5.509422 1.330002 10.665000 1.330002 c +15.820578 1.330002 20.000000 5.509424 20.000000 10.665002 c +20.000000 15.820580 15.820578 20.000002 10.665000 20.000002 c +h +0.000000 10.665002 m +0.000000 16.555119 4.774883 21.330002 10.665000 21.330002 c +16.555117 21.330002 21.330002 16.555119 21.330002 10.665002 c +21.330002 4.774885 16.555117 0.000000 10.665000 0.000000 c +4.774883 0.000000 0.000000 4.774885 0.000000 10.665002 c +h +10.665000 15.138485 m +9.306379 15.138485 8.205000 14.037106 8.205000 12.678485 c +8.205000 12.311215 7.907269 12.013485 7.540000 12.013485 c +7.172730 12.013485 6.875000 12.311215 6.875000 12.678485 c +6.875000 14.771645 8.571840 16.468485 10.665000 16.468485 c +12.758160 16.468485 14.455000 14.771645 14.455000 12.678485 c +14.455000 11.036498 13.411167 9.640008 11.953011 9.113155 c +11.520578 8.956911 11.330000 8.669144 11.330000 8.470152 c +11.330000 7.990985 l +11.330000 7.623715 11.032269 7.325985 10.665000 7.325985 c +10.297730 7.325985 10.000000 7.623715 10.000000 7.990985 c +10.000000 8.470152 l +10.000000 9.467776 10.808081 10.113627 11.501059 10.364010 c +12.449083 10.706545 13.125000 11.614429 13.125000 12.678485 c +13.125000 14.037106 12.023621 15.138485 10.665000 15.138485 c +h +10.664997 4.006662 m +11.240294 4.006662 11.706664 4.473032 11.706664 5.048328 c +11.706664 5.623627 11.240294 6.089996 10.664997 6.089996 c +10.089701 6.089996 9.623331 5.623627 9.623331 5.048328 c +9.623331 4.473032 10.089701 4.006662 10.664997 4.006662 c +h +f* +n +Q + +endstream +endobj + +3 0 obj + 1692 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 30.000000 30.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001782 00000 n +0000001805 00000 n +0000001978 00000 n +0000002052 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2111 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Placeholder.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Placeholder.imageset/Contents.json new file mode 100644 index 0000000000..36e91193f0 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Placeholder.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "recentactions.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Placeholder.imageset/recentactions.pdf b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Placeholder.imageset/recentactions.pdf new file mode 100644 index 0000000000..d4a44d77bf --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Placeholder.imageset/recentactions.pdf @@ -0,0 +1,110 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 23.500000 18.363636 cm +0.000000 0.000000 0.000000 scn +36.636364 54.363636 m +35.330963 54.363636 34.306767 55.443432 33.939365 56.696064 c +32.932384 60.129303 29.758968 62.636364 26.000000 62.636364 c +22.241032 62.636364 19.067616 60.129303 18.060635 56.696064 c +17.693233 55.443432 16.669035 54.363636 15.363634 54.363636 c +7.090909 54.363636 l +3.174709 54.363636 0.000000 51.188931 0.000000 47.272728 c +0.000000 7.090908 l +0.000000 3.174709 3.174708 0.000000 7.090909 0.000000 c +44.909092 0.000000 l +48.825291 0.000000 52.000000 3.174709 52.000000 7.090908 c +52.000000 47.272728 l +52.000000 51.188927 48.825291 54.363636 44.909092 54.363636 c +36.636364 54.363636 l +h +29.545456 54.363636 m +29.545456 52.405537 27.958101 50.818184 26.000000 50.818184 c +24.041901 50.818184 22.454546 52.405537 22.454546 54.363636 c +22.454546 56.321739 24.041901 57.909092 26.000000 57.909092 c +27.958101 57.909092 29.545456 56.321739 29.545456 54.363636 c +h +14.181818 41.363636 m +12.876418 41.363636 11.818182 40.305401 11.818182 39.000000 c +11.818182 37.694599 12.876417 36.636364 14.181818 36.636364 c +37.818184 36.636364 l +39.123581 36.636364 40.181816 37.694599 40.181816 39.000000 c +40.181816 40.305401 39.123581 41.363636 37.818184 41.363636 c +14.181818 41.363636 l +h +14.181818 29.545456 m +12.876418 29.545456 11.818182 28.487217 11.818182 27.181820 c +11.818182 25.876419 12.876417 24.818180 14.181818 24.818180 c +37.818184 24.818180 l +39.123581 24.818180 40.181816 25.876419 40.181816 27.181820 c +40.181816 28.487217 39.123581 29.545456 37.818184 29.545456 c +14.181818 29.545456 l +h +11.818182 15.363636 m +11.818182 16.669041 12.876418 17.727276 14.181818 17.727276 c +28.363640 17.727276 l +29.669039 17.727276 30.727272 16.669041 30.727272 15.363636 c +30.727272 14.058239 29.669035 13.000004 28.363636 13.000004 c +14.181814 13.000004 l +12.876414 13.000004 11.818182 14.058239 11.818182 15.363636 c +h +f* +n +Q + +endstream +endobj + +3 0 obj + 1962 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 100.000000 100.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000002052 00000 n +0000002075 00000 n +0000002250 00000 n +0000002324 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2383 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Sources/ContactMultiselectionController.swift b/submodules/TelegramUI/Sources/ContactMultiselectionController.swift index 118bb3bc37..b4433818ba 100644 --- a/submodules/TelegramUI/Sources/ContactMultiselectionController.swift +++ b/submodules/TelegramUI/Sources/ContactMultiselectionController.swift @@ -12,7 +12,7 @@ import AccountContext import AlertUI import PresentationDataUtils import ContactListUI -import CounterContollerTitleView +import CounterControllerTitleView import EditableTokenListNode import PremiumUI import UndoUI @@ -35,7 +35,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection private let isPeerEnabled: ((EnginePeer) -> Bool)? private let attemptDisabledItemSelection: ((EnginePeer, ChatListDisabledPeerReason) -> Void)? - private let titleView: CounterContollerTitleView + private let titleView: CounterControllerTitleView private var contactsNode: ContactMultiselectionControllerNode { return self.displayNode as! ContactMultiselectionControllerNode @@ -100,7 +100,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection self.limit = params.limit self.presentationData = params.updatedPresentationData?.initial ?? params.context.sharedContext.currentPresentationData.with { $0 } - self.titleView = CounterContollerTitleView(theme: self.presentationData.theme) + self.titleView = CounterControllerTitleView(theme: self.presentationData.theme) super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData)) @@ -250,7 +250,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection case let .chats(chatsNode): count = chatsNode.currentState.selectedPeerIds.count } - self.titleView.title = CounterContollerTitle(title: self.presentationData.strings.Compose_NewGroupTitle, counter: "\(count)/\(maxCount)") + self.titleView.title = CounterControllerTitle(title: self.presentationData.strings.Compose_NewGroupTitle, counter: "\(count)/\(maxCount)") if self.rightNavigationButton == nil { let rightNavigationButton = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.rightNavigationButtonPressed)) self.rightNavigationButton = rightNavigationButton @@ -262,23 +262,23 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection if case let .contacts(contactsNode) = self.contactsNode.contentNode { count = contactsNode.selectionState?.selectedPeerIndices.count ?? 0 } - self.titleView.title = CounterContollerTitle(title: self.presentationData.strings.Premium_Gift_ContactSelection_Title, counter: "\(count)/\(maxCount)") + self.titleView.title = CounterControllerTitle(title: self.presentationData.strings.Premium_Gift_ContactSelection_Title, counter: "\(count)/\(maxCount)") case .requestedUsersSelection: let maxCount: Int32 = self.limit ?? 10 var count = 0 if case let .contacts(contactsNode) = self.contactsNode.contentNode { count = contactsNode.selectionState?.selectedPeerIndices.count ?? 0 } - self.titleView.title = CounterContollerTitle(title: self.presentationData.strings.RequestPeer_SelectUsers, counter: "\(count)/\(maxCount)") + self.titleView.title = CounterControllerTitle(title: self.presentationData.strings.RequestPeer_SelectUsers, counter: "\(count)/\(maxCount)") case .channelCreation: - self.titleView.title = CounterContollerTitle(title: self.presentationData.strings.GroupInfo_AddParticipantTitle, counter: "") + self.titleView.title = CounterControllerTitle(title: self.presentationData.strings.GroupInfo_AddParticipantTitle, counter: "") if self.rightNavigationButton == nil { let rightNavigationButton = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.rightNavigationButtonPressed)) self.rightNavigationButton = rightNavigationButton self.navigationItem.rightBarButtonItem = self.rightNavigationButton } case .peerSelection: - self.titleView.title = CounterContollerTitle(title: self.presentationData.strings.PrivacyLastSeenSettings_EmpryUsersPlaceholder, counter: "") + self.titleView.title = CounterControllerTitle(title: self.presentationData.strings.PrivacyLastSeenSettings_EmpryUsersPlaceholder, counter: "") if self.rightNavigationButton == nil { let rightNavigationButton = UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.rightNavigationButtonPressed)) self.rightNavigationButton = rightNavigationButton @@ -286,7 +286,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection self.navigationItem.rightBarButtonItem = self.rightNavigationButton } case let .chatSelection(chatSelection): - self.titleView.title = CounterContollerTitle(title: chatSelection.title, counter: "") + self.titleView.title = CounterControllerTitle(title: chatSelection.title, counter: "") if self.rightNavigationButton == nil { let rightNavigationButton = UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.rightNavigationButtonPressed)) self.rightNavigationButton = rightNavigationButton @@ -540,13 +540,13 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection switch strongSelf.mode { case .groupCreation: let maxCount: Int32 = strongSelf.limitsConfiguration?.maxSupergroupMemberCount ?? 5000 - strongSelf.titleView.title = CounterContollerTitle(title: strongSelf.presentationData.strings.Compose_NewGroupTitle, counter: "\(updatedCount)/\(maxCount)") + strongSelf.titleView.title = CounterControllerTitle(title: strongSelf.presentationData.strings.Compose_NewGroupTitle, counter: "\(updatedCount)/\(maxCount)") case .premiumGifting: let maxCount: Int32 = strongSelf.limit ?? 10 - strongSelf.titleView.title = CounterContollerTitle(title: strongSelf.presentationData.strings.Premium_Gift_ContactSelection_Title, counter: "\(updatedCount)/\(maxCount)") + strongSelf.titleView.title = CounterControllerTitle(title: strongSelf.presentationData.strings.Premium_Gift_ContactSelection_Title, counter: "\(updatedCount)/\(maxCount)") case .requestedUsersSelection: let maxCount: Int32 = strongSelf.limit ?? 10 - strongSelf.titleView.title = CounterContollerTitle(title: strongSelf.presentationData.strings.RequestPeer_SelectUsers, counter: "\(updatedCount)/\(maxCount)") + strongSelf.titleView.title = CounterControllerTitle(title: strongSelf.presentationData.strings.RequestPeer_SelectUsers, counter: "\(updatedCount)/\(maxCount)") case .peerSelection, .channelCreation, .chatSelection: break } diff --git a/submodules/WebUI/BUILD b/submodules/WebUI/BUILD index 9fdbf7604b..ae4a135088 100644 --- a/submodules/WebUI/BUILD +++ b/submodules/WebUI/BUILD @@ -18,7 +18,7 @@ swift_library( "//submodules/PresentationDataUtils:PresentationDataUtils", "//submodules/AccountContext:AccountContext", "//submodules/AttachmentUI:AttachmentUI", - "//submodules/CounterContollerTitleView:CounterContollerTitleView", + "//submodules/CounterControllerTitleView:CounterControllerTitleView", "//submodules/HexColor:HexColor", "//submodules/PhotoResources:PhotoResources", "//submodules/ShimmerEffect:ShimmerEffect", diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index 24b963a7ba..a100d6a1e6 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -9,7 +9,7 @@ import SwiftSignalKit import TelegramPresentationData import AccountContext import AttachmentUI -import CounterContollerTitleView +import CounterControllerTitleView import ContextUI import PresentationDataUtils import HexColor @@ -1703,7 +1703,7 @@ public final class WebAppController: ViewController, AttachmentContainable { return self.displayNode as! Node } - private var titleView: CounterContollerTitleView? + private var titleView: CounterControllerTitleView? fileprivate let cancelButtonNode: WebAppCancelButtonNode fileprivate let moreButtonNode: MoreButtonNode @@ -1774,8 +1774,8 @@ public final class WebAppController: ViewController, AttachmentContainable { self.navigationItem.rightBarButtonItem?.action = #selector(self.moreButtonPressed) self.navigationItem.rightBarButtonItem?.target = self - let titleView = CounterContollerTitleView(theme: self.presentationData.theme) - titleView.title = CounterContollerTitle(title: params.botName, counter: self.presentationData.strings.Bot_GenericBotStatus) + let titleView = CounterControllerTitleView(theme: self.presentationData.theme) + titleView.title = CounterControllerTitle(title: params.botName, counter: self.presentationData.strings.Bot_GenericBotStatus) self.navigationItem.titleView = titleView self.titleView = titleView From 8876026edb3cbfa32420fa34749b0094eeb7f2af Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 17 Apr 2024 21:19:06 +0400 Subject: [PATCH 07/11] Add option to disable future login tokens --- .../AuthorizationSequenceController.swift | 4 +++- .../Sources/DebugController.swift | 24 ++++++++++++++----- .../TelegramCore/Sources/Authorization.swift | 17 ++++++------- .../Sources/ExperimentalUISettings.swift | 10 ++++++-- 4 files changed, 38 insertions(+), 17 deletions(-) diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift index 7f472c2bc5..52e028b8ae 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift @@ -192,13 +192,15 @@ public final class AuthorizationSequenceController: NavigationController, ASAuth return } controller?.inProgress = true + + let disableAuthTokens = self.sharedContext.immediateExperimentalUISettings.disableReloginTokens let authorizationPushConfiguration = self.sharedContext.authorizationPushConfiguration |> take(1) |> timeout(2.0, queue: .mainQueue(), alternate: .single(nil)) let _ = (authorizationPushConfiguration |> deliverOnMainQueue).startStandalone(next: { [weak self] authorizationPushConfiguration in if let strongSelf = self { - strongSelf.actionDisposable.set((sendAuthorizationCode(accountManager: strongSelf.sharedContext.accountManager, account: strongSelf.account, phoneNumber: number, apiId: strongSelf.apiId, apiHash: strongSelf.apiHash, pushNotificationConfiguration: authorizationPushConfiguration, firebaseSecretStream: strongSelf.sharedContext.firebaseSecretStream, syncContacts: syncContacts, forcedPasswordSetupNotice: { value in + strongSelf.actionDisposable.set((sendAuthorizationCode(accountManager: strongSelf.sharedContext.accountManager, account: strongSelf.account, phoneNumber: number, apiId: strongSelf.apiId, apiHash: strongSelf.apiHash, pushNotificationConfiguration: authorizationPushConfiguration, firebaseSecretStream: strongSelf.sharedContext.firebaseSecretStream, syncContacts: syncContacts, disableAuthTokens: disableAuthTokens, forcedPasswordSetupNotice: { value in guard let entry = CodableEntry(ApplicationSpecificCounterNotice(value: value)) else { return nil } diff --git a/submodules/DebugSettingsUI/Sources/DebugController.swift b/submodules/DebugSettingsUI/Sources/DebugController.swift index 591793299e..b900586afb 100644 --- a/submodules/DebugSettingsUI/Sources/DebugController.swift +++ b/submodules/DebugSettingsUI/Sources/DebugController.swift @@ -101,6 +101,7 @@ private enum DebugControllerEntry: ItemListNodeEntry { case storiesJpegExperiment(Bool) case playlistPlayback(Bool) case enableQuickReactionSwitch(Bool) + case disableReloginTokens(Bool) case voiceConference case preferredVideoCodec(Int, String, String?, Bool) case disableVideoAspectScaling(Bool) @@ -126,7 +127,7 @@ private enum DebugControllerEntry: ItemListNodeEntry { return DebugControllerSection.web.rawValue case .keepChatNavigationStack, .skipReadHistory, .dustEffect, .crashOnSlowQueries, .crashOnMemoryPressure: return DebugControllerSection.experiments.rawValue - case .clearTips, .resetNotifications, .crash, .fillLocalSavedMessageCache, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .resetTagHoles, .reindexUnread, .resetCacheIndex, .reindexCache, .resetBiometricsData, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .storiesExperiment, .storiesJpegExperiment, .playlistPlayback, .enableQuickReactionSwitch, .voiceConference, .experimentalCompatibility, .enableDebugDataDisplay, .acceleratedStickers, .browserExperiment, .localTranscription, .enableReactionOverrides, .restorePurchases: + case .clearTips, .resetNotifications, .crash, .fillLocalSavedMessageCache, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .resetTagHoles, .reindexUnread, .resetCacheIndex, .reindexCache, .resetBiometricsData, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .storiesExperiment, .storiesJpegExperiment, .playlistPlayback, .enableQuickReactionSwitch, .voiceConference, .experimentalCompatibility, .enableDebugDataDisplay, .acceleratedStickers, .browserExperiment, .localTranscription, .enableReactionOverrides, .restorePurchases, .disableReloginTokens: return DebugControllerSection.experiments.rawValue case .logTranslationRecognition, .resetTranslationStates: return DebugControllerSection.translation.rawValue @@ -233,14 +234,16 @@ private enum DebugControllerEntry: ItemListNodeEntry { return 46 case .storiesJpegExperiment: return 47 - case .playlistPlayback: + case .disableReloginTokens: return 48 - case .enableQuickReactionSwitch: + case .playlistPlayback: return 49 - case .voiceConference: + case .enableQuickReactionSwitch: return 50 + case .voiceConference: + return 51 case let .preferredVideoCodec(index, _, _, _): - return 51 + index + return 52 + index case .disableVideoAspectScaling: return 100 case .enableNetworkFramework: @@ -1371,6 +1374,14 @@ private enum DebugControllerEntry: ItemListNodeEntry { } }) }) + case let .disableReloginTokens(value): + return ItemListSwitchItem(presentationData: presentationData, title: "Disable Relogin Tokens", value: value, sectionId: self.section, style: .blocks, updated: { value in + let _ = updateExperimentalUISettingsInteractively(accountManager: arguments.sharedContext.accountManager, { settings in + var settings = settings + settings.disableReloginTokens = value + return settings + }).start() + }) case let .hostInfo(_, string): return ItemListTextItem(presentationData: presentationData, text: .plain(string), sectionId: self.section) case .versionInfo: @@ -1449,10 +1460,11 @@ private func debugControllerEntries(sharedContext: SharedAccountContext, present entries.append(.logTranslationRecognition(experimentalSettings.logLanguageRecognition)) entries.append(.resetTranslationStates) - + if case .internal = sharedContext.applicationBindings.appBuildType { entries.append(.storiesExperiment(experimentalSettings.storiesExperiment)) entries.append(.storiesJpegExperiment(experimentalSettings.storiesJpegExperiment)) + entries.append(.disableReloginTokens(experimentalSettings.disableReloginTokens)) } entries.append(.playlistPlayback(experimentalSettings.playlistPlayback)) entries.append(.enableQuickReactionSwitch(!experimentalSettings.disableQuickReaction)) diff --git a/submodules/TelegramCore/Sources/Authorization.swift b/submodules/TelegramCore/Sources/Authorization.swift index e2cf3449f8..0a485b6517 100644 --- a/submodules/TelegramCore/Sources/Authorization.swift +++ b/submodules/TelegramCore/Sources/Authorization.swift @@ -142,7 +142,7 @@ private func sendFirebaseAuthorizationCode(accountManager: AccountManager, account: UnauthorizedAccount, phoneNumber: String, apiId: Int32, apiHash: String, pushNotificationConfiguration: AuthorizationCodePushNotificationConfiguration?, firebaseSecretStream: Signal<[String: String], NoError>, syncContacts: Bool, forcedPasswordSetupNotice: @escaping (Int32) -> (NoticeEntryKey, CodableEntry)?) -> Signal { +public func sendAuthorizationCode(accountManager: AccountManager, account: UnauthorizedAccount, phoneNumber: String, apiId: Int32, apiHash: String, pushNotificationConfiguration: AuthorizationCodePushNotificationConfiguration?, firebaseSecretStream: Signal<[String: String], NoError>, syncContacts: Bool, disableAuthTokens: Bool = false, forcedPasswordSetupNotice: @escaping (Int32) -> (NoticeEntryKey, CodableEntry)?) -> Signal { var cloudValue: [Data] = [] if let list = NSUbiquitousKeyValueStore.default.object(forKey: "T_SLTokens") as? [String] { cloudValue = list.compactMap { string -> Data? in @@ -152,9 +152,6 @@ public func sendAuthorizationCode(accountManager: AccountManager [Data] in return transaction.getStoredLoginTokens() } @@ -162,16 +159,20 @@ public func sendAuthorizationCode(accountManager: AccountManager mapToSignal { localAuthTokens -> Signal in var authTokens = localAuthTokens - #if DEBUG - authTokens.removeAll() - #endif - for data in cloudValue { if !authTokens.contains(data) { authTokens.insert(data, at: 0) } } + if disableAuthTokens { + authTokens.removeAll() + } + +#if DEBUG + authTokens.removeAll() +#endif + var flags: Int32 = 0 flags |= 1 << 5 //allowMissedCall flags |= 1 << 6 //tokens diff --git a/submodules/TelegramUIPreferences/Sources/ExperimentalUISettings.swift b/submodules/TelegramUIPreferences/Sources/ExperimentalUISettings.swift index feeb42b98f..644d2a270a 100644 --- a/submodules/TelegramUIPreferences/Sources/ExperimentalUISettings.swift +++ b/submodules/TelegramUIPreferences/Sources/ExperimentalUISettings.swift @@ -56,6 +56,7 @@ public struct ExperimentalUISettings: Codable, Equatable { public var dustEffect: Bool public var callV2: Bool public var allowWebViewInspection: Bool + public var disableReloginTokens: Bool public static var defaultSettings: ExperimentalUISettings { return ExperimentalUISettings( @@ -89,7 +90,8 @@ public struct ExperimentalUISettings: Codable, Equatable { crashOnMemoryPressure: false, dustEffect: false, callV2: false, - allowWebViewInspection: false + allowWebViewInspection: false, + disableReloginTokens: false ) } @@ -124,7 +126,8 @@ public struct ExperimentalUISettings: Codable, Equatable { crashOnMemoryPressure: Bool, dustEffect: Bool, callV2: Bool, - allowWebViewInspection: Bool + allowWebViewInspection: Bool, + disableReloginTokens: Bool ) { self.keepChatNavigationStack = keepChatNavigationStack self.skipReadHistory = skipReadHistory @@ -157,6 +160,7 @@ public struct ExperimentalUISettings: Codable, Equatable { self.dustEffect = dustEffect self.callV2 = callV2 self.allowWebViewInspection = allowWebViewInspection + self.disableReloginTokens = disableReloginTokens } public init(from decoder: Decoder) throws { @@ -193,6 +197,7 @@ public struct ExperimentalUISettings: Codable, Equatable { self.dustEffect = try container.decodeIfPresent(Bool.self, forKey: "dustEffect") ?? false self.callV2 = try container.decodeIfPresent(Bool.self, forKey: "callV2") ?? false self.allowWebViewInspection = try container.decodeIfPresent(Bool.self, forKey: "allowWebViewInspection") ?? false + self.disableReloginTokens = try container.decodeIfPresent(Bool.self, forKey: "disableReloginTokens") ?? false } public func encode(to encoder: Encoder) throws { @@ -229,6 +234,7 @@ public struct ExperimentalUISettings: Codable, Equatable { try container.encode(self.dustEffect, forKey: "dustEffect") try container.encode(self.callV2, forKey: "callV2") try container.encode(self.allowWebViewInspection, forKey: "allowWebViewInspection") + try container.encode(self.disableReloginTokens, forKey: "disableReloginTokens") } } From 1870ebd097c9e3789e345bf3f45d03739b43fa04 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 17 Apr 2024 21:20:51 +0400 Subject: [PATCH 08/11] Don't try to translate ads --- submodules/TelegramUI/Sources/ChatHistoryListNode.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index 1cfaed2e0e..a40f2bb03d 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -2453,6 +2453,9 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto for i in (wideIndexRange.0 ... wideIndexRange.1) { switch historyView.filteredEntries[i] { case let .MessageEntry(message, _, _, _, _, _): + guard message.adAttribute == nil && message.id.namespace == Namespaces.Message.Cloud else { + continue + } if !message.text.isEmpty && message.author?.id != self.context.account.peerId { if let translation = message.attributes.first(where: { $0 is TranslationMessageAttribute }) as? TranslationMessageAttribute, translation.toLang == translateToLanguage { } else { @@ -2461,6 +2464,9 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto } case let .MessageGroupEntry(_, messages, _): for (message, _, _, _, _) in messages { + guard message.adAttribute && message.id.namespace == Namespaces.Message.Cloud == nil else { + continue + } if !message.text.isEmpty && message.author?.id != self.context.account.peerId { if let translation = message.attributes.first(where: { $0 is TranslationMessageAttribute }) as? TranslationMessageAttribute, translation.toLang == translateToLanguage { } else { From c26fe84f6c44aae04c0e70351ea39a5b90f6600c Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 17 Apr 2024 22:08:12 +0400 Subject: [PATCH 09/11] Fix typo --- submodules/TelegramUI/Sources/ChatHistoryListNode.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index a40f2bb03d..66cac8ff0e 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -2464,7 +2464,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto } case let .MessageGroupEntry(_, messages, _): for (message, _, _, _, _) in messages { - guard message.adAttribute && message.id.namespace == Namespaces.Message.Cloud == nil else { + guard message.adAttribute == nil && message.id.namespace == Namespaces.Message.Cloud else { continue } if !message.text.isEmpty && message.author?.id != self.context.account.peerId { From e87e918e6e3c37f0464cd8224c52c28410b38f04 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 17 Apr 2024 22:22:57 +0400 Subject: [PATCH 10/11] Authorization improvements --- .../AuthorizationSequenceCodeEntryControllerNode.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryControllerNode.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryControllerNode.swift index d56702e7e6..e2abc23356 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryControllerNode.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryControllerNode.swift @@ -359,12 +359,14 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF if let text = UIPasteboard.general.string, !text.isEmpty { if checkValidity(text: text) { self.textField.textField.text = text + self.updatePasteVisibility() } } } func updatePasteVisibility() { - self.pasteButton.isHidden = !UIPasteboard.general.hasStrings + let text = self.textField.textField.text ?? "" + self.pasteButton.isHidden = !text.isEmpty || !UIPasteboard.general.hasStrings } func updateCode(_ code: String) { @@ -932,6 +934,8 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF let text = self.textField.textField.text ?? "" self.proceedNode.isEnabled = !text.isEmpty self.updateNextEnabled?(!text.isEmpty) + + self.updatePasteVisibility() } private func codeChanged(text: String) { @@ -961,7 +965,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF } } } - + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { if self.inProgress { return false From eee28fae4c2cfeef500a0512f1dec9b92a126890 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 17 Apr 2024 23:03:11 +0400 Subject: [PATCH 11/11] Fix keyboard blinking during authorization screen transitions --- ...horizationSequenceCodeEntryController.swift | 18 ++++++++++++------ ...zationSequencePasswordEntryController.swift | 6 +++++- ...AuthorizationSequenceSignUpController.swift | 6 +++++- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryController.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryController.swift index f125c86064..0909886408 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryController.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryController.swift @@ -154,9 +154,9 @@ public final class AuthorizationSequenceCodeEntryController: ViewController { super.viewDidAppear(animated) if let navigationController = self.navigationController as? NavigationController, let layout = self.validLayout { - addTemporaryKeyboardSnapshotView(navigationController: navigationController, parentView: self.view, layout: layout) + addTemporaryKeyboardSnapshotView(navigationController: navigationController, layout: layout) } - + self.controllerNode.activateInput() } @@ -215,6 +215,10 @@ public final class AuthorizationSequenceCodeEntryController: ViewController { if !hadLayout { self.updateNavigationItems() + + if let navigationController = self.navigationController as? NavigationController { + addTemporaryKeyboardSnapshotView(navigationController: navigationController, layout: layout, local: true) + } } self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition) @@ -263,18 +267,20 @@ public final class AuthorizationSequenceCodeEntryController: ViewController { } } -func addTemporaryKeyboardSnapshotView(navigationController: NavigationController, parentView: UIView, layout: ContainerViewLayout) { +func addTemporaryKeyboardSnapshotView(navigationController: NavigationController, layout: ContainerViewLayout, local: Bool = false) { if case .compact = layout.metrics.widthClass, let statusBarHost = navigationController.statusBarHost { if let keyboardView = statusBarHost.keyboardView { + keyboardView.layer.removeAllAnimations() if let snapshotView = keyboardView.snapshotView(afterScreenUpdates: false) { - keyboardView.layer.removeAllAnimations() UIView.performWithoutAnimation { snapshotView.frame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - snapshotView.frame.size.height), size: snapshotView.frame.size) - if let keyboardWindow = statusBarHost.keyboardWindow { + if local { + navigationController.view.addSubview(snapshotView) + } else if let keyboardWindow = statusBarHost.keyboardWindow { keyboardWindow.addSubview(snapshotView) } - Queue.mainQueue().after(0.5, { + Queue.mainQueue().after(local ? 0.8 : 0.7, { snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in snapshotView?.removeFromSuperview() }) diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequencePasswordEntryController.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequencePasswordEntryController.swift index b4ba03969a..000a0a49db 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequencePasswordEntryController.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequencePasswordEntryController.swift @@ -90,7 +90,7 @@ final class AuthorizationSequencePasswordEntryController: ViewController { super.viewDidAppear(animated) if let navigationController = self.navigationController as? NavigationController, let layout = self.validLayout { - addTemporaryKeyboardSnapshotView(navigationController: navigationController, parentView: self.view, layout: layout) + addTemporaryKeyboardSnapshotView(navigationController: navigationController, layout: layout) } self.controllerNode.activateInput() @@ -134,6 +134,10 @@ final class AuthorizationSequencePasswordEntryController: ViewController { if !hadLayout { self.updateNavigationItems() + + if let navigationController = self.navigationController as? NavigationController { + addTemporaryKeyboardSnapshotView(navigationController: navigationController, layout: layout, local: true) + } } self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition) diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequenceSignUpController.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequenceSignUpController.swift index fda1ef9855..8c8fdd8df9 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequenceSignUpController.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequenceSignUpController.swift @@ -216,7 +216,7 @@ final class AuthorizationSequenceSignUpController: ViewController { super.viewDidAppear(animated) if let navigationController = self.navigationController as? NavigationController, let layout = self.validLayout { - addTemporaryKeyboardSnapshotView(navigationController: navigationController, parentView: self.view, layout: layout) + addTemporaryKeyboardSnapshotView(navigationController: navigationController, layout: layout) } self.controllerNode.activateInput() @@ -242,6 +242,10 @@ final class AuthorizationSequenceSignUpController: ViewController { if !hadLayout { self.updateNavigationItems() + + if let navigationController = self.navigationController as? NavigationController { + addTemporaryKeyboardSnapshotView(navigationController: navigationController, layout: layout, local: true) + } } self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)