From 1e6c6d6091d1af971580f13963dd5f849b9c296e Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 21 Feb 2023 18:40:34 +0400 Subject: [PATCH] Various fixes --- .../Telegram-iOS/en.lproj/Localizable.strings | 2 + .../Sources/AccountContext.swift | 1 + .../Sources/ChatListSearchListPaneNode.swift | 4 +- .../Sources/Node/ChatListNode.swift | 4 + .../ContextUI/Sources/ContextController.swift | 7 +- submodules/Display/Source/Accessibility.swift | 4 + .../Sources/InviteLinkViewController.swift | 204 ++++++++++-------- .../LocalizedPeerData/Sources/PeerTitle.swift | 2 +- .../Sources/LegacyMediaPickerGallery.swift | 15 +- .../Sources/MediaPickerScreen.swift | 2 +- .../Sources/PasscodeEntryKeyboardNode.swift | 4 + .../Sources/ChannelAdminController.swift | 6 +- .../Sources/State/PendingMessageManager.swift | 2 +- .../DefaultDarkPresentationTheme.swift | 2 +- .../Sources/DefaultDayPresentationTheme.swift | 2 +- .../Sources/ServiceMessageStrings.swift | 38 +++- .../TelegramUI/Sources/ChatController.swift | 34 ++- ...atMessageInteractiveInstantVideoNode.swift | 53 +++-- .../ChatRecentActionsControllerNode.swift | 2 + .../Sources/ChatTextInputPanelNode.swift | 26 ++- .../TelegramUI/Sources/OpenResolvedUrl.swift | 20 ++ .../Sources/PeerInfo/PeerInfoScreen.swift | 2 +- .../UrlHandling/Sources/UrlHandling.swift | 5 +- 23 files changed, 290 insertions(+), 151 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 360145e7b5..3b86c42f45 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -8930,3 +8930,5 @@ Sorry for the inconvenience."; "VoiceOver.Chat.NotPlayedByRecipients" = "Not played by recipients"; "VoiceOver.Chat.ReplyingToMessage" = "In reply to message: %@"; + +"MediaPicker.VoiceOver.Camera" = "Camera"; diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index 08a1158228..cc0cfc3c2b 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -277,6 +277,7 @@ public enum ResolvedUrl { case inaccessiblePeer case botStart(peer: Peer, payload: String) case groupBotStart(peerId: PeerId, payload: String, adminRights: ResolvedBotAdminRights?) + case gameStart(peerId: PeerId, game: String) case channelMessage(peer: Peer, messageId: MessageId, timecode: Double?) case replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage, messageId: MessageId) case replyThread(messageId: MessageId) diff --git a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift index ebbb4515fe..8be0947f5d 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift @@ -2461,7 +2461,9 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { if let strongSelf = self { strongSelf.presentationData = presentationData strongSelf.presentationDataPromise.set(.single(ChatListPresentationData(theme: presentationData.theme, fontSize: presentationData.listsFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: true))) - + if strongSelf.backgroundColor != nil { + strongSelf.backgroundColor = presentationData.theme.chatList.backgroundColor + } strongSelf.listNode.forEachItemHeaderNode({ itemHeaderNode in if let itemHeaderNode = itemHeaderNode as? ChatListSearchItemHeaderNode { itemHeaderNode.updateTheme(theme: presentationData.theme) diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index 64c764c79a..0ecd93e6df 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -1648,6 +1648,10 @@ public final class ChatListNode: ListView { guard !filter.contains(.onlyPrivateChats) || peer.peerId.namespace == Namespaces.Peer.CloudUser else { return false } if let peer = peer.peer { + if peer.id.isReplies { + return false + } + switch peer { case let .user(user): if user.botInfo != nil { diff --git a/submodules/ContextUI/Sources/ContextController.swift b/submodules/ContextUI/Sources/ContextController.swift index 2edb6c4796..f7cf8c2329 100644 --- a/submodules/ContextUI/Sources/ContextController.swift +++ b/submodules/ContextUI/Sources/ContextController.swift @@ -994,15 +994,16 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi if let _ = self.presentationNode { self.currentPresentationStateTransition = .animateOut(result: initialResult, completion: completion) if let validLayout = self.validLayout { - if case .custom = initialResult { + if case let .custom(transition) = initialResult { self.delayLayoutUpdate = true - Queue.mainQueue().after(0.05) { + Queue.mainQueue().after(0.1) { self.delayLayoutUpdate = false self.updateLayout( layout: validLayout, - transition: .animated(duration: 0.35, curve: .easeInOut), + transition: transition, previousActionsContainerNode: nil ) + self.isAnimatingOut = true } } else { self.updateLayout( diff --git a/submodules/Display/Source/Accessibility.swift b/submodules/Display/Source/Accessibility.swift index 78382eb2ac..36be42c7ee 100644 --- a/submodules/Display/Source/Accessibility.swift +++ b/submodules/Display/Source/Accessibility.swift @@ -80,3 +80,7 @@ public func isBoldTextEnabled() -> Signal { } |> runOn(Queue.mainQueue()) } + +public func isReduceTransparencyEnabled() -> Bool { + UIAccessibility.isReduceTransparencyEnabled +} diff --git a/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift b/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift index 18d0e8b409..4bf2cbcbf4 100644 --- a/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift +++ b/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift @@ -544,122 +544,142 @@ public final class InviteLinkViewController: ViewController { return } - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - var items: [ContextMenuItem] = [] - - items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextCopy, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) - }, action: { [weak self] _, f in - f(.dismissWithoutContent) - - UIPasteboard.general.string = invite.link - - self?.controller?.dismissAllTooltips() - - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - self?.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root)) - }))) + var creatorIsBot: Signal + if case let .link(_, _, _, _, _, adminId, _, _, _, _, _, _) = invite { + creatorIsBot = context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: adminId)) + |> map { peer -> Bool in + if let peer, case let .user(user) = peer, user.botInfo != nil { + return true + } else { + return false + } + } + } else { + creatorIsBot = .single(false) + } - if invite.isRevoked { - items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextDelete, textColor: .destructive, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor) + let _ = (creatorIsBot + |> take(1) + |> deliverOnMainQueue).start(next: { creatorIsBot in + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + var items: [ContextMenuItem] = [] + + items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextCopy, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in f(.dismissWithoutContent) - let controller = ActionSheetController(presentationData: presentationData) - let dismissAction: () -> Void = { [weak controller] in - controller?.dismissAnimated() - } - controller.setItemGroups([ - ActionSheetItemGroup(items: [ - ActionSheetTextItem(title: presentationData.strings.InviteLink_DeleteLinkAlert_Text), - ActionSheetButtonItem(title: presentationData.strings.InviteLink_DeleteLinkAlert_Action, color: .destructive, action: { - dismissAction() - self?.controller?.dismiss() - - if let inviteLink = invite.link { - let _ = (context.engine.peers.deletePeerExportedInvitation(peerId: peerId, link: inviteLink) |> deliverOnMainQueue).start() - } - - self?.controller?.revokedInvitationsContext?.remove(invite) - }) - ]), - ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })]) - ]) - self?.controller?.present(controller, in: .window(.root)) + UIPasteboard.general.string = invite.link + + self?.controller?.dismissAllTooltips() + + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + self?.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root)) }))) - } else { - if !invitationAvailability(invite).isZero { - items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Settings/QrIcon"), color: theme.contextMenu.primaryColor) + + if invite.isRevoked { + items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextDelete, textColor: .destructive, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor) }, action: { [weak self] _, f in f(.dismissWithoutContent) - let _ = (context.account.postbox.loadedPeerWithId(peerId) - |> deliverOnMainQueue).start(next: { [weak self] peer in - guard let strongSelf = self, let parentController = strongSelf.controller else { - return - } - let isGroup: Bool - if let peer = peer as? TelegramChannel, case .broadcast = peer.info { - isGroup = false - } else { - isGroup = true - } - let updatedPresentationData = (strongSelf.presentationData, parentController.presentationDataPromise.get()) - strongSelf.controller?.present(QrCodeScreen(context: context, updatedPresentationData: updatedPresentationData, subject: .invite(invite: invite, isGroup: isGroup)), in: .window(.root)) - }) - }))) - } - items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextRevoke, textColor: .destructive, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor) - }, action: { [weak self] _, f in - f(.dismissWithoutContent) - - let _ = (context.account.postbox.loadedPeerWithId(peerId) - |> deliverOnMainQueue).start(next: { peer in - let isGroup: Bool - if let peer = peer as? TelegramChannel, case .broadcast = peer.info { - isGroup = false - } else { - isGroup = true - } let controller = ActionSheetController(presentationData: presentationData) let dismissAction: () -> Void = { [weak controller] in controller?.dismissAnimated() } controller.setItemGroups([ ActionSheetItemGroup(items: [ - ActionSheetTextItem(title: isGroup ? presentationData.strings.GroupInfo_InviteLink_RevokeAlert_Text : presentationData.strings.ChannelInfo_InviteLink_RevokeAlert_Text), - ActionSheetButtonItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeLink, color: .destructive, action: { + ActionSheetTextItem(title: presentationData.strings.InviteLink_DeleteLinkAlert_Text), + ActionSheetButtonItem(title: presentationData.strings.InviteLink_DeleteLinkAlert_Action, color: .destructive, action: { dismissAction() self?.controller?.dismiss() - + if let inviteLink = invite.link { - let _ = (context.engine.peers.revokePeerExportedInvitation(peerId: peerId, link: inviteLink) |> deliverOnMainQueue).start(next: { result in - if case let .replace(_, newInvite) = result { - self?.controller?.invitationsContext?.add(newInvite) - } - }) + let _ = (context.engine.peers.deletePeerExportedInvitation(peerId: peerId, link: inviteLink) |> deliverOnMainQueue).start() } - self?.controller?.invitationsContext?.remove(invite) - let revokedInvite = invite.withUpdated(isRevoked: true) - self?.controller?.revokedInvitationsContext?.add(revokedInvite) - - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - self?.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkRevoked(text: presentationData.strings.InviteLink_InviteLinkRevoked), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root)) + self?.controller?.revokedInvitationsContext?.remove(invite) }) ]), ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })]) ]) self?.controller?.present(controller, in: .window(.root)) - }) - }))) - } - - let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture) - self?.controller?.presentInGlobalOverlay(contextController) + }))) + } else { + if !invitationAvailability(invite).isZero { + items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Settings/QrIcon"), color: theme.contextMenu.primaryColor) + }, action: { [weak self] _, f in + f(.dismissWithoutContent) + + let _ = (context.account.postbox.loadedPeerWithId(peerId) + |> deliverOnMainQueue).start(next: { [weak self] peer in + guard let strongSelf = self, let parentController = strongSelf.controller else { + return + } + let isGroup: Bool + if let peer = peer as? TelegramChannel, case .broadcast = peer.info { + isGroup = false + } else { + isGroup = true + } + let updatedPresentationData = (strongSelf.presentationData, parentController.presentationDataPromise.get()) + strongSelf.controller?.present(QrCodeScreen(context: context, updatedPresentationData: updatedPresentationData, subject: .invite(invite: invite, isGroup: isGroup)), in: .window(.root)) + }) + }))) + } + if !creatorIsBot { + items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextRevoke, textColor: .destructive, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor) + }, action: { [weak self] _, f in + f(.dismissWithoutContent) + + let _ = (context.account.postbox.loadedPeerWithId(peerId) + |> deliverOnMainQueue).start(next: { peer in + let isGroup: Bool + if let peer = peer as? TelegramChannel, case .broadcast = peer.info { + isGroup = false + } else { + isGroup = true + } + let controller = ActionSheetController(presentationData: presentationData) + let dismissAction: () -> Void = { [weak controller] in + controller?.dismissAnimated() + } + controller.setItemGroups([ + ActionSheetItemGroup(items: [ + ActionSheetTextItem(title: isGroup ? presentationData.strings.GroupInfo_InviteLink_RevokeAlert_Text : presentationData.strings.ChannelInfo_InviteLink_RevokeAlert_Text), + ActionSheetButtonItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeLink, color: .destructive, action: { + dismissAction() + self?.controller?.dismiss() + + if let inviteLink = invite.link { + let _ = (context.engine.peers.revokePeerExportedInvitation(peerId: peerId, link: inviteLink) |> deliverOnMainQueue).start(next: { result in + if case let .replace(_, newInvite) = result { + self?.controller?.invitationsContext?.add(newInvite) + } + }) + } + + self?.controller?.invitationsContext?.remove(invite) + let revokedInvite = invite.withUpdated(isRevoked: true) + self?.controller?.revokedInvitationsContext?.add(revokedInvite) + + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + self?.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkRevoked(text: presentationData.strings.InviteLink_InviteLinkRevoked), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root)) + }) + ]), + ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })]) + ]) + self?.controller?.present(controller, in: .window(.root)) + }) + }))) + } + } + + let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture) + self?.controller?.presentInGlobalOverlay(contextController) + }) }) let previousEntries = Atomic<[InviteLinkViewEntry]?>(value: nil) diff --git a/submodules/LocalizedPeerData/Sources/PeerTitle.swift b/submodules/LocalizedPeerData/Sources/PeerTitle.swift index db16fdd65e..0986fe7de3 100644 --- a/submodules/LocalizedPeerData/Sources/PeerTitle.swift +++ b/submodules/LocalizedPeerData/Sources/PeerTitle.swift @@ -15,7 +15,7 @@ public extension EnginePeer { } else if let _ = user.phone { return "" //formatPhoneNumber("+\(phone)") } else { - return "" + return "Deleted Account" } case let .legacyGroup(group): return group.title diff --git a/submodules/MediaPickerUI/Sources/LegacyMediaPickerGallery.swift b/submodules/MediaPickerUI/Sources/LegacyMediaPickerGallery.swift index 82cfcc94ef..b135d60a43 100644 --- a/submodules/MediaPickerUI/Sources/LegacyMediaPickerGallery.swift +++ b/submodules/MediaPickerUI/Sources/LegacyMediaPickerGallery.swift @@ -238,28 +238,29 @@ func presentLegacyMediaPickerGallery(context: AccountContext, peer: EnginePeer?, } let legacySheetController = LegacyController(presentation: .custom, theme: presentationData.theme, initialLayout: nil) - let controller = TGMediaPickerSendActionSheetController(context: legacyController.context, isDark: true, sendButtonFrame: model.interfaceView.doneButtonFrame, canSendSilently: hasSilentPosting, canSchedule: effectiveHasSchedule, reminder: reminder, hasTimer: hasTimer) + let sheetController = TGMediaPickerSendActionSheetController(context: legacyController.context, isDark: true, sendButtonFrame: model.interfaceView.doneButtonFrame, canSendSilently: hasSilentPosting, canSchedule: effectiveHasSchedule, reminder: reminder, hasTimer: hasTimer) let dismissImpl = { [weak model] in model?.dismiss(true, false) + dismissAll() } - controller.send = { + sheetController.send = { completed(item.asset, false, nil, { dismissImpl() }) } - controller.sendSilently = { + sheetController.sendSilently = { completed(item.asset, true, nil, { dismissImpl() }) } - controller.schedule = { + sheetController.schedule = { presentSchedulePicker(true, { time in completed(item.asset, false, time, { dismissImpl() }) }) } - controller.sendWithTimer = { + sheetController.sendWithTimer = { presentTimerPicker { time in var items = selectionContext.selectedItems() ?? [] items.append(item.asset as Any) @@ -273,10 +274,10 @@ func presentLegacyMediaPickerGallery(context: AccountContext, peer: EnginePeer?, }) } } - controller.customDismissBlock = { [weak legacySheetController] in + sheetController.customDismissBlock = { [weak legacySheetController] in legacySheetController?.dismiss() } - legacySheetController.bind(controller: controller) + legacySheetController.bind(controller: sheetController) present(legacySheetController, nil) let hapticFeedback = HapticFeedback() diff --git a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift index 3c8960f0c3..8353f2df28 100644 --- a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift +++ b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift @@ -235,7 +235,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable { self.scrollingArea = SparseItemGridScrollingArea() self.cameraActivateAreaNode = AccessibilityAreaNode() - self.cameraActivateAreaNode.accessibilityLabel = "Camera" + self.cameraActivateAreaNode.accessibilityLabel = self.presentationData.strings.MediaPicker_VoiceOver_Camera self.cameraActivateAreaNode.accessibilityTraits = [.button] super.init() diff --git a/submodules/PasscodeUI/Sources/PasscodeEntryKeyboardNode.swift b/submodules/PasscodeUI/Sources/PasscodeEntryKeyboardNode.swift index 5ccd1b07d3..07aa30d4b0 100644 --- a/submodules/PasscodeUI/Sources/PasscodeEntryKeyboardNode.swift +++ b/submodules/PasscodeUI/Sources/PasscodeEntryKeyboardNode.swift @@ -119,6 +119,10 @@ final class PasscodeEntryButtonNode: HighlightTrackingButtonNode { let blurredBackgroundColor = (background.inverted ? UIColor(rgb: 0xffffff, alpha: 0.1) : UIColor(rgb: 0x000000, alpha: 0.2), dateFillNeedsBlur(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper)) let blurredBackgroundNode = NavigationBackgroundNode(color: blurredBackgroundColor.0, enableBlur: blurredBackgroundColor.1) self.blurredBackgroundNode = blurredBackgroundNode + + if isReduceTransparencyEnabled() { + blurredBackgroundNode.alpha = 0.1 + } } self.backgroundNode = ASImageNode() diff --git a/submodules/PeerInfoUI/Sources/ChannelAdminController.swift b/submodules/PeerInfoUI/Sources/ChannelAdminController.swift index 16f44376c2..f2107b9bc4 100644 --- a/submodules/PeerInfoUI/Sources/ChannelAdminController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelAdminController.swift @@ -1100,11 +1100,11 @@ public func channelAdminController(context: AccountContext, updatedPresentationD return } - if updateFlags != currentFlags { + if let updateFlags, updateFlags != currentFlags { updateState { current in return current.withUpdatedUpdating(true) } - updateRightsDisposable.set((context.peerChannelMemberCategoriesContextsManager.updateMemberAdminRights(engine: context.engine, peerId: peerId, memberId: adminId, adminRights: TelegramChatAdminRights(rights: updateFlags ?? []), rank: effectiveRank) |> deliverOnMainQueue).start(error: { error in + updateRightsDisposable.set((context.peerChannelMemberCategoriesContextsManager.updateMemberAdminRights(engine: context.engine, peerId: peerId, memberId: adminId, adminRights: TelegramChatAdminRights(rights: updateFlags), rank: effectiveRank) |> deliverOnMainQueue).start(error: { error in updateState { current in return current.withUpdatedUpdating(false) } @@ -1145,7 +1145,7 @@ public func channelAdminController(context: AccountContext, updatedPresentationD } presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) }, completed: { - updated(TelegramChatAdminRights(rights: updateFlags ?? [])) + updated(TelegramChatAdminRights(rights: updateFlags)) dismissImpl?() })) } else if let updateRank = updateRank, let currentFlags = currentFlags { diff --git a/submodules/TelegramCore/Sources/State/PendingMessageManager.swift b/submodules/TelegramCore/Sources/State/PendingMessageManager.swift index 94978e384b..f66ef7a482 100644 --- a/submodules/TelegramCore/Sources/State/PendingMessageManager.swift +++ b/submodules/TelegramCore/Sources/State/PendingMessageManager.swift @@ -400,7 +400,7 @@ public final class PendingMessageManager { return lhs.1.index < rhs.1.index }) { if case let .collectingInfo(message) = messageContext.state { - let contentToUpload = messageContentToUpload(network: strongSelf.network, postbox: strongSelf.postbox, auxiliaryMethods: strongSelf.auxiliaryMethods, transformOutgoingMessageMedia: strongSelf.transformOutgoingMessageMedia, messageMediaPreuploadManager: strongSelf.messageMediaPreuploadManager, revalidationContext: strongSelf.revalidationContext, forceReupload: messageContext.forcedReuploadOnce, isGrouped: message.groupingKey != nil, message: message) + let contentToUpload = messageContentToUpload(network: strongSelf.network, postbox: strongSelf.postbox, auxiliaryMethods: strongSelf.auxiliaryMethods, transformOutgoingMessageMedia: strongSelf.transformOutgoingMessageMedia, messageMediaPreuploadManager: strongSelf.messageMediaPreuploadManager, revalidationContext: strongSelf.revalidationContext, forceReupload: messageContext.forcedReuploadOnce, isGrouped: message.groupingKey != nil, message: message) messageContext.contentType = contentToUpload.type switch contentToUpload { case let .immediate(result, type): diff --git a/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift b/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift index bc24c91fa9..06ab683f5e 100644 --- a/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift +++ b/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift @@ -623,7 +623,7 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati let inputPanel = PresentationThemeChatInputPanel( panelBackgroundColor: rootNavigationBar.blurredBackgroundColor, - panelBackgroundColorNoWallpaper: UIColor(rgb: 0x000000, alpha: 0.94), + panelBackgroundColorNoWallpaper: UIColor(rgb: 0x000000), panelSeparatorColor: UIColor(rgb: 0x545458, alpha: 0.55), panelControlAccentColor: UIColor(rgb: 0xffffff), panelControlColor: UIColor(rgb: 0x808080), diff --git a/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift b/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift index f4bb19fa0e..fb41c05549 100644 --- a/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift +++ b/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift @@ -877,7 +877,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio let inputPanel = PresentationThemeChatInputPanel( panelBackgroundColor: rootNavigationBar.blurredBackgroundColor, - panelBackgroundColorNoWallpaper: rootNavigationBar.blurredBackgroundColor, + panelBackgroundColorNoWallpaper: UIColor(rgb: 0xffffff), panelSeparatorColor: UIColor(rgb: 0xb2b2b2), panelControlAccentColor: defaultDayAccentColor, panelControlColor: UIColor(rgb: 0x858e99), diff --git a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift index 7aa7e2ced1..fffb0ca1f3 100644 --- a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift +++ b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift @@ -51,6 +51,34 @@ public func plainServiceMessageString(strings: PresentationStrings, nameDisplayO } } +private func peerDisplayTitles(_ peerIds: [PeerId], _ dict: SimpleDictionary, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder) -> String { + var peers: [Peer] = [] + for id in peerIds { + if let peer = dict[id] { + peers.append(peer) + } + } + return peerDisplayTitles(peers, strings: strings, nameDisplayOrder: nameDisplayOrder) +} + +private func peerDisplayTitles(_ peers: [Peer], strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder) -> String { + if peers.count == 0 { + return "" + } else { + var string = "" + var first = true + for peer in peers { + if first { + first = false + } else { + string.append(", ") + } + string.append(EnginePeer(peer).displayTitle(strings: strings, displayOrder: nameDisplayOrder)) + } + return string + } +} + public func universalServiceMessageString(presentationData: (PresentationTheme, TelegramWallpaper)?, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: EngineMessage, accountPeerId: EnginePeer.Id, forChatList: Bool, forForumOverview: Bool) -> NSAttributedString? { var attributedString: NSAttributedString? @@ -96,9 +124,9 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, let resultTitleString: PresentationStrings.FormattedString if peerIds.count == 1 { attributePeerIds.append((1, peerIds.first)) - resultTitleString = strings.Notification_Invited(authorName, peerDebugDisplayTitles(peerIds, message.peers)) + resultTitleString = strings.Notification_Invited(authorName, peerDisplayTitles(peerIds, message.peers, strings: strings, nameDisplayOrder: nameDisplayOrder)) } else { - resultTitleString = strings.Notification_InvitedMultiple(authorName, peerDebugDisplayTitles(peerIds, message.peers)) + resultTitleString = strings.Notification_InvitedMultiple(authorName, peerDisplayTitles(peerIds, message.peers, strings: strings, nameDisplayOrder: nameDisplayOrder)) } attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: attributePeerIds)) @@ -115,7 +143,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, if peerIds.count == 1 { attributePeerIds.append((1, peerIds.first)) } - attributedString = addAttributesToStringWithRanges(strings.Notification_Kicked(authorName, peerDebugDisplayTitles(peerIds, message.peers))._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: attributePeerIds)) + attributedString = addAttributesToStringWithRanges(strings.Notification_Kicked(authorName, peerDisplayTitles(peerIds, message.peers, strings: strings, nameDisplayOrder: nameDisplayOrder))._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: attributePeerIds)) } case let .photoUpdated(image): if authorName.isEmpty || isChannel { @@ -652,10 +680,10 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, resultTitleString = strings.Notification_VoiceChatInvitationForYou(authorName) } else { attributePeerIds.append((1, peerIds.first)) - resultTitleString = strings.Notification_VoiceChatInvitation(authorName, peerDebugDisplayTitles(peerIds, message.peers)) + resultTitleString = strings.Notification_VoiceChatInvitation(authorName, peerDisplayTitles(peerIds, message.peers, strings: strings, nameDisplayOrder: nameDisplayOrder)) } } else { - resultTitleString = strings.Notification_VoiceChatInvitation(authorName, peerDebugDisplayTitles(peerIds, message.peers)) + resultTitleString = strings.Notification_VoiceChatInvitation(authorName, peerDisplayTitles(peerIds, message.peers, strings: strings, nameDisplayOrder: nameDisplayOrder)) } attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: attributePeerIds)) diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 5ac0cb0bb5..aa66cf395b 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -3061,6 +3061,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } strongSelf.commitPurposefulAction() + var isScheduledMessages = false + if case .scheduledMessages = strongSelf.presentationInterfaceState.subject { + isScheduledMessages = true + } + + guard !isScheduledMessages else { + strongSelf.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: nil, text: strongSelf.presentationData.strings.ScheduledMessages_BotActionUnavailable, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + return + } + let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Messages.Message(id: messageId)) |> deliverOnMainQueue).start(next: { message in guard let strongSelf = self, let message = message else { @@ -4226,7 +4236,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } } } - + let controller = richTextAlertController(context: context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationSend, action: { completion() @@ -4238,15 +4248,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G guard let strongSelf = self else { return } - var isChannel = false - if let channel = peer as? TelegramChannel, case .broadcast = channel.info { - isChannel = true - } - let peerName = EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder) - presentConfirmation(peerName, isChannel, { + if case .user = peerType { let _ = context.engine.peers.sendBotRequestedPeer(messageId: messageId, buttonId: buttonId, requestedPeerId: peer.id).start() - controller?.dismiss() - }) + } else { + var isChannel = false + if let channel = peer as? TelegramChannel, case .broadcast = channel.info { + isChannel = true + } + let peerName = EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder) + presentConfirmation(peerName, isChannel, { + let _ = context.engine.peers.sendBotRequestedPeer(messageId: messageId, buttonId: buttonId, requestedPeerId: peer.id).start() + controller?.dismiss() + }) + } } createNewGroupImpl = { [weak controller] in switch peerType { @@ -14591,7 +14605,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return } let replyMessageId = self.presentationInterfaceState.interfaceState.replyMessageId - if self.context.engine.messages.enqueueOutgoingMessageWithChatContextResult(to: peerId, threadId: self.chatLocation.threadId, botId: results.botId, result: result, replyToMessageId: replyMessageId, hideVia: hideVia, silentPosting: silentPosting) { + if self.context.engine.messages.enqueueOutgoingMessageWithChatContextResult(to: peerId, threadId: self.chatLocation.threadId, botId: results.botId, result: result, replyToMessageId: replyMessageId, hideVia: hideVia, silentPosting: silentPosting, scheduleTime: scheduleTime) { self.chatDisplayNode.setupSendActionOnViewUpdate({ [weak self] in if let strongSelf = self { strongSelf.chatDisplayNode.collapseInput() diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift index c0a447dbc7..7b6c2be1cf 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift @@ -238,7 +238,6 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { var viaBotApply: (TextNodeLayout, () -> TextNode)? var replyInfoApply: (CGSize, (Bool) -> ChatMessageReplyInfoNode)? - var updatedReplyBackgroundNode: NavigationBackgroundNode? var updatedInstantVideoBackgroundImage: UIImage? let instantVideoBackgroundImage: UIImage? @@ -556,17 +555,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { } let effectiveAudioTranscriptionState = updatedAudioTranscriptionState ?? audioTranscriptionState - - if replyInfoApply != nil || viaBotApply != nil || forwardInfoSizeApply != nil { - if let currentReplyBackgroundNode = currentReplyBackgroundNode { - updatedReplyBackgroundNode = currentReplyBackgroundNode - } else { - updatedReplyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper)) - } - - updatedReplyBackgroundNode?.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate) - } - + return (result, { [weak self] layoutData, animation in if let strongSelf = self { strongSelf.item = item @@ -575,6 +564,17 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { strongSelf.secretProgressIcon = secretProgressIcon strongSelf.automaticDownload = automaticDownload + var updatedReplyBackgroundNode: NavigationBackgroundNode? + if replyInfoApply != nil || viaBotApply != nil || forwardInfoSizeApply != nil { + if let currentReplyBackgroundNode = currentReplyBackgroundNode { + updatedReplyBackgroundNode = currentReplyBackgroundNode + } else { + updatedReplyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper)) + } + + updatedReplyBackgroundNode?.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate) + } + if let updatedAudioTranscriptionState = updatedAudioTranscriptionState { strongSelf.audioTranscriptionState = updatedAudioTranscriptionState strongSelf.updateTranscriptionExpanded?(strongSelf.audioTranscriptionState) @@ -928,7 +928,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { strongSelf.addSubnode(viaBotNode) } - let viaBotFrame = CGRect(origin: CGPoint(x: (!incoming ? 11.0 : (width - messageInfoSize.width - bubbleEdgeInset - 9.0 + 10.0)), y: 8.0), size: viaBotLayout.size) + let viaBotFrame = CGRect(origin: CGPoint(x: (!incoming ? (displayVideoFrame.maxX - width + 6.0) : (width - messageInfoSize.width - bubbleEdgeInset - 9.0 + 10.0)), y: 8.0), size: viaBotLayout.size) animation.animator.updateFrame(layer: viaBotNode.layer, frame: viaBotFrame, completion: nil) messageInfoSize = CGSize(width: messageInfoSize.width, height: viaBotLayout.size.height) @@ -1226,6 +1226,30 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation { switch gesture { case .tap: + if let viaBotNode = self.viaBotNode, viaBotNode.frame.contains(location) { + if let item = self.item { + for attribute in item.message.attributes { + if let attribute = attribute as? InlineBotMessageAttribute { + var botAddressName: String? + if let peerId = attribute.peerId, let botPeer = item.message.peers[peerId], let addressName = botPeer.addressName { + botAddressName = addressName + } else { + botAddressName = attribute.title + } + + if let botAddressName = botAddressName { + item.controllerInteraction.updateInputState { textInputState in + return ChatTextInputState(inputText: NSAttributedString(string: "@" + botAddressName + " ")) + } + item.controllerInteraction.updateInputMode { _ in + return .text + } + return + } + } + } + } + } if let replyInfoNode = self.replyInfoNode, replyInfoNode.frame.contains(location) { if let item = self.item { for attribute in item.message.attributes { @@ -1315,6 +1339,9 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { return playbackNode.view } } + if let viaBotNode = self.viaBotNode, viaBotNode.frame.contains(point), !viaBotNode.alpha.isZero { + return self.view + } if let forwardInfoNode = self.forwardInfoNode, forwardInfoNode.frame.contains(point), !forwardInfoNode.alpha.isZero { return self.view } diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift index 5208ce3c18..27172dcff2 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift @@ -975,6 +975,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { break case .groupBotStart: break + case .gameStart: + break case let .channelMessage(peer, messageId, timecode): if let navigationController = strongSelf.getNavigationController() { strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(EnginePeer(peer)), subject: .message(id: .id(messageId), highlight: true, timecode: timecode))) diff --git a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift index 63e5c64bdd..d484a85425 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift @@ -379,11 +379,11 @@ private func calculateTextFieldRealInsets(presentationInterfaceState: ChatPresen return UIEdgeInsets(top: 4.5 + top, left: 0.0, bottom: 5.5 + bottom, right: right) } -private var currentTextInputBackgroundImage: (UIColor, UIColor, CGFloat, UIImage)? -private func textInputBackgroundImage(backgroundColor: UIColor?, inputBackgroundColor: UIColor?, strokeColor: UIColor, diameter: CGFloat) -> UIImage? { +private var currentTextInputBackgroundImage: (UIColor, UIColor, CGFloat, CGFloat, UIImage)? +private func textInputBackgroundImage(backgroundColor: UIColor?, inputBackgroundColor: UIColor?, strokeColor: UIColor, diameter: CGFloat, strokeWidth: CGFloat) -> UIImage? { if let backgroundColor = backgroundColor, let current = currentTextInputBackgroundImage { - if current.0.isEqual(backgroundColor) && current.1.isEqual(strokeColor) && current.2.isEqual(to: diameter) { - return current.3 + if current.0.isEqual(backgroundColor) && current.1.isEqual(strokeColor) && current.2.isEqual(to: diameter) && current.3.isEqual(to: strokeWidth) { + return current.4 } } @@ -401,13 +401,12 @@ private func textInputBackgroundImage(backgroundColor: UIColor?, inputBackground context.setBlendMode(.normal) context.setStrokeColor(strokeColor.cgColor) - let strokeWidth: CGFloat = UIScreenPixel context.setLineWidth(strokeWidth) context.strokeEllipse(in: CGRect(x: strokeWidth / 2.0, y: strokeWidth / 2.0, width: diameter - strokeWidth, height: diameter - strokeWidth)) })?.stretchableImage(withLeftCapWidth: Int(diameter) / 2, topCapHeight: Int(diameter) / 2) if let image = image { if let backgroundColor = backgroundColor { - currentTextInputBackgroundImage = (backgroundColor, strokeColor, diameter, image) + currentTextInputBackgroundImage = (backgroundColor, strokeColor, diameter, strokeWidth, image) } return image } else { @@ -1290,7 +1289,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { if self.theme == nil || !self.theme!.chat.inputPanel.inputTextColor.isEqual(interfaceState.theme.chat.inputPanel.inputTextColor) { let textColor = interfaceState.theme.chat.inputPanel.inputTextColor - let tintColor = interfaceState.theme.list.itemAccentColor let baseFontSize = max(minInputFontSize, interfaceState.fontSize.baseDisplaySize) if let textInputNode = self.textInputNode { @@ -1302,12 +1300,17 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { textInputNode.selectedRange = range } textInputNode.typingAttributes = [NSAttributedString.Key.font.rawValue: Font.regular(baseFontSize), NSAttributedString.Key.foregroundColor.rawValue: textColor] - textInputNode.tintColor = tintColor self.updateSpoiler() } } + let tintColor = interfaceState.theme.list.itemAccentColor + if let textInputNode = self.textInputNode, tintColor != textInputNode.tintColor { + textInputNode.tintColor = tintColor + textInputNode.tintColorDidChange() + } + let keyboardAppearance = interfaceState.theme.rootController.keyboardColor.keyboardAppearance if let textInputNode = self.textInputNode, textInputNode.keyboardAppearance != keyboardAppearance, textInputNode.isFirstResponder() { if textInputNode.isCurrentlyEmoji() { @@ -1332,15 +1335,18 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { let textFieldMinHeight = calclulateTextFieldMinHeight(interfaceState, metrics: metrics) let minimalInputHeight: CGFloat = 2.0 + textFieldMinHeight + let strokeWidth: CGFloat let backgroundColor: UIColor if case let .color(color) = interfaceState.chatWallpaper, UIColor(rgb: color).isEqual(interfaceState.theme.chat.inputPanel.panelBackgroundColorNoWallpaper) { backgroundColor = interfaceState.theme.chat.inputPanel.panelBackgroundColorNoWallpaper + strokeWidth = 1.0 - UIScreenPixel } else { backgroundColor = interfaceState.theme.chat.inputPanel.panelBackgroundColor + strokeWidth = UIScreenPixel } - self.textInputBackgroundNode.image = textInputBackgroundImage(backgroundColor: backgroundColor, inputBackgroundColor: nil, strokeColor: interfaceState.theme.chat.inputPanel.inputStrokeColor, diameter: minimalInputHeight) - self.transparentTextInputBackgroundImage = textInputBackgroundImage(backgroundColor: nil, inputBackgroundColor: interfaceState.theme.chat.inputPanel.inputBackgroundColor, strokeColor: interfaceState.theme.chat.inputPanel.inputStrokeColor, diameter: minimalInputHeight) + self.textInputBackgroundNode.image = textInputBackgroundImage(backgroundColor: backgroundColor, inputBackgroundColor: nil, strokeColor: interfaceState.theme.chat.inputPanel.inputStrokeColor, diameter: minimalInputHeight, strokeWidth: strokeWidth) + self.transparentTextInputBackgroundImage = textInputBackgroundImage(backgroundColor: nil, inputBackgroundColor: interfaceState.theme.chat.inputPanel.inputBackgroundColor, strokeColor: interfaceState.theme.chat.inputPanel.inputStrokeColor, diameter: minimalInputHeight, strokeWidth: strokeWidth) self.textInputContainerBackgroundNode.image = generateStretchableFilledCircleImage(diameter: minimalInputHeight, color: interfaceState.theme.chat.inputPanel.inputBackgroundColor) self.searchLayoutClearImageNode.image = PresentationResourcesChat.chatInputTextFieldClearImage(interfaceState.theme) diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index 5901b7c7bd..7ff0b07f28 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -162,6 +162,26 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur } dismissInput() navigationController?.pushViewController(controller) + case let .gameStart(peerId, 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 presentationData = context.sharedContext.currentPresentationData.with { $0 } + let text: String + if let peer = peer as? TelegramUser { + text = presentationData.strings.Target_ShareGameConfirmationPrivate(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string + } else { + text = presentationData.strings.Target_ShareGameConfirmationGroup(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string + } + + let alertController = textAlertController(context: context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.RequestPeer_SelectionConfirmationSend, action: { + controller?.dismiss() + }), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: { + })]) + present(alertController, nil) + } + dismissInput() + navigationController?.pushViewController(controller) case let .channelMessage(peer, messageId, timecode): openPeer(EnginePeer(peer), .chat(textInputState: nil, subject: .message(id: .id(messageId), highlight: true, timecode: timecode), peekData: nil)) case let .replyThreadMessage(replyThreadMessage, messageId): diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 7e6aad351e..89220c7e6f 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -2495,7 +2495,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate if actions.options.contains(.deleteGlobally) { let globalTitle: String if isChannel { - globalTitle = strongSelf.presentationData.strings.Conversation_DeleteMessagesForMe + globalTitle = strongSelf.presentationData.strings.Conversation_DeleteMessagesForEveryone } else if let personalPeerName = personalPeerName { globalTitle = strongSelf.presentationData.strings.Conversation_DeleteMessagesFor(personalPeerName).string } else { diff --git a/submodules/UrlHandling/Sources/UrlHandling.swift b/submodules/UrlHandling/Sources/UrlHandling.swift index 4d9a7ef277..c0c6e1cfcf 100644 --- a/submodules/UrlHandling/Sources/UrlHandling.swift +++ b/submodules/UrlHandling/Sources/UrlHandling.swift @@ -67,6 +67,7 @@ public enum ParsedInternalPeerUrlParameter { case botStart(String) case groupBotStart(String, ResolvedBotAdminRights?) case attachBotStart(String, String?) + case gameStart(String) case channelMessage(Int32, Double?) case replyThread(Int32, Int32) case voiceChat(String?) @@ -212,7 +213,7 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? { } return .peer(.name(peerName), .groupBotStart(value, botAdminRights)) } else if queryItem.name == "game" { - return nil + return .peer(.name(peerName), .gameStart(value)) } else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) { return .peer(.name(peerName), .voiceChat(value)) } else if queryItem.name == "startattach" { @@ -582,6 +583,8 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl) return .single(.botStart(peer: peer, payload: payload)) case let .groupBotStart(payload, adminRights): return .single(.groupBotStart(peerId: peer.id, payload: payload, adminRights: adminRights)) + case let .gameStart(game): + return .single(.gameStart(peerId: peer.id, game: game)) case let .attachBotStart(name, payload): return context.engine.peers.resolvePeerByName(name: name) |> take(1)