diff --git a/submodules/AccountContext/Sources/ChatController.swift b/submodules/AccountContext/Sources/ChatController.swift index e9a9bc820a..1daefa389d 100644 --- a/submodules/AccountContext/Sources/ChatController.swift +++ b/submodules/AccountContext/Sources/ChatController.swift @@ -623,6 +623,9 @@ public protocol ChatController: ViewController { func hintPlayNextOutgoingGift() var isSendButtonVisible: Bool { get } + + var isSelectingMessagesUpdated: ((Bool) -> Void)? { get set } + func cancelSelectingMessages() } public protocol ChatMessagePreviewItemNode: AnyObject { diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 5323d57412..90f855857a 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -968,7 +968,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController strongSelf.setInlineChatList(location: .forum(peerId: channel.id)) } } else { - if let threadId = threadId { + if case let .channel(channel) = peer, channel.flags.contains(.isForum), let threadId { let _ = strongSelf.context.sharedContext.navigateToForumThread(context: strongSelf.context, peerId: peer.id, threadId: threadId, messageId: nil, navigationController: navigationController, activateInput: nil, keepStack: .never).start() strongSelf.chatListDisplayNode.clearHighlightAnimated(true) } else { @@ -1069,7 +1069,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController if case .chatList(.root) = strongSelf.location { navigationAnimationOptions = .removeOnMasterDetails } - if let threadId = threadId { + if case let .channel(channel) = actualPeer, channel.flags.contains(.isForum), let threadId { let _ = strongSelf.context.sharedContext.navigateToForumThread(context: strongSelf.context, peerId: peer.id, threadId: threadId, messageId: messageId, navigationController: navigationController, activateInput: nil, keepStack: .never).start() } else { strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(actualPeer), subject: .message(id: .id(messageId), highlight: true, timecode: nil), purposefulAction: { @@ -1102,7 +1102,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController if case .chatList(.root) = strongSelf.location { navigationAnimationOptions = .removeOnMasterDetails } - if let threadId = threadId { + if case let .channel(channel) = peer, channel.flags.contains(.isForum), let threadId { let _ = strongSelf.context.sharedContext.navigateToForumThread(context: strongSelf.context, peerId: peer.id, threadId: threadId, messageId: nil, navigationController: navigationController, activateInput: nil, keepStack: .never).start() } else { strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer), purposefulAction: { [weak self] in diff --git a/submodules/Display/Source/GridNode.swift b/submodules/Display/Source/GridNode.swift index eef5d88868..6235e8d5b1 100644 --- a/submodules/Display/Source/GridNode.swift +++ b/submodules/Display/Source/GridNode.swift @@ -492,7 +492,7 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate { let effectiveWidth = gridLayout.size.width - itemInsets.left - itemInsets.right - let itemsInRow = Int(effectiveWidth / defaultItemSize.width) + let itemsInRow = max(1, Int(effectiveWidth / defaultItemSize.width)) let itemsInRowWidth = CGFloat(itemsInRow) * defaultItemSize.width let remainingWidth = max(0.0, effectiveWidth - itemsInRowWidth) diff --git a/submodules/FeaturedStickersScreen/Sources/FeaturedStickersScreen.swift b/submodules/FeaturedStickersScreen/Sources/FeaturedStickersScreen.swift index c9c815ac9b..75fbb91720 100644 --- a/submodules/FeaturedStickersScreen/Sources/FeaturedStickersScreen.swift +++ b/submodules/FeaturedStickersScreen/Sources/FeaturedStickersScreen.swift @@ -713,6 +713,8 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode { itemSize.width -= 60.0 insets.left += 30.0 insets.right += 30.0 + } else { + itemSize.width -= layout.safeInsets.left + layout.safeInsets.right } self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: layout.size, insets: UIEdgeInsets(top: insets.top, left: insets.left + layout.safeInsets.left, bottom: insets.bottom + layout.safeInsets.bottom, right: insets.right + layout.safeInsets.right), preloadSize: 300.0, type: .fixed(itemSize: itemSize, fillWidth: nil, lineSpacing: 0.0, itemSpacing: nil)), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil), completion: { _ in }) diff --git a/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift b/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift index 7a558ee8f7..6a3f513e52 100644 --- a/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift +++ b/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift @@ -152,7 +152,7 @@ public final class HashtagSearchController: TelegramBaseController { } override public func loadDisplayNode() { - self.displayNode = HashtagSearchControllerNode(context: self.context, peer: self.peer, query: self.query, navigationBar: self.navigationBar, navigationController: self.navigationController as? NavigationController) + self.displayNode = HashtagSearchControllerNode(context: self.context, controller: self, peer: self.peer, query: self.query, navigationBar: self.navigationBar, navigationController: self.navigationController as? NavigationController) if let chatController = self.controllerNode.chatController { chatController.parentController = self } diff --git a/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift b/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift index 9fdd713186..289a388de6 100644 --- a/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift +++ b/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift @@ -9,6 +9,9 @@ import SegmentedControlNode import ChatListSearchItemHeader final class HashtagSearchControllerNode: ASDisplayNode { + private let context: AccountContext + private weak var controller: HashtagSearchController? + private let navigationBar: NavigationBar? private let segmentedControlNode: SegmentedControlNode @@ -16,15 +19,16 @@ final class HashtagSearchControllerNode: ASDisplayNode { let chatController: ChatController? - private let context: AccountContext + private let query: String private var containerLayout: (ContainerViewLayout, CGFloat)? private var enqueuedTransitions: [(ChatListSearchContainerTransition, Bool)] = [] private var hasValidLayout = false - init(context: AccountContext, peer: EnginePeer?, query: String, navigationBar: NavigationBar?, navigationController: NavigationController?) { + init(context: AccountContext, controller: HashtagSearchController, peer: EnginePeer?, query: String, navigationBar: NavigationBar?, navigationController: NavigationController?) { self.context = context + self.controller = controller self.query = query self.navigationBar = navigationBar @@ -74,6 +78,17 @@ final class HashtagSearchControllerNode: ASDisplayNode { } } } + + self.chatController?.isSelectingMessagesUpdated = { [weak self] isSelecting in + if let strongSelf = self { + let button: UIBarButtonItem? = isSelecting ? UIBarButtonItem(title: presentationData.strings.Common_Cancel, style: .done, target: self, action: #selector(strongSelf.cancelPressed)) : nil + strongSelf.controller?.navigationItem.setRightBarButton(button, animated: true) + } + } + } + + @objc private func cancelPressed() { + self.chatController?.cancelSelectingMessages() } func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) { diff --git a/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift b/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift index 48a7f4c05e..2c4b223f40 100644 --- a/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift @@ -1803,6 +1803,15 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta var footerItem: ItemListControllerFooterItem? + var isGroup = false + if let peer = peer as? TelegramChannel { + if case .group = peer.info { + isGroup = true + } + } else if let _ = peer as? TelegramGroup { + isGroup = true + } + var rightNavigationButton: ItemListNavigationButton? if case .revokeNames = mode { let count = Int32(publicChannelsToRevoke?.count ?? 0) @@ -1993,7 +2002,13 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta _ = (ApplicationSpecificNotice.getSetPublicChannelLink(accountManager: context.sharedContext.accountManager) |> deliverOnMainQueue).start(next: { showAlert in if showAlert { - presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Group_Edit_PrivatePublicLinkAlert, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: invokeAction)]), nil) + let text: String + if isGroup { + text = presentationData.strings.Group_Edit_PrivatePublicLinkAlert + } else { + text = presentationData.strings.Channel_Edit_PrivatePublicLinkAlert + } + presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: invokeAction)]), nil) } else { invokeAction() } @@ -2013,16 +2028,7 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta if state.revokingPeerId != nil { rightNavigationButton = ItemListNavigationButton(content: .none, style: .activity, enabled: true, action: {}) } - - var isGroup = false - if let peer = peer as? TelegramChannel { - if case .group = peer.info { - isGroup = true - } - } else if let _ = peer as? TelegramGroup { - isGroup = true - } - + let leftNavigationButton: ItemListNavigationButton? switch mode { case .initialSetup: diff --git a/submodules/SettingsUI/Sources/Data and Storage/AutodownloadMediaCategoryController.swift b/submodules/SettingsUI/Sources/Data and Storage/AutodownloadMediaCategoryController.swift index 7ed34ef52d..28194cede9 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/AutodownloadMediaCategoryController.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/AutodownloadMediaCategoryController.swift @@ -13,6 +13,9 @@ import AccountContext public func autodownloadDataSizeString(_ size: Int64, decimalSeparator: String = ".") -> String { if size >= 1024 * 1024 * 1024 { var remainder = (size % (1024 * 1024 * 1024)) / (1024 * 1024 * 102) + if remainder == 10 { + remainder = 9 + } while remainder != 0 && remainder % 10 == 0 { remainder /= 10 } @@ -24,6 +27,9 @@ public func autodownloadDataSizeString(_ size: Int64, decimalSeparator: String = } } else if size >= 1024 * 1024 { var remainder = (size % (1024 * 1024)) / (1024 * 102) + if remainder == 10 { + remainder = 9 + } while remainder != 0 && remainder % 10 == 0 { remainder /= 10 } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/CachedStickerPack.swift b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/CachedStickerPack.swift index d683c4dccc..f304be11ea 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/CachedStickerPack.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/CachedStickerPack.swift @@ -245,10 +245,11 @@ func cachedStickerPack(transaction: Transaction, reference: StickerPackReference } } case let .name(shortName): + let shortName = shortName.lowercased() for namespace in namespaces { for info in transaction.getItemCollectionsInfos(namespace: namespace) { if let info = info.1 as? StickerPackCollectionInfo { - if info.shortName == shortName { + if info.shortName.lowercased() == shortName { let items = transaction.getItemCollectionItems(collectionId: info.id) if !items.isEmpty { return (info, items.compactMap { $0 as? StickerPackItem }, true) diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index aa66cf395b..1b043dd979 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -513,6 +513,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G var updatedClosedPinnedMessageId: ((MessageId) -> Void)? var requestedUnpinAllMessages: ((Int, MessageId) -> Void)? + public var isSelectingMessagesUpdated: ((Bool) -> Void)? + private let scrolledToMessageId = ValuePromise(nil, ignoreRepeated: true) private var scrolledToMessageIdValue: ScrolledToMessageId? = nil { didSet { @@ -11455,6 +11457,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.recordingActivityPromise.set(recordingActivityValue) } + if (self.presentationInterfaceState.interfaceState.selectionState == nil) != (updatedChatPresentationInterfaceState.interfaceState.selectionState == nil) { + self.isSelectingMessagesUpdated?(updatedChatPresentationInterfaceState.interfaceState.selectionState != nil) + } + self.presentationInterfaceState = updatedChatPresentationInterfaceState self.updateSlowmodeStatus() @@ -11678,6 +11684,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G }), in: .current) } + public func cancelSelectingMessages() { + self.navigationButtonAction(.cancelMessageSelection) + } + private func navigationButtonAction(_ action: ChatNavigationButtonAction) { switch action { case .spacer, .toggleInfoPanel: diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index 78185c45a0..4fe5a44bf7 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -2654,7 +2654,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { context: self.context, currentInputData: inputMediaNodeData, updatedInputData: self.inputMediaNodeDataPromise.get(), - defaultToEmojiTab: !self.chatPresentationInterfaceState.interfaceState.effectiveInputState.inputText.string.isEmpty || self.openStickersBeginWithEmoji, + defaultToEmojiTab: !self.chatPresentationInterfaceState.interfaceState.effectiveInputState.inputText.string.isEmpty || self.chatPresentationInterfaceState.interfaceState.forwardMessageIds != nil || self.openStickersBeginWithEmoji, controllerInteraction: self.controllerInteraction, interfaceInteraction: self.interfaceInteraction, chatPeerId: peerId diff --git a/submodules/TelegramUI/Sources/ChatInterfaceInputContexts.swift b/submodules/TelegramUI/Sources/ChatInterfaceInputContexts.swift index c492f5ebf0..ed6ed431b2 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceInputContexts.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceInputContexts.swift @@ -354,47 +354,50 @@ func inputTextPanelStateForChatPresentationInterfaceState(_ chatPresentationInte let isTextEmpty = chatPresentationInterfaceState.interfaceState.composeInputState.inputText.length == 0 - if chatPresentationInterfaceState.interfaceState.forwardMessageIds == nil { - if isTextEmpty && chatPresentationInterfaceState.hasScheduledMessages { - accessoryItems.append(.scheduledMessages) + let hasForward = chatPresentationInterfaceState.interfaceState.forwardMessageIds != nil + + if isTextEmpty && chatPresentationInterfaceState.hasScheduledMessages && !hasForward { + accessoryItems.append(.scheduledMessages) + } + + var stickersEnabled = true + var stickersAreEmoji = !isTextEmpty + + if let peer = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel { + if isTextEmpty, case .broadcast = peer.info, canSendMessagesToPeer(peer) { + accessoryItems.append(.silentPost(chatPresentationInterfaceState.interfaceState.silentPosting)) } - - var stickersEnabled = true - - let stickersAreEmoji = !isTextEmpty - - if let peer = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel { - if isTextEmpty, case .broadcast = peer.info, canSendMessagesToPeer(peer) { - accessoryItems.append(.silentPost(chatPresentationInterfaceState.interfaceState.silentPosting)) - } - if peer.hasBannedPermission(.banSendStickers) != nil { - stickersEnabled = false - } - } else if let peer = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramGroup { - if peer.hasBannedPermission(.banSendStickers) { - stickersEnabled = false - } + if peer.hasBannedPermission(.banSendStickers) != nil { + stickersEnabled = false } - if isTextEmpty && chatPresentationInterfaceState.hasBots && chatPresentationInterfaceState.hasBotCommands { - accessoryItems.append(.commands) - } - - if !canSendTextMessages { - if stickersEnabled && !stickersAreEmoji { - accessoryItems.append(.input(isEnabled: true, inputMode: .stickers)) - } - } else { - if stickersEnabled { - accessoryItems.append(.input(isEnabled: true, inputMode: stickersAreEmoji ? .emoji : .stickers)) - } else { - accessoryItems.append(.input(isEnabled: true, inputMode: .emoji)) - } - } - - if isTextEmpty, let message = chatPresentationInterfaceState.keyboardButtonsMessage, let _ = message.visibleButtonKeyboardMarkup, chatPresentationInterfaceState.interfaceState.messageActionsState.dismissedButtonKeyboardMessageId != message.id { - accessoryItems.append(.botInput(isEnabled: true, inputMode: .bot)) + } else if let peer = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramGroup { + if peer.hasBannedPermission(.banSendStickers) { + stickersEnabled = false } } + + + if isTextEmpty && chatPresentationInterfaceState.hasBots && chatPresentationInterfaceState.hasBotCommands && !hasForward { + accessoryItems.append(.commands) + } + + if !canSendTextMessages { + if stickersEnabled && !stickersAreEmoji && !hasForward { + accessoryItems.append(.input(isEnabled: true, inputMode: .stickers)) + } + } else { + stickersAreEmoji = stickersAreEmoji || hasForward + if stickersEnabled { + accessoryItems.append(.input(isEnabled: true, inputMode: stickersAreEmoji ? .emoji : .stickers)) + } else { + accessoryItems.append(.input(isEnabled: true, inputMode: .emoji)) + } + } + + if isTextEmpty, let message = chatPresentationInterfaceState.keyboardButtonsMessage, let _ = message.visibleButtonKeyboardMarkup, chatPresentationInterfaceState.interfaceState.messageActionsState.dismissedButtonKeyboardMessageId != message.id { + accessoryItems.append(.botInput(isEnabled: true, inputMode: .bot)) + } + return ChatTextInputPanelState(accessoryItems: accessoryItems, contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState) } } diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index 7ff0b07f28..1de8c2e2d4 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -162,10 +162,12 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur } dismissInput() navigationController?.pushViewController(controller) - case let .gameStart(peerId, game): + case let .gameStart(botPeerId, game): let controller = context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: context, filter: [.onlyManageable, .excludeDisabled, .excludeRecent, .doNotSearchMessages], hasContactSelector: false, title: presentationData.strings.Bot_AddToChat_Title, selectForumThreads: true)) controller.peerSelected = { [weak controller] peer, _ in - let peerId = peer.id + let _ = peer.id + let _ = botPeerId + let _ = game let presentationData = context.sharedContext.currentPresentationData.with { $0 } let text: String if let peer = peer as? TelegramUser {