mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various fixes and improvements
This commit is contained in:
parent
0ecc138ff6
commit
b14e81b767
@ -6151,3 +6151,5 @@ Sorry for the inconvenience.";
|
||||
"VoiceOver.ScrollStatus" = "Row %1$@ of %2$@";
|
||||
|
||||
"Conversation.UsersTooMuchError" = "Sorry, this group is full.";
|
||||
|
||||
"Conversation.UploadFileTooLarge" = "File could not be sent, because it is larger than 2 GB.\n\nYou can send as many files as you like, but each must be smaller than 2 GB.";
|
||||
|
@ -162,6 +162,7 @@ public enum ResolvedUrlSettingsSection {
|
||||
|
||||
public enum ResolvedUrl {
|
||||
case externalUrl(String)
|
||||
case urlAuth(String)
|
||||
case peer(PeerId?, ChatControllerInteractionNavigateToPeer)
|
||||
case inaccessiblePeer
|
||||
case botStart(peerId: PeerId, payload: String)
|
||||
@ -603,7 +604,7 @@ public protocol SharedAccountContext: class {
|
||||
func chatAvailableMessageActions(postbox: Postbox, accountPeerId: PeerId, messageIds: Set<MessageId>) -> Signal<ChatAvailableMessageActions, NoError>
|
||||
func chatAvailableMessageActions(postbox: Postbox, accountPeerId: PeerId, messageIds: Set<MessageId>, messages: [MessageId: Message], peers: [PeerId: Peer]) -> Signal<ChatAvailableMessageActions, NoError>
|
||||
func resolveUrl(account: Account, url: String) -> Signal<ResolvedUrl, NoError>
|
||||
func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, openPeer: @escaping (PeerId, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?)
|
||||
func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, openPeer: @escaping (PeerId, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?)
|
||||
func openAddContact(context: AccountContext, firstName: String, lastName: String, phoneNumber: String, label: String, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, completed: @escaping () -> Void)
|
||||
func openAddPersonContact(context: AccountContext, peerId: PeerId, pushController: @escaping (ViewController) -> Void, present: @escaping (ViewController, Any?) -> Void)
|
||||
func presentContactsWarningSuppression(context: AccountContext, present: (ViewController, Any?) -> Void)
|
||||
|
@ -527,6 +527,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
}
|
||||
|
||||
self.titleView.theme = self.presentationData.theme
|
||||
self.titleView.strings = self.presentationData.strings
|
||||
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData))
|
||||
|
@ -166,8 +166,9 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
context.sharedContext.openResolvedUrl(resolved, context: context, urlContext: .generic, navigationController: navigationController, openPeer: { peerId, navigation in
|
||||
// self?.openPeer(peerId: peerId, navigation: navigation)
|
||||
}, sendFile: nil,
|
||||
sendSticker: nil,
|
||||
present: { c, a in
|
||||
sendSticker: nil,
|
||||
requestMessageActionUrlAuth: nil,
|
||||
present: { c, a in
|
||||
present(c, a)
|
||||
}, dismissInput: {
|
||||
self?.dismissInput()
|
||||
|
@ -511,7 +511,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
peerContextAction(peer.peer, .search(nil), node, gesture)
|
||||
}
|
||||
})
|
||||
case let .message(message, peer, readState, presentationData, totalCount, selected, displayCustomHeader):
|
||||
case let .message(message, peer, readState, presentationData, _, selected, displayCustomHeader):
|
||||
let header = ChatListSearchItemHeader(type: .messages, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
|
||||
let selection: ChatHistoryMessageSelection = selected.flatMap { .selectable(selected: $0) } ?? .none
|
||||
if let tagMask = tagMask, tagMask != .photoOrVideo {
|
||||
|
@ -68,7 +68,11 @@ final class ChatListTitleView: UIView, NavigationBarTitleView, NavigationBarTitl
|
||||
}
|
||||
}
|
||||
|
||||
var strings: PresentationStrings
|
||||
var strings: PresentationStrings {
|
||||
didSet {
|
||||
self.proxyButton.accessibilityLabel = self.strings.VoiceOver_Navigation_ProxySettings
|
||||
}
|
||||
}
|
||||
|
||||
init(theme: PresentationTheme, strings: PresentationStrings) {
|
||||
self.theme = theme
|
||||
|
@ -132,9 +132,7 @@ public class InviteContactsController: ViewController, MFMessageComposeViewContr
|
||||
if let strongSelf = self {
|
||||
let url = strongSelf.presentationData.strings.InviteText_URL
|
||||
let body = strongSelf.presentationData.strings.InviteText_SingleContact(url).0
|
||||
|
||||
let shareController = ShareController(context: strongSelf.context, subject: .text(body), externalShare: true, immediateExternalShare: true)
|
||||
strongSelf.present(shareController, in: .window(.root))
|
||||
presentExternalShare(context: strongSelf.context, text: body, parentController: strongSelf)
|
||||
|
||||
strongSelf.contactsNode.listNode.clearHighlightAnimated(true)
|
||||
}
|
||||
|
@ -1249,11 +1249,16 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
public var forceHidden = false {
|
||||
didSet {
|
||||
self.updateItemNodeVisibilititesAndScrolling()
|
||||
}
|
||||
}
|
||||
private func updateItemNodeVisibilititesAndScrolling() {
|
||||
let visibleRect = self.scrollView.bounds
|
||||
let isScrolling = self.scrollView.isDragging || self.scrollView.isDecelerating
|
||||
for (_, itemNode) in self.itemNodes {
|
||||
let visible = itemNode.frame.intersects(visibleRect)
|
||||
let visible = itemNode.frame.intersects(visibleRect) && !self.forceHidden
|
||||
if itemNode.isVisibleInGrid != visible {
|
||||
itemNode.isVisibleInGrid = visible
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ public final class PeekController: ViewController {
|
||||
private let content: PeekControllerContent
|
||||
var sourceNode: () -> ASDisplayNode?
|
||||
|
||||
public var visibilityUpdated: ((Bool) -> Void)?
|
||||
|
||||
private var animatedIn = false
|
||||
|
||||
public init(theme: PeekControllerTheme, content: PeekControllerContent, sourceNode: @escaping () -> ASDisplayNode?) {
|
||||
@ -67,6 +69,8 @@ public final class PeekController: ViewController {
|
||||
if !self.animatedIn {
|
||||
self.animatedIn = true
|
||||
self.controllerNode.animateIn(from: self.getSourceRect())
|
||||
|
||||
self.visibilityUpdated?(true)
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,6 +81,7 @@ public final class PeekController: ViewController {
|
||||
}
|
||||
|
||||
override public func dismiss(completion: (() -> Void)? = nil) {
|
||||
self.visibilityUpdated?(false)
|
||||
self.controllerNode.animateOut(to: self.getSourceRect(), completion: { [weak self] in
|
||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||
})
|
||||
|
@ -504,6 +504,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
if !displayInfo {
|
||||
authorNameText = ""
|
||||
dateText = ""
|
||||
canEdit = false
|
||||
}
|
||||
|
||||
var messageText = NSAttributedString(string: "")
|
||||
|
@ -665,7 +665,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
playing = true
|
||||
case let .buffering(_, whilePlaying, _, display):
|
||||
displayProgress = display
|
||||
initialBuffering = true
|
||||
initialBuffering = !whilePlaying
|
||||
isPaused = !whilePlaying
|
||||
var isStreaming = false
|
||||
if let fetchStatus = strongSelf.fetchStatus {
|
||||
|
@ -1198,6 +1198,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
}, sendFile: nil,
|
||||
sendSticker: nil,
|
||||
requestMessageActionUrlAuth: nil,
|
||||
present: { c, a in
|
||||
self?.present(c, a)
|
||||
}, dismissInput: {
|
||||
@ -1275,6 +1276,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
fromPlayingVideo = true
|
||||
entries.append(InstantPageGalleryEntry(index: Int32(media.index), pageId: webPage.webpageId, media: media, caption: media.caption, credit: media.credit, location: nil))
|
||||
} else {
|
||||
fromPlayingVideo = true
|
||||
var medias: [InstantPageMedia] = mediasFromItems(items)
|
||||
medias = medias.filter {
|
||||
return $0.media is TelegramMediaImage || $0.media is TelegramMediaFile
|
||||
|
@ -615,24 +615,26 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId, ad
|
||||
})))
|
||||
}
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextEdit, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
let controller = inviteLinkEditController(context: context, peerId: peerId, invite: invite, completion: { invite in
|
||||
if let invite = invite {
|
||||
if invite.isRevoked {
|
||||
invitesContext.remove(invite)
|
||||
revokedInvitesContext.add(invite.withUpdated(isRevoked: true))
|
||||
} else {
|
||||
invitesContext.update(invite)
|
||||
if !invite.isPermanent {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextEdit, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
let controller = inviteLinkEditController(context: context, peerId: peerId, invite: invite, completion: { invite in
|
||||
if let invite = invite {
|
||||
if invite.isRevoked {
|
||||
invitesContext.remove(invite)
|
||||
revokedInvitesContext.add(invite.withUpdated(isRevoked: true))
|
||||
} else {
|
||||
invitesContext.update(invite)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
controller.navigationPresentation = .modal
|
||||
pushControllerImpl?(controller)
|
||||
})))
|
||||
})
|
||||
controller.navigationPresentation = .modal
|
||||
pushControllerImpl?(controller)
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
if invite.isRevoked {
|
||||
|
@ -79,10 +79,36 @@ public struct ItemListToolbarItem {
|
||||
}
|
||||
|
||||
let actions: [Action]
|
||||
|
||||
var toolbar: Toolbar {
|
||||
var leftAction: ToolbarAction?
|
||||
var middleAction: ToolbarAction?
|
||||
var rightAction: ToolbarAction?
|
||||
|
||||
if self.actions.count == 1 {
|
||||
if let action = self.actions.first {
|
||||
middleAction = ToolbarAction(title: action.title, isEnabled: action.isEnabled)
|
||||
}
|
||||
} else if actions.count == 2 {
|
||||
if let action = self.actions.first {
|
||||
leftAction = ToolbarAction(title: action.title, isEnabled: action.isEnabled)
|
||||
}
|
||||
if let action = self.actions.last {
|
||||
rightAction = ToolbarAction(title: action.title, isEnabled: action.isEnabled)
|
||||
}
|
||||
} else if actions.count == 3 {
|
||||
leftAction = ToolbarAction(title: self.actions[0].title, isEnabled: self.actions[0].isEnabled)
|
||||
middleAction = ToolbarAction(title: self.actions[1].title, isEnabled: self.actions[1].isEnabled)
|
||||
rightAction = ToolbarAction(title: self.actions[2].title, isEnabled: self.actions[2].isEnabled)
|
||||
}
|
||||
return Toolbar(leftAction: leftAction, rightAction: rightAction, middleAction: middleAction)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private struct ItemListNodeTransition {
|
||||
let theme: PresentationTheme
|
||||
let strings: PresentationStrings
|
||||
let entries: ItemListNodeEntryTransition
|
||||
let updateStyle: ItemListStyle?
|
||||
let emptyStateItem: ItemListControllerEmptyStateItem?
|
||||
@ -348,7 +374,7 @@ open class ItemListControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
scrollToItem = state.initialScrollToItem
|
||||
}
|
||||
|
||||
return ItemListNodeTransition(theme: presentationData.theme, entries: transition, updateStyle: updatedStyle, emptyStateItem: state.emptyStateItem, searchItem: state.searchItem, toolbarItem: state.toolbarItem, focusItemTag: state.focusItemTag, ensureVisibleItemTag: state.ensureVisibleItemTag, scrollToItem: scrollToItem, firstTime: previous == nil, animated: previous != nil && state.animateChanges, animateAlpha: previous != nil && state.animateChanges, crossfade: state.crossfadeState, mergedEntries: state.entries, scrollEnabled: state.scrollEnabled)
|
||||
return ItemListNodeTransition(theme: presentationData.theme, strings: presentationData.strings, entries: transition, updateStyle: updatedStyle, emptyStateItem: state.emptyStateItem, searchItem: state.searchItem, toolbarItem: state.toolbarItem, focusItemTag: state.focusItemTag, ensureVisibleItemTag: state.ensureVisibleItemTag, scrollToItem: scrollToItem, firstTime: previous == nil, animated: previous != nil && state.animateChanges, animateAlpha: previous != nil && state.animateChanges, crossfade: state.crossfadeState, mergedEntries: state.entries, scrollEnabled: state.scrollEnabled)
|
||||
})
|
||||
|> deliverOnMainQueue).start(next: { [weak self] transition in
|
||||
if let strongSelf = self {
|
||||
@ -452,6 +478,10 @@ open class ItemListControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
searchNode.updateLayout(layout: layout, navigationBarHeight: navigationBarHeight, transition: transition)
|
||||
}
|
||||
|
||||
if let toolbarNode = self.toolbarNode {
|
||||
// toolbarNode.updateLayout(size: layout.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: UIEdgeInsets(), bottomInset: 0.0, toolbar: <#T##Toolbar#>, transition: transition)
|
||||
}
|
||||
|
||||
let dequeue = self.validLayout == nil
|
||||
self.validLayout = (layout, navigationBarHeight)
|
||||
if dequeue {
|
||||
@ -610,6 +640,47 @@ open class ItemListControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
self.listNode.accessibilityPageScrolledString = { row, count in
|
||||
return transition.strings.VoiceOver_ScrollStatus(row, count).0
|
||||
}
|
||||
|
||||
let toolbarFrame = CGRect()
|
||||
let layoutTransition: ContainedViewLayoutTransition = .immediate
|
||||
if let toolbarItem = transition.toolbarItem, let (layout, _) = self.validLayout {
|
||||
if let toolbarNode = self.toolbarNode {
|
||||
layoutTransition.updateFrame(node: toolbarNode, frame: toolbarFrame)
|
||||
toolbarNode.updateLayout(size: toolbarFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, bottomInset: layout.intrinsicInsets.bottom, toolbar: toolbarItem.toolbar, transition: layoutTransition)
|
||||
} else {
|
||||
let toolbarNode = ToolbarNode(theme: TabBarControllerTheme(rootControllerTheme: transition.theme), left: {
|
||||
toolbarItem.actions[0].action()
|
||||
}, right: {
|
||||
if toolbarItem.actions.count == 2 {
|
||||
toolbarItem.actions[1].action()
|
||||
} else if toolbarItem.actions.count == 3 {
|
||||
toolbarItem.actions[2].action()
|
||||
}
|
||||
}, middle: {
|
||||
if toolbarItem.actions.count == 1 {
|
||||
toolbarItem.actions[0].action()
|
||||
} else if toolbarItem.actions.count == 3 {
|
||||
toolbarItem.actions[1].action()
|
||||
}
|
||||
})
|
||||
toolbarNode.frame = toolbarFrame
|
||||
toolbarNode.updateLayout(size: toolbarFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, bottomInset: layout.intrinsicInsets.bottom, toolbar: toolbarItem.toolbar, transition: .immediate)
|
||||
self.addSubnode(toolbarNode)
|
||||
self.toolbarNode = toolbarNode
|
||||
if transition.animated {
|
||||
toolbarNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
} else if let toolbarNode = self.toolbarNode {
|
||||
self.toolbarNode = nil
|
||||
layoutTransition.updateAlpha(node: toolbarNode, alpha: 0.0, completion: { [weak toolbarNode] _ in
|
||||
toolbarNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
|
||||
self.listNode.transaction(deleteIndices: transition.entries.deletions, insertIndicesAndItems: transition.entries.insertions, updateIndicesAndItems: transition.entries.updates, options: options, scrollToItem: scrollToItem, updateOpaqueState: ItemListNodeOpaqueState(mergedEntries: transition.mergedEntries), completion: { [weak self] _ in
|
||||
if let strongSelf = self {
|
||||
if !strongSelf.didSetReady {
|
||||
|
@ -61,7 +61,7 @@ const CGFloat TGPhotoPaintSettingsPadPickerWidth = 360.0f;
|
||||
_eyedropperButton.exclusiveTouch = true;
|
||||
[_eyedropperButton setImage:TGTintedImage([UIImage imageNamed:@"Editor/Eyedropper"], [UIColor whiteColor]) forState:UIControlStateNormal];
|
||||
[_eyedropperButton addTarget:self action:@selector(eyedropperButtonPressed) forControlEvents:UIControlEventTouchUpInside];
|
||||
// [self addSubview:_eyedropperButton];
|
||||
[self addSubview:_eyedropperButton];
|
||||
|
||||
_settingsButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 44.0f, 44.0f)];
|
||||
_settingsButton.exclusiveTouch = true;
|
||||
@ -211,8 +211,7 @@ const CGFloat TGPhotoPaintSettingsPadPickerWidth = 360.0f;
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
CGFloat leftInset = 23.0f;
|
||||
CGFloat rightInset = 66.0f;
|
||||
CGFloat inset = 66.0f;
|
||||
CGFloat colorPickerHeight = 10.0f;
|
||||
if (self.frame.size.width > self.frame.size.height)
|
||||
{
|
||||
@ -223,14 +222,14 @@ const CGFloat TGPhotoPaintSettingsPadPickerWidth = 360.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
_colorPicker.frame = CGRectMake(leftInset, ceil((self.frame.size.height - colorPickerHeight) / 2.0f), self.frame.size.width - leftInset - rightInset, colorPickerHeight);
|
||||
_colorPicker.frame = CGRectMake(inset, ceil((self.frame.size.height - colorPickerHeight) / 2.0f), self.frame.size.width - inset - inset, colorPickerHeight);
|
||||
_eyedropperButton.frame = CGRectMake(10.0f, floor((self.frame.size.height - _eyedropperButton.frame.size.height) / 2.0f) + 1.0f, _eyedropperButton.frame.size.width, _eyedropperButton.frame.size.height);
|
||||
_settingsButton.frame = CGRectMake(self.frame.size.width - _settingsButton.frame.size.width - 10.0f, floor((self.frame.size.height - _settingsButton.frame.size.height) / 2.0f) + 1.0f, _settingsButton.frame.size.width, _settingsButton.frame.size.height);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_colorPicker.frame = CGRectMake(ceil((self.frame.size.width - colorPickerHeight) / 2.0f), rightInset, colorPickerHeight, self.frame.size.height - leftInset - rightInset);
|
||||
_colorPicker.frame = CGRectMake(ceil((self.frame.size.width - colorPickerHeight) / 2.0f), inset, colorPickerHeight, self.frame.size.height - inset - inset);
|
||||
_eyedropperButton.frame = CGRectMake(floor((self.frame.size.width - _eyedropperButton.frame.size.width) / 2.0f), self.frame.size.height - _eyedropperButton.frame.size.height - 10.0, _eyedropperButton.frame.size.width, _eyedropperButton.frame.size.height);
|
||||
_settingsButton.frame = CGRectMake(floor((self.frame.size.width - _settingsButton.frame.size.width) / 2.0f), 10.0f, _settingsButton.frame.size.width, _settingsButton.frame.size.height);
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ private enum ChannelDiscussionGroupSetupControllerEntry: ItemListNodeEntry {
|
||||
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.plusIconImage(theme), title: text, sectionId: self.section, editing: false, action: {
|
||||
arguments.createGroup()
|
||||
})
|
||||
case let .group(_, theme, strings, peer, nameOrder):
|
||||
case let .group(_, _, strings, peer, nameOrder):
|
||||
let text: String
|
||||
if let peer = peer as? TelegramChannel, let addressName = peer.addressName, !addressName.isEmpty {
|
||||
text = "@\(addressName)"
|
||||
@ -160,9 +160,9 @@ private enum ChannelDiscussionGroupSetupControllerEntry: ItemListNodeEntry {
|
||||
return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(timeFormat: .regular, dateFormat: .monthFirst, dateSeparator: ".", decimalSeparator: ".", groupingSeparator: "."), nameDisplayOrder: nameOrder, context: arguments.context, peer: peer, aliasHandling: .standard, nameStyle: .plain, presence: nil, text: .text(text, .secondary), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: true, sectionId: self.section, action: {
|
||||
arguments.selectGroup(peer.id)
|
||||
}, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in })
|
||||
case let .groupsInfo(theme, title):
|
||||
case let .groupsInfo(_, title):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(title), sectionId: self.section)
|
||||
case let .unlink(theme, title):
|
||||
case let .unlink(_, title):
|
||||
return ItemListActionItem(presentationData: presentationData, title: title, kind: .destructive, alignment: .center, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.unlinkGroup()
|
||||
})
|
||||
|
@ -20,6 +20,7 @@ import Markdown
|
||||
public enum PeerReportSubject {
|
||||
case peer(PeerId)
|
||||
case messages([MessageId])
|
||||
case profilePhoto(PeerId, Int64)
|
||||
}
|
||||
|
||||
public enum PeerReportOption {
|
||||
@ -60,7 +61,7 @@ public func presentPeerReportOptions(context: AccountContext, parent: ViewContro
|
||||
}, action: { [weak parent] _, f in
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
var reportReason: ReportReason?
|
||||
let reportReason: ReportReason
|
||||
switch option {
|
||||
case .spam:
|
||||
reportReason = .spam
|
||||
@ -75,30 +76,60 @@ public func presentPeerReportOptions(context: AccountContext, parent: ViewContro
|
||||
case .copyright:
|
||||
reportReason = .copyright
|
||||
case .other:
|
||||
break
|
||||
reportReason = .custom
|
||||
}
|
||||
if let reportReason = reportReason {
|
||||
switch subject {
|
||||
case let .peer(peerId):
|
||||
let _ = (reportPeer(account: context.account, peerId: peerId, reason: reportReason, message: "")
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
if let path = getAppBundle().path(forResource: "PoliceCar", ofType: "tgs") {
|
||||
parent?.present(UndoOverlayController(presentationData: presentationData, content: .emoji(path: path, text: presentationData.strings.Report_Succeed), elevatedLayout: false, action: { _ in return false }), in: .current)
|
||||
}
|
||||
completion(reportReason, true)
|
||||
})
|
||||
case let .messages(messageIds):
|
||||
let _ = (reportPeerMessages(account: context.account, messageIds: messageIds, reason: reportReason, message: "")
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
if let path = getAppBundle().path(forResource: "PoliceCar", ofType: "tgs") {
|
||||
parent?.present(UndoOverlayController(presentationData: presentationData, content: .emoji(path: path, text: presentationData.strings.Report_Succeed), elevatedLayout: false, action: { _ in return false }), in: .current)
|
||||
}
|
||||
completion(reportReason, true)
|
||||
})
|
||||
|
||||
let displaySuccess = {
|
||||
if let path = getAppBundle().path(forResource: "PoliceCar", ofType: "tgs") {
|
||||
parent?.present(UndoOverlayController(presentationData: presentationData, content: .emoji(path: path, text: presentationData.strings.Report_Succeed), elevatedLayout: false, action: { _ in return false }), in: .current)
|
||||
}
|
||||
} else {
|
||||
parent?.push(peerReportController(context: context, subject: subject, completion: completion))
|
||||
}
|
||||
|
||||
let action: (String) -> Void = { message in
|
||||
switch subject {
|
||||
case let .peer(peerId):
|
||||
let _ = (reportPeer(account: context.account, peerId: peerId, reason: reportReason, message: "")
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
displaySuccess()
|
||||
completion(reportReason, true)
|
||||
})
|
||||
case let .messages(messageIds):
|
||||
let _ = (reportPeerMessages(account: context.account, messageIds: messageIds, reason: reportReason, message: "")
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
displaySuccess()
|
||||
completion(reportReason, true)
|
||||
})
|
||||
case let .profilePhoto(peerId, photoId):
|
||||
let _ = (reportPeerPhoto(account: context.account, peerId: peerId, reason: reportReason, message: "")
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
displaySuccess()
|
||||
completion(reportReason, true)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let controller = ActionSheetController(presentationData: presentationData, allowInputInset: true)
|
||||
let dismissAction: () -> Void = { [weak controller] in
|
||||
controller?.dismissAnimated()
|
||||
}
|
||||
var message = ""
|
||||
var items: [ActionSheetItem] = []
|
||||
items.append(ReportPeerHeaderActionSheetItem(context: context, text: presentationData.strings.Report_AdditionalDetailsText))
|
||||
items.append(ReportPeerDetailsActionSheetItem(context: context, placeholderText: presentationData.strings.Report_AdditionalDetailsPlaceholder, textUpdated: { text in
|
||||
message = text
|
||||
}))
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Report_Report, color: .accent, font: .bold, enabled: true, action: {
|
||||
dismissAction()
|
||||
|
||||
action(message)
|
||||
}))
|
||||
|
||||
controller.setItemGroups([
|
||||
ActionSheetItemGroup(items: items),
|
||||
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
|
||||
])
|
||||
parent?.present(controller, in: .window(.root))
|
||||
|
||||
f(.dismissWithoutContent)
|
||||
})))
|
||||
}
|
||||
@ -162,17 +193,21 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe
|
||||
passthrough = false
|
||||
}
|
||||
|
||||
let action = {
|
||||
let displaySuccess = {
|
||||
if let path = getAppBundle().path(forResource: "PoliceCar", ofType: "tgs") {
|
||||
present(UndoOverlayController(presentationData: presentationData, content: .emoji(path: path, text: presentationData.strings.Report_Succeed), elevatedLayout: false, action: { _ in return false }), nil)
|
||||
}
|
||||
}
|
||||
|
||||
let action: (String) -> Void = { message in
|
||||
switch subject {
|
||||
case let .peer(peerId):
|
||||
if passthrough {
|
||||
completion(reportReason, true)
|
||||
} else {
|
||||
let _ = (reportPeer(account: context.account, peerId: peerId, reason: reportReason, message: "")
|
||||
let _ = (reportPeer(account: context.account, peerId: peerId, reason: reportReason, message: message)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
if let path = getAppBundle().path(forResource: "PoliceCar", ofType: "tgs") {
|
||||
present(UndoOverlayController(presentationData: presentationData, content: .emoji(path: path, text: presentationData.strings.Report_Succeed), elevatedLayout: false, action: { _ in return false }), nil)
|
||||
}
|
||||
displaySuccess()
|
||||
completion(nil, false)
|
||||
})
|
||||
}
|
||||
@ -180,11 +215,19 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe
|
||||
if passthrough {
|
||||
completion(reportReason, true)
|
||||
} else {
|
||||
let _ = (reportPeerMessages(account: context.account, messageIds: messageIds, reason: reportReason, message: "")
|
||||
let _ = (reportPeerMessages(account: context.account, messageIds: messageIds, reason: reportReason, message: message)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
if let path = getAppBundle().path(forResource: "PoliceCar", ofType: "tgs") {
|
||||
present(UndoOverlayController(presentationData: presentationData, content: .emoji(path: path, text: presentationData.strings.Report_Succeed), elevatedLayout: false, action: { _ in return false }), nil)
|
||||
}
|
||||
displaySuccess()
|
||||
completion(nil, false)
|
||||
})
|
||||
}
|
||||
case let .profilePhoto(peerId, photoId):
|
||||
if passthrough {
|
||||
completion(reportReason, true)
|
||||
} else {
|
||||
let _ = (reportPeerPhoto(account: context.account, peerId: peerId, reason: reportReason, message: message)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
displaySuccess()
|
||||
completion(nil, false)
|
||||
})
|
||||
}
|
||||
@ -205,7 +248,7 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Report_Report, color: .accent, font: .bold, enabled: true, action: {
|
||||
dismissAction()
|
||||
|
||||
action()
|
||||
action(message)
|
||||
}))
|
||||
|
||||
controller.setItemGroups([
|
||||
@ -214,7 +257,7 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe
|
||||
])
|
||||
present(controller, nil)
|
||||
} else {
|
||||
action()
|
||||
action("")
|
||||
}
|
||||
} else {
|
||||
push(peerReportController(context: context, subject: subject, completion: completion))
|
||||
@ -369,16 +412,21 @@ private func peerReportController(context: AccountContext, subject: PeerReportSu
|
||||
dismissImpl?()
|
||||
}
|
||||
switch subject {
|
||||
case let .peer(peerId):
|
||||
reportDisposable.set((reportPeer(account: context.account, peerId: peerId, reason: reportReason, message: text)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
completed()
|
||||
}))
|
||||
case let .messages(messageIds):
|
||||
reportDisposable.set((reportPeerMessages(account: context.account, messageIds: messageIds, reason: reportReason, message: text)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
completed()
|
||||
}))
|
||||
case let .peer(peerId):
|
||||
reportDisposable.set((reportPeer(account: context.account, peerId: peerId, reason: reportReason, message: text)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
completed()
|
||||
}))
|
||||
case let .messages(messageIds):
|
||||
reportDisposable.set((reportPeerMessages(account: context.account, messageIds: messageIds, reason: reportReason, message: text)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
completed()
|
||||
}))
|
||||
case let .profilePhoto(peerId, photoId):
|
||||
reportDisposable.set((reportPeerPhoto(account: context.account, peerId: peerId, reason: reportReason, message: text)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
completed()
|
||||
}))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -1438,6 +1438,7 @@ public func userInfoController(context: AccountContext, peerId: PeerId, mode: Pe
|
||||
|
||||
}, sendFile: nil,
|
||||
sendSticker: nil,
|
||||
requestMessageActionUrlAuth: nil,
|
||||
present: { c, a in
|
||||
presentControllerImpl?(c, a)
|
||||
}, dismissInput: {
|
||||
|
@ -531,8 +531,7 @@ public func proxySettingsController(accountManager: AccountManager, context: Acc
|
||||
result += string
|
||||
}
|
||||
|
||||
let controller = ShareController(context: context, subject: .text(result), preferredAction: .default, showInChat: nil, externalShare: true, immediateExternalShare: true, switchableAccounts: [])
|
||||
presentControllerImpl?(controller, nil)
|
||||
presentExternalShare(context: context, text: result, parentController: strongController)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -378,19 +378,15 @@ func proxyServerSettingsController(context: AccountContext? = nil, presentationD
|
||||
}
|
||||
shareImpl = { [weak controller] in
|
||||
let state = stateValue.with { $0 }
|
||||
guard let server = proxyServerSettings(with: state), let strongController = controller else {
|
||||
guard let server = proxyServerSettings(with: state) else {
|
||||
return
|
||||
}
|
||||
|
||||
let link = shareLink(for: server)
|
||||
controller?.view.endEditing(true)
|
||||
if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
|
||||
let controller = ShareProxyServerActionSheetController(presentationData: presentationData, updatedPresentationData: updatedPresentationData, link: link)
|
||||
presentControllerImpl?(controller, nil)
|
||||
} else if let context = context {
|
||||
let controller = ShareController(context: context, subject: .url(link), preferredAction: .default, showInChat: nil, externalShare: true, immediateExternalShare: true, switchableAccounts: [])
|
||||
presentControllerImpl?(controller, nil)
|
||||
}
|
||||
|
||||
let controller = ShareProxyServerActionSheetController(presentationData: presentationData, updatedPresentationData: updatedPresentationData, link: link)
|
||||
presentControllerImpl?(controller, nil)
|
||||
}
|
||||
|
||||
return controller
|
||||
|
@ -180,7 +180,7 @@ public func logoutOptionsController(context: AccountContext, navigationControlle
|
||||
dismissImpl?()
|
||||
|
||||
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, openPeer: { peer, navigation in
|
||||
}, sendFile: nil, sendSticker: nil, present: { controller, arguments in
|
||||
}, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, present: { controller, arguments in
|
||||
pushControllerImpl?(controller)
|
||||
}, dismissInput: {}, contentContext: nil)
|
||||
})
|
||||
|
@ -897,7 +897,7 @@ func settingsSearchableItems(context: AccountContext, notificationExceptionsList
|
||||
let _ = (cachedFaqInstantPage(context: context)
|
||||
|> deliverOnMainQueue).start(next: { resolvedUrl in
|
||||
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, openPeer: { peer, navigation in
|
||||
}, sendFile: nil, sendSticker: nil, present: { controller, arguments in
|
||||
}, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, present: { controller, arguments in
|
||||
present(.push, controller)
|
||||
}, dismissInput: {}, contentContext: nil)
|
||||
})
|
||||
|
@ -1080,3 +1080,13 @@ private class ShareToInstagramActivity: UIActivity {
|
||||
activityDidFinish(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func presentExternalShare(context: AccountContext, text: String, parentController: ViewController) {
|
||||
let activityController = UIActivityViewController(activityItems: [text], applicationActivities: nil)
|
||||
if let window = parentController.view.window {
|
||||
activityController.popoverPresentationController?.sourceView = window
|
||||
activityController.popoverPresentationController?.sourceRect = CGRect(origin: CGPoint(x: window.bounds.width / 2.0, y: window.bounds.size.height - 1.0), size: CGSize(width: 1.0, height: 1.0))
|
||||
}
|
||||
context.sharedContext.applicationBindings.presentNativeController(activityController)
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ public final class StickerPackPreviewController: ViewController, StandalonePrese
|
||||
private let openMentionDisposable = MetaDisposable()
|
||||
|
||||
private var presentationDataDisposable: Disposable?
|
||||
|
||||
|
||||
public var sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)? {
|
||||
didSet {
|
||||
if self.isNodeLoaded {
|
||||
|
@ -240,6 +240,11 @@ final class StickerPackPreviewControllerNode: ViewControllerTracingNode, UIScrol
|
||||
let controller = PeekController(theme: PeekControllerTheme(presentationTheme: strongSelf.presentationData.theme), content: content, sourceNode: {
|
||||
return sourceNode
|
||||
})
|
||||
controller.visibilityUpdated = { [weak self] visible in
|
||||
if let strongSelf = self {
|
||||
strongSelf.contentGridNode.forceHidden = visible
|
||||
}
|
||||
}
|
||||
strongSelf.presentInGlobalOverlay?(controller, nil)
|
||||
return controller
|
||||
}
|
||||
|
@ -133,9 +133,9 @@ func managedConsumePersonalMessagesActions(postbox: Postbox, network: Network, s
|
||||
|
||||
for (entry, disposable) in beginValidateOperations {
|
||||
let signal = synchronizeUnseenPersonalMentionsTag(postbox: postbox, network: network, entry: entry)
|
||||
|> then(postbox.transaction { transaction -> Void in
|
||||
transaction.removeInvalidatedMessageHistoryTagsSummaryEntry(entry)
|
||||
})
|
||||
|> then(postbox.transaction { transaction -> Void in
|
||||
transaction.removeInvalidatedMessageHistoryTagsSummaryEntry(entry)
|
||||
})
|
||||
disposable.set(signal.start())
|
||||
}
|
||||
})
|
||||
|
@ -126,6 +126,22 @@ public func reportPeer(account: Account, peerId: PeerId, reason: ReportReason, m
|
||||
} |> switchToLatest
|
||||
}
|
||||
|
||||
public func reportPeerPhoto(account: Account, peerId: PeerId, reason: ReportReason, message: String) -> Signal<Void, NoError> {
|
||||
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
|
||||
return account.network.request(Api.functions.account.reportProfilePhoto(peer: inputPeer, photoId: .inputPhotoEmpty, reason: reason.apiReason, message: message))
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
}
|
||||
|> mapToSignal { _ -> Signal<Void, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
} |> switchToLatest
|
||||
}
|
||||
|
||||
public func reportPeerMessages(account: Account, messageIds: [MessageId], reason: ReportReason, message: String) -> Signal<Void, NoError> {
|
||||
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
let groupedIds = messagesIdsGroupedByPeerId(messageIds)
|
||||
@ -149,22 +165,6 @@ public func reportPeerMessages(account: Account, messageIds: [MessageId], reason
|
||||
} |> switchToLatest
|
||||
}
|
||||
|
||||
public func reportSupergroupPeer(account: Account, peerId: PeerId, memberId: PeerId, messageIds: [MessageId]) -> Signal<Void, NoError> {
|
||||
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputChannel(peer), let memberPeer = transaction.getPeer(memberId), let inputMember = apiInputUser(memberPeer) {
|
||||
return account.network.request(Api.functions.channels.reportSpam(channel: inputPeer, userId: inputMember, id: messageIds.map({$0.id})))
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
}
|
||||
|> mapToSignal { _ -> Signal<Void, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
} |> switchToLatest
|
||||
}
|
||||
|
||||
public func dismissPeerStatusOptions(account: Account, peerId: PeerId) -> Signal<Void, NoError> {
|
||||
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
|
||||
|
@ -174,62 +174,89 @@ public enum MessageActionUrlAuthResult {
|
||||
case request(String, Peer, Bool)
|
||||
}
|
||||
|
||||
public func requestMessageActionUrlAuth(account: Account, messageId: MessageId, buttonId: Int32) -> Signal<MessageActionUrlAuthResult, NoError> {
|
||||
return account.postbox.loadedPeerWithId(messageId.peerId)
|
||||
|> take(1)
|
||||
|> mapToSignal { peer in
|
||||
if let inputPeer = apiInputPeer(peer) {
|
||||
return account.network.request(Api.functions.messages.requestUrlAuth(peer: inputPeer, msgId: messageId.id, buttonId: buttonId))
|
||||
public enum MessageActionUrlSubject {
|
||||
case message(id: MessageId, buttonId: Int32)
|
||||
case url(String)
|
||||
}
|
||||
|
||||
public func requestMessageActionUrlAuth(account: Account, subject: MessageActionUrlSubject) -> Signal<MessageActionUrlAuthResult, NoError> {
|
||||
let request: Signal<Api.UrlAuthResult?, MTRpcError>
|
||||
switch subject {
|
||||
case let .message(messageId, buttonId):
|
||||
request = account.postbox.loadedPeerWithId(messageId.peerId)
|
||||
|> take(1)
|
||||
|> castError(MTRpcError.self)
|
||||
|> mapToSignal { peer -> Signal<Api.UrlAuthResult?, MTRpcError> in
|
||||
if let inputPeer = apiInputPeer(peer) {
|
||||
return account.network.request(Api.functions.messages.requestUrlAuth(peer: inputPeer, msgId: messageId.id, buttonId: buttonId))
|
||||
|> map(Optional.init)
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
case let .url(url):
|
||||
request = account.network.request(Api.functions.messages.requestUrlAuth(peer: .inputPeerEmpty, msgId: 0, buttonId: 0))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.UrlAuthResult?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> map { result -> MessageActionUrlAuthResult in
|
||||
guard let result = result else {
|
||||
return .default
|
||||
}
|
||||
switch result {
|
||||
case .urlAuthResultDefault:
|
||||
return .default
|
||||
case let .urlAuthResultAccepted(url):
|
||||
return .accepted(url)
|
||||
case let .urlAuthResultRequest(flags, bot, domain):
|
||||
return .request(domain, TelegramUser(user: bot), (flags & (1 << 0)) != 0)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .single(.default)
|
||||
}
|
||||
|
||||
return request
|
||||
|> `catch` { _ -> Signal<Api.UrlAuthResult?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> map { result -> MessageActionUrlAuthResult in
|
||||
guard let result = result else {
|
||||
return .default
|
||||
}
|
||||
switch result {
|
||||
case .urlAuthResultDefault:
|
||||
return .default
|
||||
case let .urlAuthResultAccepted(url):
|
||||
return .accepted(url)
|
||||
case let .urlAuthResultRequest(flags, bot, domain):
|
||||
return .request(domain, TelegramUser(user: bot), (flags & (1 << 0)) != 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func acceptMessageActionUrlAuth(account: Account, messageId: MessageId, buttonId: Int32, allowWriteAccess: Bool) -> Signal<MessageActionUrlAuthResult, NoError> {
|
||||
return account.postbox.loadedPeerWithId(messageId.peerId)
|
||||
|> take(1)
|
||||
|> mapToSignal { peer in
|
||||
if let inputPeer = apiInputPeer(peer) {
|
||||
var flags: Int32 = 0
|
||||
if allowWriteAccess {
|
||||
flags |= Int32(1 << 0)
|
||||
public func acceptMessageActionUrlAuth(account: Account, subject: MessageActionUrlSubject, allowWriteAccess: Bool) -> Signal<MessageActionUrlAuthResult, NoError> {
|
||||
var flags: Int32 = 0
|
||||
if allowWriteAccess {
|
||||
flags |= Int32(1 << 0)
|
||||
}
|
||||
|
||||
let request: Signal<Api.UrlAuthResult?, MTRpcError>
|
||||
switch subject {
|
||||
case let .message(messageId, buttonId):
|
||||
request = account.postbox.loadedPeerWithId(messageId.peerId)
|
||||
|> take(1)
|
||||
|> castError(MTRpcError.self)
|
||||
|> mapToSignal { peer -> Signal<Api.UrlAuthResult?, MTRpcError> in
|
||||
if let inputPeer = apiInputPeer(peer) {
|
||||
return account.network.request(Api.functions.messages.acceptUrlAuth(flags: flags, peer: inputPeer, msgId: messageId.id, buttonId: buttonId))
|
||||
|> map(Optional.init)
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
return account.network.request(Api.functions.messages.acceptUrlAuth(flags: flags, peer: inputPeer, msgId: messageId.id, buttonId: buttonId))
|
||||
case let .url(url):
|
||||
request = account.network.request(Api.functions.messages.acceptUrlAuth(flags: flags, peer: .inputPeerEmpty, msgId: 0, buttonId: 0))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.UrlAuthResult?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> map { result -> MessageActionUrlAuthResult in
|
||||
guard let result = result else {
|
||||
return .default
|
||||
}
|
||||
switch result {
|
||||
case let .urlAuthResultAccepted(url):
|
||||
return .accepted(url)
|
||||
default:
|
||||
return .default
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .single(.default)
|
||||
}
|
||||
|
||||
|
||||
return request
|
||||
|> `catch` { _ -> Signal<Api.UrlAuthResult?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> map { result -> MessageActionUrlAuthResult in
|
||||
guard let result = result else {
|
||||
return .default
|
||||
}
|
||||
switch result {
|
||||
case let .urlAuthResultAccepted(url):
|
||||
return .accepted(url)
|
||||
default:
|
||||
return .default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -27,8 +27,8 @@ final class ChatAvatarNavigationNode: ASDisplayNode {
|
||||
|
||||
super.init()
|
||||
|
||||
self.containerNode.addSubnode(self.avatarNode)
|
||||
self.addSubnode(self.containerNode)
|
||||
self.containerNode.addSubnode(self.avatarNode)
|
||||
|
||||
self.containerNode.activated = { [weak self] gesture, _ in
|
||||
guard let strongSelf = self else {
|
||||
|
@ -209,7 +209,7 @@ final class ChatButtonKeyboardInputNode: ChatInputNode {
|
||||
break
|
||||
case let .urlAuth(url, buttonId):
|
||||
if let message = self.message {
|
||||
self.controllerInteraction.requestMessageActionUrlAuth(url, message.id, buttonId)
|
||||
self.controllerInteraction.requestMessageActionUrlAuth(url, .message(id: message.id, buttonId: buttonId))
|
||||
}
|
||||
case let .setupPoll(isQuiz):
|
||||
self.controllerInteraction.openPollCreation(isQuiz)
|
||||
|
@ -306,6 +306,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
private var automaticMediaDownloadSettings: MediaAutoDownloadSettings
|
||||
private var automaticMediaDownloadSettingsDisposable: Disposable?
|
||||
|
||||
private var disableStickerAnimationsPromise = ValuePromise<Bool>(false)
|
||||
private var disableStickerAnimations = false
|
||||
private var stickerSettings: ChatInterfaceStickerSettings
|
||||
private var stickerSettingsDisposable: Disposable?
|
||||
|
||||
@ -1163,124 +1165,122 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}
|
||||
}
|
||||
}, requestMessageActionUrlAuth: { [weak self] defaultUrl, messageId, buttonId in
|
||||
}, requestMessageActionUrlAuth: { [weak self] defaultUrl, subject in
|
||||
if let strongSelf = self {
|
||||
guard strongSelf.presentationInterfaceState.subject != .scheduledMessages else {
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.ScheduledMessages_BotActionUnavailable, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
return
|
||||
}
|
||||
if let _ = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(messageId) {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
|
||||
return $0.updatedTitlePanelContext {
|
||||
if !$0.contains(where: {
|
||||
switch $0 {
|
||||
case .requestInProgress:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}) {
|
||||
var updatedContexts = $0
|
||||
updatedContexts.append(.requestInProgress)
|
||||
return updatedContexts.sorted()
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
|
||||
return $0.updatedTitlePanelContext {
|
||||
if !$0.contains(where: {
|
||||
switch $0 {
|
||||
case .requestInProgress:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return $0
|
||||
}) {
|
||||
var updatedContexts = $0
|
||||
updatedContexts.append(.requestInProgress)
|
||||
return updatedContexts.sorted()
|
||||
}
|
||||
})
|
||||
strongSelf.messageActionUrlAuthDisposable.set(((combineLatest(strongSelf.context.account.postbox.loadedPeerWithId(strongSelf.context.account.peerId), requestMessageActionUrlAuth(account: strongSelf.context.account, messageId: messageId, buttonId: buttonId) |> afterDisposed {
|
||||
Queue.mainQueue().async {
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
|
||||
return $0.updatedTitlePanelContext {
|
||||
if let index = $0.firstIndex(where: {
|
||||
switch $0 {
|
||||
case .requestInProgress:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}) {
|
||||
var updatedContexts = $0
|
||||
updatedContexts.remove(at: index)
|
||||
return updatedContexts
|
||||
return $0
|
||||
}
|
||||
})
|
||||
strongSelf.messageActionUrlAuthDisposable.set(((combineLatest(strongSelf.context.account.postbox.loadedPeerWithId(strongSelf.context.account.peerId), requestMessageActionUrlAuth(account: strongSelf.context.account, subject: subject) |> afterDisposed {
|
||||
Queue.mainQueue().async {
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
|
||||
return $0.updatedTitlePanelContext {
|
||||
if let index = $0.firstIndex(where: {
|
||||
switch $0 {
|
||||
case .requestInProgress:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}) {
|
||||
var updatedContexts = $0
|
||||
updatedContexts.remove(at: index)
|
||||
return updatedContexts
|
||||
}
|
||||
return $0
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})) |> deliverOnMainQueue).start(next: { peer, result in
|
||||
if let strongSelf = self {
|
||||
switch result {
|
||||
case .default:
|
||||
strongSelf.openUrl(defaultUrl, concealed: false)
|
||||
case let .request(domain, bot, requestWriteAccess):
|
||||
let controller = chatMessageActionUrlAuthController(context: strongSelf.context, defaultUrl: defaultUrl, domain: domain, bot: bot, requestWriteAccess: requestWriteAccess, displayName: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), open: { [weak self] authorize, allowWriteAccess in
|
||||
if let strongSelf = self {
|
||||
if authorize {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
|
||||
return $0.updatedTitlePanelContext {
|
||||
if !$0.contains(where: {
|
||||
switch $0 {
|
||||
case .requestInProgress:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}) {
|
||||
var updatedContexts = $0
|
||||
updatedContexts.append(.requestInProgress)
|
||||
return updatedContexts.sorted()
|
||||
}
|
||||
return $0
|
||||
}
|
||||
})
|
||||
|
||||
strongSelf.messageActionUrlAuthDisposable.set(((acceptMessageActionUrlAuth(account: strongSelf.context.account, subject: subject, allowWriteAccess: allowWriteAccess) |> afterDisposed {
|
||||
Queue.mainQueue().async {
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
|
||||
return $0.updatedTitlePanelContext {
|
||||
if let index = $0.firstIndex(where: {
|
||||
switch $0 {
|
||||
case .requestInProgress:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}) {
|
||||
var updatedContexts = $0
|
||||
updatedContexts.remove(at: index)
|
||||
return updatedContexts
|
||||
}
|
||||
return $0
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}) |> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
if let strongSelf = self {
|
||||
switch result {
|
||||
case let .accepted(url):
|
||||
strongSelf.openUrl(url, concealed: false)
|
||||
default:
|
||||
strongSelf.openUrl(defaultUrl, concealed: false)
|
||||
}
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
strongSelf.openUrl(defaultUrl, concealed: false)
|
||||
}
|
||||
return $0
|
||||
}
|
||||
})
|
||||
}
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
case let .accepted(url):
|
||||
strongSelf.openUrl(url, concealed: false)
|
||||
}
|
||||
})) |> deliverOnMainQueue).start(next: { peer, result in
|
||||
if let strongSelf = self {
|
||||
switch result {
|
||||
case .default:
|
||||
strongSelf.openUrl(defaultUrl, concealed: false)
|
||||
case let .request(domain, bot, requestWriteAccess):
|
||||
let controller = chatMessageActionUrlAuthController(context: strongSelf.context, defaultUrl: defaultUrl, domain: domain, bot: bot, requestWriteAccess: requestWriteAccess, displayName: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), open: { [weak self] authorize, allowWriteAccess in
|
||||
if let strongSelf = self {
|
||||
if authorize {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
|
||||
return $0.updatedTitlePanelContext {
|
||||
if !$0.contains(where: {
|
||||
switch $0 {
|
||||
case .requestInProgress:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}) {
|
||||
var updatedContexts = $0
|
||||
updatedContexts.append(.requestInProgress)
|
||||
return updatedContexts.sorted()
|
||||
}
|
||||
return $0
|
||||
}
|
||||
})
|
||||
|
||||
strongSelf.messageActionUrlAuthDisposable.set(((acceptMessageActionUrlAuth(account: strongSelf.context.account, messageId: messageId, buttonId: buttonId, allowWriteAccess: allowWriteAccess) |> afterDisposed {
|
||||
Queue.mainQueue().async {
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
|
||||
return $0.updatedTitlePanelContext {
|
||||
if let index = $0.firstIndex(where: {
|
||||
switch $0 {
|
||||
case .requestInProgress:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}) {
|
||||
var updatedContexts = $0
|
||||
updatedContexts.remove(at: index)
|
||||
return updatedContexts
|
||||
}
|
||||
return $0
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}) |> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
if let strongSelf = self {
|
||||
switch result {
|
||||
case let .accepted(url):
|
||||
strongSelf.openUrl(url, concealed: false)
|
||||
default:
|
||||
strongSelf.openUrl(defaultUrl, concealed: false)
|
||||
}
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
strongSelf.openUrl(defaultUrl, concealed: false)
|
||||
}
|
||||
}
|
||||
})
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
case let .accepted(url):
|
||||
strongSelf.openUrl(url, concealed: false)
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
}, activateSwitchInline: { [weak self] peerId, inputString in
|
||||
guard let strongSelf = self else {
|
||||
@ -2578,7 +2578,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}
|
||||
self.chatTitleView?.longPressed = { [weak self] in
|
||||
self?.interfaceInteraction?.beginMessageSearch(.everything, "")
|
||||
if let strongSelf = self, let peerView = strongSelf.peerView, let peer = peerView.peers[peerView.peerId], peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil && !strongSelf.presentationInterfaceState.isNotAccessible {
|
||||
strongSelf.interfaceInteraction?.beginMessageSearch(.everything, "")
|
||||
}
|
||||
}
|
||||
|
||||
let chatInfoButtonItem: UIBarButtonItem
|
||||
@ -3440,20 +3442,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
})
|
||||
|
||||
self.stickerSettingsDisposable = (context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.stickerSettings])
|
||||
|> deliverOnMainQueue).start(next: { [weak self] sharedData in
|
||||
self.stickerSettingsDisposable = combineLatest(queue: Queue.mainQueue(), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.stickerSettings]), self.disableStickerAnimationsPromise.get()).start(next: { [weak self] sharedData, disableStickerAnimations in
|
||||
var stickerSettings = StickerSettings.defaultSettings
|
||||
if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings] as? StickerSettings {
|
||||
stickerSettings = value
|
||||
}
|
||||
|
||||
let chatStickerSettings = ChatInterfaceStickerSettings(stickerSettings: stickerSettings)
|
||||
|
||||
if let strongSelf = self, strongSelf.stickerSettings != chatStickerSettings {
|
||||
if let strongSelf = self, strongSelf.stickerSettings != chatStickerSettings || strongSelf.disableStickerAnimations != disableStickerAnimations {
|
||||
strongSelf.stickerSettings = chatStickerSettings
|
||||
strongSelf.disableStickerAnimations = disableStickerAnimations
|
||||
strongSelf.controllerInteraction?.stickerSettings = chatStickerSettings
|
||||
if strongSelf.isNodeLoaded {
|
||||
strongSelf.chatDisplayNode.updateStickerSettings(chatStickerSettings)
|
||||
strongSelf.chatDisplayNode.updateStickerSettings(chatStickerSettings, forceStopAnimations: disableStickerAnimations)
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -7144,6 +7145,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
|
||||
override public func inFocusUpdated(isInFocus: Bool) {
|
||||
self.disableStickerAnimationsPromise.set(!isInFocus)
|
||||
self.chatDisplayNode.inFocusUpdated(isInFocus: isInFocus)
|
||||
}
|
||||
|
||||
@ -8497,6 +8499,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if let strongSelf = self {
|
||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||
|
||||
for item in results {
|
||||
if let item = item, item.fileSize > 2000 * 1024 * 1024 {
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: strongSelf.presentationData.strings.Conversation_UploadFileTooLarge, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var groupingKey: Int64?
|
||||
var fileTypes: (music: Bool, other: Bool) = (false, false)
|
||||
if results.count > 1 {
|
||||
@ -11082,6 +11091,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}, sendFile: nil,
|
||||
sendSticker: { [weak self] f, sourceNode, sourceRect in
|
||||
return self?.interfaceInteraction?.sendSticker(f, sourceNode, sourceRect) ?? false
|
||||
}, requestMessageActionUrlAuth: { [weak self] subject in
|
||||
if case let .url(url) = subject {
|
||||
self?.controllerInteraction?.requestMessageActionUrlAuth(url, subject)
|
||||
}
|
||||
}, present: { [weak self] c, a in
|
||||
self?.present(c, in: .window(.root), with: a)
|
||||
}, dismissInput: { [weak self] in
|
||||
|
@ -64,7 +64,7 @@ public final class ChatControllerInteraction {
|
||||
let sendGif: (FileMediaReference, ASDisplayNode, CGRect) -> Bool
|
||||
let sendBotContextResultAsGif: (ChatContextResultCollection, ChatContextResult, ASDisplayNode, CGRect) -> Bool
|
||||
let requestMessageActionCallback: (MessageId, MemoryBuffer?, Bool, Bool) -> Void
|
||||
let requestMessageActionUrlAuth: (String, MessageId, Int32) -> Void
|
||||
let requestMessageActionUrlAuth: (String, MessageActionUrlSubject) -> Void
|
||||
let activateSwitchInline: (PeerId?, String) -> Void
|
||||
let openUrl: (String, Bool, Bool?, Message?) -> Void
|
||||
let shareCurrentLocation: () -> Void
|
||||
@ -154,7 +154,7 @@ public final class ChatControllerInteraction {
|
||||
sendGif: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool,
|
||||
sendBotContextResultAsGif: @escaping (ChatContextResultCollection, ChatContextResult, ASDisplayNode, CGRect) -> Bool,
|
||||
requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool, Bool) -> Void,
|
||||
requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void,
|
||||
requestMessageActionUrlAuth: @escaping (String, MessageActionUrlSubject) -> Void,
|
||||
activateSwitchInline: @escaping (PeerId?, String) -> Void,
|
||||
openUrl: @escaping (String, Bool, Bool?, Message?) -> Void,
|
||||
shareCurrentLocation: @escaping () -> Void,
|
||||
@ -298,7 +298,7 @@ public final class ChatControllerInteraction {
|
||||
|
||||
static var `default`: ChatControllerInteraction {
|
||||
return ChatControllerInteraction(openMessage: { _, _ in
|
||||
return false }, openPeer: { _, _, _ in }, openPeerMention: { _ in }, openMessageContextMenu: { _, _, _, _, _ in }, openMessageContextActions: { _, _, _, _ in }, navigateToMessage: { _, _ in }, navigateToMessageStandalone: { _ in }, tapMessage: nil, clickThroughMessage: { }, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _, _ in return false }, sendGif: { _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _ in return false }, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _, _ in }, activateSwitchInline: { _, _ in }, openUrl: { _, _, _, _ in }, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { _, _ in }, openWallpaper: { _ in }, openTheme: { _ in }, openHashtag: { _, _ in }, updateInputState: { _ in }, updateInputMode: { _ in }, openMessageShareMenu: { _ in
|
||||
return false }, openPeer: { _, _, _ in }, openPeerMention: { _ in }, openMessageContextMenu: { _, _, _, _, _ in }, openMessageContextActions: { _, _, _, _ in }, navigateToMessage: { _, _ in }, navigateToMessageStandalone: { _ in }, tapMessage: nil, clickThroughMessage: { }, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _, _ in return false }, sendGif: { _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _ in return false }, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _ in }, activateSwitchInline: { _, _ in }, openUrl: { _, _, _, _ in }, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { _, _ in }, openWallpaper: { _ in }, openTheme: { _ in }, openHashtag: { _, _ in }, updateInputState: { _ in }, updateInputMode: { _ in }, openMessageShareMenu: { _ in
|
||||
}, presentController: { _, _ in }, navigationController: {
|
||||
return nil
|
||||
}, chatControllerNode: {
|
||||
|
@ -2086,10 +2086,10 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
self.historyNode.prefetchManager.updateAutoDownloadSettings(settings)
|
||||
}
|
||||
|
||||
func updateStickerSettings(_ settings: ChatInterfaceStickerSettings) {
|
||||
func updateStickerSettings(_ settings: ChatInterfaceStickerSettings, forceStopAnimations: Bool) {
|
||||
self.historyNode.forEachItemNode { itemNode in
|
||||
if let itemNode = itemNode as? ChatMessageItemView {
|
||||
itemNode.updateStickerSettings()
|
||||
itemNode.updateStickerSettings(forceStopAnimations: forceStopAnimations)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -810,6 +810,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
})))
|
||||
}
|
||||
|
||||
var isUnremovableAction = false
|
||||
if messages.count == 1 {
|
||||
let message = messages[0]
|
||||
|
||||
@ -826,6 +827,14 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
|
||||
if !hasAutoremove {
|
||||
for media in message.media {
|
||||
if media is TelegramMediaAction {
|
||||
if let channel = message.peers[message.id.peerId] as? TelegramChannel {
|
||||
if channel.flags.contains(.isCreator) || (channel.adminRights?.rights.contains(.canDeleteMessages) == true) {
|
||||
} else {
|
||||
isUnremovableAction = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if let file = media as? TelegramMediaFile {
|
||||
if file.isVideo {
|
||||
if file.isAnimated {
|
||||
@ -937,7 +946,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
interfaceInteraction.deleteMessages(selectAll ? messages : [message], controller, f)
|
||||
}
|
||||
}), false))
|
||||
} else {
|
||||
} else if !isUnremovableAction {
|
||||
actions.append(.action(ContextMenuActionItem(text: title, textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: isSending ? "Chat/Context Menu/Clear" : "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor)
|
||||
}, action: { controller, f in
|
||||
|
@ -1242,6 +1242,9 @@ final class ChatMediaInputNode: ChatInputNode {
|
||||
let controller = PeekController(theme: PeekControllerTheme(presentationTheme: strongSelf.theme), content: content, sourceNode: {
|
||||
return sourceNode
|
||||
})
|
||||
controller.visibilityUpdated = { [weak self] visible in
|
||||
|
||||
}
|
||||
strongSelf.controllerInteraction.presentGlobalOverlayController(controller, nil)
|
||||
return controller
|
||||
}
|
||||
|
@ -178,6 +178,8 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
|
||||
private var highlightedState: Bool = false
|
||||
|
||||
private var forceStopAnimations = false
|
||||
|
||||
private var haptic: EmojiHaptic?
|
||||
private var mediaPlayer: MediaPlayer?
|
||||
private let mediaStatusDisposable = MetaDisposable()
|
||||
@ -489,7 +491,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
}
|
||||
|
||||
if let animationNode = self.animationNode as? AnimatedStickerNode {
|
||||
let isPlaying = self.visibilityStatus
|
||||
let isPlaying = self.visibilityStatus && !self.forceStopAnimations
|
||||
if self.isPlaying != isPlaying {
|
||||
self.isPlaying = isPlaying
|
||||
|
||||
@ -550,7 +552,8 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
}
|
||||
}
|
||||
|
||||
override func updateStickerSettings() {
|
||||
override func updateStickerSettings(forceStopAnimations: Bool) {
|
||||
self.forceStopAnimations = forceStopAnimations
|
||||
self.updateVisibility()
|
||||
}
|
||||
|
||||
|
@ -758,7 +758,7 @@ public class ChatMessageItemView: ListViewItemNode {
|
||||
func updateAutomaticMediaDownloadSettings() {
|
||||
}
|
||||
|
||||
func updateStickerSettings() {
|
||||
func updateStickerSettings(forceStopAnimations: Bool) {
|
||||
}
|
||||
|
||||
func playMediaWithSound() -> ((Double?) -> Void, Bool, Bool, Bool, ASDisplayNode?)? {
|
||||
@ -814,7 +814,7 @@ public class ChatMessageItemView: ListViewItemNode {
|
||||
case .payment:
|
||||
item.controllerInteraction.openCheckoutOrReceipt(item.message.id)
|
||||
case let .urlAuth(url, buttonId):
|
||||
item.controllerInteraction.requestMessageActionUrlAuth(url, item.message.id, buttonId)
|
||||
item.controllerInteraction.requestMessageActionUrlAuth(url, .message(id: item.message.id, buttonId: buttonId))
|
||||
case .setupPoll:
|
||||
break
|
||||
}
|
||||
|
@ -261,7 +261,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
self?.openMessageContextMenu(message: message, selectAll: selectAll, node: node, frame: frame)
|
||||
}, openMessageContextActions: { _, _, _, _ in
|
||||
}, navigateToMessage: { _, _ in }, navigateToMessageStandalone: { _ in
|
||||
}, tapMessage: nil, clickThroughMessage: { }, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _, _ in return false }, sendGif: { _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _ in return false }, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _, _ in }, activateSwitchInline: { _, _ in }, openUrl: { [weak self] url, _, _, _ in
|
||||
}, tapMessage: nil, clickThroughMessage: { }, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _, _ in return false }, sendGif: { _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _ in return false }, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _ in }, activateSwitchInline: { _, _ in }, openUrl: { [weak self] url, _, _, _ in
|
||||
self?.openUrl(url)
|
||||
}, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { [weak self] message, associatedData in
|
||||
if let strongSelf = self, let navigationController = strongSelf.getNavigationController() {
|
||||
@ -852,6 +852,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
self?.view.endEditing(true)
|
||||
})
|
||||
}
|
||||
case .urlAuth:
|
||||
break
|
||||
case let .peer(peerId, _):
|
||||
if let peerId = peerId {
|
||||
strongSelf.openPeer(peerId: peerId, peer: nil)
|
||||
@ -890,6 +892,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
}
|
||||
}, sendFile: nil,
|
||||
sendSticker: nil,
|
||||
requestMessageActionUrlAuth: nil,
|
||||
present: { c, a in
|
||||
self?.presentController(c, a)
|
||||
}, dismissInput: {
|
||||
|
@ -110,7 +110,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
|
||||
|
||||
self.controllerInteraction = ChatControllerInteraction(openMessage: { _, _ in
|
||||
return false }, openPeer: { _, _, _ in }, openPeerMention: { _ in }, openMessageContextMenu: { _, _, _, _, _ in }, openMessageContextActions: { _, _, _, _ in }, navigateToMessage: { _, _ in }, navigateToMessageStandalone: { _ in
|
||||
}, tapMessage: nil, clickThroughMessage: { }, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { fileReference, _, _, node, rect in return selectStickerImpl?(fileReference, node, rect) ?? false }, sendGif: { _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _ in return false }, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _, _ in }, activateSwitchInline: { _, _ in }, openUrl: { _, _, _, _ in }, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { _, _ in }, openWallpaper: { _ in }, openTheme: { _ in }, openHashtag: { _, _ in }, updateInputState: { _ in }, updateInputMode: { _ in }, openMessageShareMenu: { _ in
|
||||
}, tapMessage: nil, clickThroughMessage: { }, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { fileReference, _, _, node, rect in return selectStickerImpl?(fileReference, node, rect) ?? false }, sendGif: { _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _ in return false }, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _ in }, activateSwitchInline: { _, _ in }, openUrl: { _, _, _, _ in }, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { _, _ in }, openWallpaper: { _ in }, openTheme: { _ in }, openHashtag: { _, _ in }, updateInputState: { _ in }, updateInputMode: { _ in }, openMessageShareMenu: { _ in
|
||||
}, presentController: { _, _ in }, navigationController: {
|
||||
return nil
|
||||
}, chatControllerNode: {
|
||||
|
@ -38,11 +38,15 @@ private func defaultNavigationForPeerId(_ peerId: PeerId?, navigation: ChatContr
|
||||
}
|
||||
}
|
||||
|
||||
func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, openPeer: @escaping (PeerId, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?) {
|
||||
func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, openPeer: @escaping (PeerId, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)? = nil, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?) {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
switch resolvedUrl {
|
||||
case let .externalUrl(url):
|
||||
context.sharedContext.openExternalUrl(context: context, urlContext: urlContext, url: url, forceExternal: false, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: navigationController, dismissInput: dismissInput)
|
||||
case let .urlAuth(url):
|
||||
requestMessageActionUrlAuth?(.url(url))
|
||||
dismissInput()
|
||||
break
|
||||
case let .peer(peerId, navigation):
|
||||
if let peerId = peerId {
|
||||
openPeer(peerId, defaultNavigationForPeerId(peerId, navigation: navigation))
|
||||
|
@ -213,6 +213,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
||||
}
|
||||
}, sendFile: nil,
|
||||
sendSticker: nil,
|
||||
requestMessageActionUrlAuth: nil,
|
||||
present: { c, a in
|
||||
context.sharedContext.applicationBindings.dismissNativeController()
|
||||
|
||||
|
@ -84,7 +84,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
|
||||
}, sendBotContextResultAsGif: { _, _, _, _ in
|
||||
return false
|
||||
}, requestMessageActionCallback: { _, _, _, _ in
|
||||
}, requestMessageActionUrlAuth: { _, _, _ in
|
||||
}, requestMessageActionUrlAuth: { _, _ in
|
||||
}, activateSwitchInline: { _, _ in
|
||||
}, openUrl: { _, _, _, _ in
|
||||
}, shareCurrentLocation: {
|
||||
|
@ -1255,8 +1255,10 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
|
||||
final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
||||
let context: AccountContext
|
||||
let avatarNode: AvatarNode
|
||||
|
||||
private let containerNode: ContextControllerSourceNode
|
||||
|
||||
let avatarNode: AvatarNode
|
||||
fileprivate var videoNode: UniversalVideoNode?
|
||||
private var videoContent: NativeVideoContent?
|
||||
private var videoStartTimestamp: Double?
|
||||
@ -1271,6 +1273,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
var tapped: (() -> Void)?
|
||||
var contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?
|
||||
|
||||
private var isFirstAvatarLoading = true
|
||||
var item: PeerInfoAvatarListItem?
|
||||
@ -1279,15 +1282,29 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
||||
|
||||
init(context: AccountContext) {
|
||||
self.context = context
|
||||
self.containerNode = ContextControllerSourceNode()
|
||||
|
||||
let avatarFont = avatarPlaceholderFont(size: floor(100.0 * 16.0 / 37.0))
|
||||
self.avatarNode = AvatarNode(font: avatarFont)
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.avatarNode)
|
||||
self.avatarNode.frame = CGRect(origin: CGPoint(x: -50.0, y: -50.0), size: CGSize(width: 100.0, height: 100.0))
|
||||
self.addSubnode(self.containerNode)
|
||||
self.containerNode.addSubnode(self.avatarNode)
|
||||
self.containerNode.frame = CGRect(origin: CGPoint(x: -50.0, y: -50.0), size: CGSize(width: 100.0, height: 100.0))
|
||||
self.avatarNode.frame = self.containerNode.bounds
|
||||
|
||||
self.avatarNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
|
||||
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))
|
||||
self.avatarNode.view.addGestureRecognizer(tapGestureRecognizer)
|
||||
|
||||
self.containerNode.activated = { [weak self] gesture, _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
tapGestureRecognizer.isEnabled = false
|
||||
tapGestureRecognizer.isEnabled = true
|
||||
strongSelf.contextAction?(strongSelf.containerNode, gesture)
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
@ -1337,7 +1354,8 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
||||
self.avatarNode.setPeer(context: self.context, theme: theme, peer: peer, overrideImage: overrideImage, synchronousLoad: self.isFirstAvatarLoading, displayDimensions: CGSize(width: avatarSize, height: avatarSize), storeUnrounded: true)
|
||||
self.isFirstAvatarLoading = false
|
||||
|
||||
self.avatarNode.frame = CGRect(origin: CGPoint(x: -avatarSize / 2.0, y: -avatarSize / 2.0), size: CGSize(width: avatarSize, height: avatarSize))
|
||||
self.containerNode.frame = CGRect(origin: CGPoint(x: -avatarSize / 2.0, y: -avatarSize / 2.0), size: CGSize(width: avatarSize, height: avatarSize))
|
||||
self.avatarNode.frame = self.containerNode.bounds
|
||||
self.avatarNode.font = avatarPlaceholderFont(size: floor(avatarSize * 16.0 / 37.0))
|
||||
|
||||
if let item = item {
|
||||
@ -1365,6 +1383,8 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
self.containerNode.isGestureEnabled = true
|
||||
|
||||
if let video = videoRepresentations.last, let peerReference = PeerReference(peer) {
|
||||
let videoFileReference = FileMediaReference.avatarList(peer: peerReference, media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.representation.resource, previewRepresentations: representations.map { $0.representation }, videoThumbnails: [], immediateThumbnailData: immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.representation.dimensions, flags: [])]))
|
||||
let videoContent = NativeVideoContent(id: .profileVideo(id, nil), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.representation.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, startTimestamp: video.representation.startTimestamp, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear)
|
||||
@ -1411,7 +1431,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
||||
shape.path = maskPath.cgPath
|
||||
videoNode.layer.mask = shape
|
||||
|
||||
self.addSubnode(videoNode)
|
||||
self.containerNode.addSubnode(videoNode)
|
||||
}
|
||||
} else if let videoNode = self.videoNode {
|
||||
self.videoContent = nil
|
||||
@ -1424,6 +1444,8 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
||||
self.videoNode = nil
|
||||
|
||||
videoNode.removeFromSupernode()
|
||||
|
||||
self.containerNode.isGestureEnabled = false
|
||||
}
|
||||
|
||||
if let videoNode = self.videoNode {
|
||||
@ -2568,6 +2590,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
var cancelUpload: (() -> Void)?
|
||||
var requestUpdateLayout: (() -> Void)?
|
||||
|
||||
var displayAvatarContextMenu: ((ASDisplayNode, ContextGesture?) -> Void)?
|
||||
var displayCopyContextMenu: ((ASDisplayNode, Bool, Bool) -> Void)?
|
||||
|
||||
var navigationTransition: PeerInfoHeaderNavigationTransition?
|
||||
@ -2663,6 +2686,10 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
self.avatarListNode.avatarContainerNode.tapped = { [weak self] in
|
||||
self?.initiateAvatarExpansion(gallery: false, first: false)
|
||||
}
|
||||
self.avatarListNode.avatarContainerNode.contextAction = { [weak self] node, gesture in
|
||||
self?.displayAvatarContextMenu?(node, gesture)
|
||||
}
|
||||
|
||||
self.editingContentNode.avatarNode.tapped = { [weak self] confirm in
|
||||
self?.initiateAvatarExpansion(gallery: true, first: true)
|
||||
}
|
||||
|
@ -1204,7 +1204,7 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
}))
|
||||
}
|
||||
|
||||
if (channel.flags.contains(.isCreator) && (channel.username?.isEmpty ?? true)) || (channel.adminRights?.rights.contains(.canInviteUsers) == true) {
|
||||
if (channel.flags.contains(.isCreator) && (channel.username?.isEmpty ?? true)) || (!channel.flags.contains(.isCreator) && channel.adminRights?.rights.contains(.canInviteUsers) == true) {
|
||||
let invitesText: String
|
||||
if let count = data.invitations?.count, count > 0 {
|
||||
invitesText = "\(count)"
|
||||
@ -1987,7 +1987,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
}, sendBotContextResultAsGif: { _, _, _, _ in
|
||||
return false
|
||||
}, requestMessageActionCallback: { _, _, _, _ in
|
||||
}, requestMessageActionUrlAuth: { _, _, _ in
|
||||
}, requestMessageActionUrlAuth: { _, _ in
|
||||
}, activateSwitchInline: { _, _ in
|
||||
}, openUrl: { [weak self] url, concealed, external, _ in
|
||||
guard let strongSelf = self else {
|
||||
@ -2726,6 +2726,29 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
}
|
||||
} else {
|
||||
screenData = peerInfoScreenData(context: context, peerId: peerId, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, isSettings: self.isSettings, ignoreGroupInCommon: ignoreGroupInCommon)
|
||||
|
||||
self.headerNode.displayAvatarContextMenu = { [weak self] node, gesture in
|
||||
guard let strongSelf = self, let peer = strongSelf.data?.peer else {
|
||||
return
|
||||
}
|
||||
|
||||
let items: [ContextMenuItem] = [
|
||||
.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.PeerInfo_ReportProfilePhoto, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Report"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { [weak self] c, f in
|
||||
if let strongSelf = self, let parent = strongSelf.controller {
|
||||
presentPeerReportOptions(context: context, parent: parent, contextController: c, subject: .profilePhoto(peer.id, 0), completion: { _, _ in })
|
||||
}
|
||||
}))
|
||||
]
|
||||
|
||||
let galleryController = AvatarGalleryController(context: strongSelf.context, peer: peer, remoteEntries: nil, replaceRootController: { controller, ready in
|
||||
}, synchronousLoad: true)
|
||||
galleryController.setHintWillBePresentedInPreviewingContext(true)
|
||||
|
||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: galleryController, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture)
|
||||
strongSelf.controller?.presentInGlobalOverlay(contextController)
|
||||
}
|
||||
}
|
||||
|
||||
self.headerNode.avatarListNode.listContainerNode.currentIndexUpdated = { [weak self] in
|
||||
@ -3024,10 +3047,10 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
}, sendFile: nil,
|
||||
sendSticker: { [weak self] f, sourceNode, sourceRect in
|
||||
return false
|
||||
}, present: { [weak self] c, a in
|
||||
}, requestMessageActionUrlAuth: nil, present: { [weak self] c, a in
|
||||
self?.controller?.present(c, in: .window(.root), with: a)
|
||||
}, dismissInput: { [weak self] in
|
||||
|
||||
self?.view.endEditing(true)
|
||||
}, contentContext: nil)
|
||||
}
|
||||
|
||||
@ -3044,8 +3067,9 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
strongSelf.context.sharedContext.openResolvedUrl(result, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.controller?.navigationController as? NavigationController, openPeer: { peerId, navigation in
|
||||
self?.openPeer(peerId: peerId, navigation: navigation)
|
||||
}, sendFile: nil,
|
||||
sendSticker: nil,
|
||||
present: { c, a in
|
||||
sendSticker: nil,
|
||||
requestMessageActionUrlAuth: nil,
|
||||
present: { c, a in
|
||||
self?.controller?.present(c, in: .window(.root), with: a)
|
||||
}, dismissInput: {
|
||||
self?.view.endEditing(true)
|
||||
@ -4091,6 +4115,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
context.sharedContext.openResolvedUrl(.groupBotStart(peerId: peerId, payload: ""), context: self.context, urlContext: .generic, navigationController: controller.navigationController as? NavigationController, openPeer: { id, navigation in
|
||||
}, sendFile: nil,
|
||||
sendSticker: nil,
|
||||
requestMessageActionUrlAuth: nil,
|
||||
present: { [weak controller] c, a in
|
||||
controller?.present(c, in: .window(.root), with: a)
|
||||
}, dismissInput: { [weak controller] in
|
||||
@ -4921,7 +4946,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
resolvedUrl = .instantView(webPage, customAnchor)
|
||||
}
|
||||
strongSelf.context.sharedContext.openResolvedUrl(resolvedUrl, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.controller?.navigationController as? NavigationController, openPeer: { peer, navigation in
|
||||
}, sendFile: nil, sendSticker: nil, present: { [weak self] controller, arguments in
|
||||
}, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, present: { [weak self] controller, arguments in
|
||||
self?.controller?.push(controller)
|
||||
}, dismissInput: {}, contentContext: nil)
|
||||
}
|
||||
|
@ -1142,8 +1142,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
return resolveUrlImpl(account: account, url: url)
|
||||
}
|
||||
|
||||
public func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, openPeer: @escaping (PeerId, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?) {
|
||||
openResolvedUrlImpl(resolvedUrl, context: context, urlContext: urlContext, navigationController: navigationController, openPeer: openPeer, sendFile: sendFile, sendSticker: sendSticker, present: present, dismissInput: dismissInput, contentContext: contentContext)
|
||||
public func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, openPeer: @escaping (PeerId, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?) {
|
||||
openResolvedUrlImpl(resolvedUrl, context: context, urlContext: urlContext, navigationController: navigationController, openPeer: openPeer, sendFile: sendFile, sendSticker: sendSticker, requestMessageActionUrlAuth: requestMessageActionUrlAuth, present: present, dismissInput: dismissInput, contentContext: contentContext)
|
||||
}
|
||||
|
||||
public func makeDeviceContactInfoController(context: AccountContext, subject: DeviceContactInfoSubject, completed: (() -> Void)?, cancelled: (() -> Void)?) -> ViewController {
|
||||
@ -1221,7 +1221,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
clickThroughMessage?()
|
||||
}, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _, _ in return false }, sendGif: { _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _ in
|
||||
return false
|
||||
}, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _, _ in }, activateSwitchInline: { _, _ in }, openUrl: { _, _, _, _ in }, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { _, _ in }, openWallpaper: { _ in }, openTheme: { _ in }, openHashtag: { _, _ in }, updateInputState: { _ in }, updateInputMode: { _ in }, openMessageShareMenu: { _ in
|
||||
}, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _ in }, activateSwitchInline: { _, _ in }, openUrl: { _, _, _, _ in }, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { _, _ in }, openWallpaper: { _ in }, openTheme: { _ in }, openHashtag: { _, _ in }, updateInputState: { _ in }, updateInputMode: { _ in }, openMessageShareMenu: { _ in
|
||||
}, presentController: { _, _ in }, navigationController: {
|
||||
return nil
|
||||
}, chatControllerNode: {
|
||||
|
@ -44,6 +44,7 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: PeerId?, navigate
|
||||
}
|
||||
}, sendFile: nil,
|
||||
sendSticker: nil,
|
||||
requestMessageActionUrlAuth: nil,
|
||||
present: presentImpl, dismissInput: {}, contentContext: nil)
|
||||
}
|
||||
|
||||
|
@ -494,20 +494,22 @@ public func parseWallpaperUrl(_ url: String) -> WallpaperUrlParameter? {
|
||||
|
||||
private struct UrlHandlingConfiguration {
|
||||
static var defaultValue: UrlHandlingConfiguration {
|
||||
return UrlHandlingConfiguration(token: nil, domains: [])
|
||||
return UrlHandlingConfiguration(token: nil, domains: [], urlAuthDomains: [])
|
||||
}
|
||||
|
||||
public let token: String?
|
||||
public let domains: [String]
|
||||
public let urlAuthDomains: [String]
|
||||
|
||||
fileprivate init(token: String?, domains: [String]) {
|
||||
fileprivate init(token: String?, domains: [String], urlAuthDomains: [String]) {
|
||||
self.token = token
|
||||
self.domains = domains
|
||||
self.urlAuthDomains = urlAuthDomains
|
||||
}
|
||||
|
||||
static func with(appConfiguration: AppConfiguration) -> UrlHandlingConfiguration {
|
||||
if let data = appConfiguration.data, let token = data["autologin_token"] as? String, let domains = data["autologin_domains"] as? [String] {
|
||||
return UrlHandlingConfiguration(token: token, domains: domains)
|
||||
if let data = appConfiguration.data, let token = data["autologin_token"] as? String, let domains = data["autologin_domains"] as? [String], let urlAuthDomains = data["url_auth_domains"] as? [String] {
|
||||
return UrlHandlingConfiguration(token: token, domains: domains, urlAuthDomains: urlAuthDomains)
|
||||
} else {
|
||||
return .defaultValue
|
||||
}
|
||||
@ -525,12 +527,16 @@ public func resolveUrlImpl(account: Account, url: String) -> Signal<ResolvedUrl,
|
||||
if !(url.hasPrefix("http") || url.hasPrefix("https")) {
|
||||
url = "http://\(url)"
|
||||
}
|
||||
if let urlValue = URL(string: url), let host = urlValue.host, urlHandlingConfiguration.domains.contains(host.lowercased()), var components = URLComponents(string: url) {
|
||||
components.scheme = "https"
|
||||
var queryItems = components.queryItems ?? []
|
||||
queryItems.append(URLQueryItem(name: "autologin_token", value: urlHandlingConfiguration.token))
|
||||
components.queryItems = queryItems
|
||||
url = components.url?.absoluteString ?? url
|
||||
if let urlValue = URL(string: url), let host = urlValue.host?.lowercased() {
|
||||
if urlHandlingConfiguration.domains.contains(host), var components = URLComponents(string: url) {
|
||||
components.scheme = "https"
|
||||
var queryItems = components.queryItems ?? []
|
||||
queryItems.append(URLQueryItem(name: "autologin_token", value: urlHandlingConfiguration.token))
|
||||
components.queryItems = queryItems
|
||||
url = components.url?.absoluteString ?? url
|
||||
} else if urlHandlingConfiguration.urlAuthDomains.contains(host) {
|
||||
return .single(.urlAuth(url))
|
||||
}
|
||||
}
|
||||
|
||||
for basePath in baseTelegramMePaths {
|
||||
|
Loading…
x
Reference in New Issue
Block a user