mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
Various fixes
This commit is contained in:
parent
0d1d0c265d
commit
ead45405b7
@ -12050,3 +12050,5 @@ Sorry for the inconvenience.";
|
||||
"MediaEditor.NewStickerPack.Title" = "New Sticker Set";
|
||||
"MediaEditor.NewStickerPack.Text" = "Choose a name for your sticker set.";
|
||||
|
||||
"Premium.Gift.ContactSelection.SendMessage" = "Send Message";
|
||||
"Premium.Gift.ContactSelection.OpenProfile" = "Open Profile";
|
||||
|
@ -637,6 +637,7 @@ public enum ContactListAction: Equatable {
|
||||
case generic
|
||||
case voiceCall
|
||||
case videoCall
|
||||
case more
|
||||
}
|
||||
|
||||
public enum ContactListPeer: Equatable {
|
||||
|
@ -102,8 +102,10 @@ public final class ContactMultiselectionControllerParams {
|
||||
public let alwaysEnabled: Bool
|
||||
public let limit: Int32?
|
||||
public let reachedLimit: ((Int32) -> Void)?
|
||||
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, mode: ContactMultiselectionControllerMode, options: [ContactListAdditionalOption], filters: [ContactListFilter] = [.excludeSelf], onlyWriteable: Bool = false, isGroupInvitation: Bool = false, isPeerEnabled: ((EnginePeer) -> Bool)? = nil, attemptDisabledItemSelection: ((EnginePeer, ChatListDisabledPeerReason) -> Void)? = nil, alwaysEnabled: Bool = false, limit: Int32? = nil, reachedLimit: ((Int32) -> Void)? = nil) {
|
||||
public let openProfile: ((EnginePeer) -> Void)?
|
||||
public let sendMessage: ((EnginePeer) -> Void)?
|
||||
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, mode: ContactMultiselectionControllerMode, options: [ContactListAdditionalOption], filters: [ContactListFilter] = [.excludeSelf], onlyWriteable: Bool = false, isGroupInvitation: Bool = false, isPeerEnabled: ((EnginePeer) -> Bool)? = nil, attemptDisabledItemSelection: ((EnginePeer, ChatListDisabledPeerReason) -> Void)? = nil, alwaysEnabled: Bool = false, limit: Int32? = nil, reachedLimit: ((Int32) -> Void)? = nil, openProfile: ((EnginePeer) -> Void)? = nil, sendMessage: ((EnginePeer) -> Void)? = nil) {
|
||||
self.context = context
|
||||
self.updatedPresentationData = updatedPresentationData
|
||||
self.mode = mode
|
||||
@ -116,6 +118,8 @@ public final class ContactMultiselectionControllerParams {
|
||||
self.alwaysEnabled = alwaysEnabled
|
||||
self.limit = limit
|
||||
self.reachedLimit = reachedLimit
|
||||
self.openProfile = openProfile
|
||||
self.sendMessage = sendMessage
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,7 @@ swift_library(
|
||||
"//submodules/TooltipUI",
|
||||
"//submodules/UndoUI",
|
||||
"//submodules/TelegramIntents",
|
||||
"//submodules/ContextUI",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -23,6 +23,7 @@ import AppBundle
|
||||
import ContextUI
|
||||
import PhoneNumberFormat
|
||||
import LocalizedPeerData
|
||||
import ContextUI
|
||||
|
||||
private let dropDownIcon = { () -> UIImage in
|
||||
UIGraphicsBeginImageContextWithOptions(CGSize(width: 12.0, height: 12.0), false, 0.0)
|
||||
@ -56,7 +57,7 @@ private final class ContactListNodeInteraction {
|
||||
fileprivate let activateSearch: () -> Void
|
||||
fileprivate let authorize: () -> Void
|
||||
fileprivate let suppressWarning: () -> Void
|
||||
fileprivate let openPeer: (ContactListPeer, ContactListAction) -> Void
|
||||
fileprivate let openPeer: (ContactListPeer, ContactListAction, ASDisplayNode?, ContextGesture?) -> Void
|
||||
fileprivate let openDisabledPeer: (EnginePeer, ChatListDisabledPeerReason) -> Void
|
||||
fileprivate let contextAction: ((EnginePeer, ASDisplayNode, ContextGesture?, CGPoint?, Bool) -> Void)?
|
||||
fileprivate let openStories: (EnginePeer, ASDisplayNode) -> Void
|
||||
@ -65,7 +66,7 @@ private final class ContactListNodeInteraction {
|
||||
|
||||
let itemHighlighting = ContactItemHighlighting()
|
||||
|
||||
init(activateSearch: @escaping () -> Void, authorize: @escaping () -> Void, suppressWarning: @escaping () -> Void, openPeer: @escaping (ContactListPeer, ContactListAction) -> Void, openDisabledPeer: @escaping (EnginePeer, ChatListDisabledPeerReason) -> Void, contextAction: ((EnginePeer, ASDisplayNode, ContextGesture?, CGPoint?, Bool) -> Void)?, openStories: @escaping (EnginePeer, ASDisplayNode) -> Void, deselectAll: @escaping () -> Void, toggleSelection: @escaping ([EnginePeer], Bool) -> Void) {
|
||||
init(activateSearch: @escaping () -> Void, authorize: @escaping () -> Void, suppressWarning: @escaping () -> Void, openPeer: @escaping (ContactListPeer, ContactListAction, ASDisplayNode?, ContextGesture?) -> Void, openDisabledPeer: @escaping (EnginePeer, ChatListDisabledPeerReason) -> Void, contextAction: ((EnginePeer, ASDisplayNode, ContextGesture?, CGPoint?, Bool) -> Void)?, openStories: @escaping (EnginePeer, ASDisplayNode) -> Void, deselectAll: @escaping () -> Void, toggleSelection: @escaping ([EnginePeer], Bool) -> Void) {
|
||||
self.activateSearch = activateSearch
|
||||
self.authorize = authorize
|
||||
self.suppressWarning = suppressWarning
|
||||
@ -96,7 +97,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
case permissionInfo(PresentationTheme, String, String, Bool)
|
||||
case permissionEnable(PresentationTheme, String)
|
||||
case option(Int, ContactListAdditionalOption, ListViewItemHeader?, PresentationTheme, PresentationStrings)
|
||||
case peer(Int, ContactListPeer, EnginePeer.Presence?, ListViewItemHeader?, ContactsPeerItemSelection, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder, Bool, Bool, StoryData?, Bool)
|
||||
case peer(Int, ContactListPeer, EnginePeer.Presence?, ListViewItemHeader?, ContactsPeerItemSelection, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder, Bool, Bool, Bool, StoryData?, Bool)
|
||||
|
||||
var stableId: ContactListNodeEntryId {
|
||||
switch self {
|
||||
@ -110,7 +111,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
return .permission(action: true)
|
||||
case let .option(index, _, _, _, _):
|
||||
return .option(index: index)
|
||||
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, storyData, _):
|
||||
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, _, storyData, _):
|
||||
switch peer {
|
||||
case let .peer(peer, _, _):
|
||||
return .peerId(peerId: peer.id.toInt64(), section: storyData != nil ? .stories : .contacts)
|
||||
@ -143,7 +144,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
})
|
||||
case let .option(_, option, header, _, _):
|
||||
return ContactListActionItem(presentationData: ItemListPresentationData(presentationData), title: option.title, icon: option.icon, clearHighlightAutomatically: option.clearHighlightAutomatically, header: header, action: option.action)
|
||||
case let .peer(_, peer, presence, header, selection, _, strings, dateTimeFormat, nameSortOrder, nameDisplayOrder, displayCallIcons, enabled, storyData, requiresPremiumForMessaging):
|
||||
case let .peer(_, peer, presence, header, selection, _, strings, dateTimeFormat, nameSortOrder, nameDisplayOrder, displayCallIcons, hasMoreButton, enabled, storyData, requiresPremiumForMessaging):
|
||||
var status: ContactsPeerItemStatus
|
||||
let itemPeer: ContactsPeerItemPeer
|
||||
var isContextActionEnabled = false
|
||||
@ -200,11 +201,15 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
}
|
||||
|
||||
var additionalActions: [ContactsPeerItemAction] = []
|
||||
if displayCallIcons {
|
||||
additionalActions = [ContactsPeerItemAction(icon: .voiceCall, action: { _ in
|
||||
interaction.openPeer(peer, .voiceCall)
|
||||
}), ContactsPeerItemAction(icon: .videoCall, action: { _ in
|
||||
interaction.openPeer(peer, .videoCall)
|
||||
if hasMoreButton {
|
||||
additionalActions = [ContactsPeerItemAction(icon: .more, action: { _, sourceNode, gesture in
|
||||
interaction.openPeer(peer, .more, sourceNode, gesture)
|
||||
})]
|
||||
} else if displayCallIcons {
|
||||
additionalActions = [ContactsPeerItemAction(icon: .voiceCall, action: { _, sourceNode, gesture in
|
||||
interaction.openPeer(peer, .voiceCall, sourceNode, gesture)
|
||||
}), ContactsPeerItemAction(icon: .videoCall, action: { _, sourceNode, gesture in
|
||||
interaction.openPeer(peer, .videoCall, sourceNode, gesture)
|
||||
})]
|
||||
}
|
||||
|
||||
@ -218,7 +223,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
}
|
||||
|
||||
return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: isSearch ? .generalSearch(isSavedMessages: false) : .peer, peer: itemPeer, status: status, requiresPremiumForMessaging: requiresPremiumForMessaging, enabled: enabled, selection: selection, selectionPosition: .left, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), additionalActions: additionalActions, index: nil, header: header, action: { _ in
|
||||
interaction.openPeer(peer, .generic)
|
||||
interaction.openPeer(peer, .generic, nil, nil)
|
||||
}, disabledAction: { _ in
|
||||
if case let .peer(peer, _, _) = peer {
|
||||
interaction.openDisabledPeer(EnginePeer(peer), requiresPremiumForMessaging ? .premiumRequired : .generic)
|
||||
@ -263,9 +268,9 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .peer(lhsIndex, lhsPeer, lhsPresence, lhsHeader, lhsSelection, lhsTheme, lhsStrings, lhsTimeFormat, lhsSortOrder, lhsDisplayOrder, lhsDisplayCallIcons, lhsEnabled, lhsStoryData, lhsRequiresPremiumForMessaging):
|
||||
case let .peer(lhsIndex, lhsPeer, lhsPresence, lhsHeader, lhsSelection, lhsTheme, lhsStrings, lhsTimeFormat, lhsSortOrder, lhsDisplayOrder, lhsDisplayCallIcons, lhsHasMoreButton, lhsEnabled, lhsStoryData, lhsRequiresPremiumForMessaging):
|
||||
switch rhs {
|
||||
case let .peer(rhsIndex, rhsPeer, rhsPresence, rhsHeader, rhsSelection, rhsTheme, rhsStrings, rhsTimeFormat, rhsSortOrder, rhsDisplayOrder, rhsDisplayCallIcons, rhsEnabled, rhsStoryData, rhsRequiresPremiumForMessaging):
|
||||
case let .peer(rhsIndex, rhsPeer, rhsPresence, rhsHeader, rhsSelection, rhsTheme, rhsStrings, rhsTimeFormat, rhsSortOrder, rhsDisplayOrder, rhsDisplayCallIcons, rhsHasMoreButton, rhsEnabled, rhsStoryData, rhsRequiresPremiumForMessaging):
|
||||
if lhsIndex != rhsIndex {
|
||||
return false
|
||||
}
|
||||
@ -303,6 +308,9 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
if lhsDisplayCallIcons != rhsDisplayCallIcons {
|
||||
return false
|
||||
}
|
||||
if lhsHasMoreButton != rhsHasMoreButton {
|
||||
return false
|
||||
}
|
||||
if lhsEnabled != rhsEnabled {
|
||||
return false
|
||||
}
|
||||
@ -353,11 +361,11 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
case .peer:
|
||||
return true
|
||||
}
|
||||
case let .peer(lhsIndex, _, _, _, _, _, _, _, _, _, _, _, lhsStoryData, _):
|
||||
case let .peer(lhsIndex, _, _, _, _, _, _, _, _, _, _, _, _, lhsStoryData, _):
|
||||
switch rhs {
|
||||
case .search, .sort, .permissionInfo, .permissionEnable, .option:
|
||||
return false
|
||||
case let .peer(rhsIndex, _, _, _, _, _, _, _, _, _, _, _, rhsStoryData, _):
|
||||
case let .peer(rhsIndex, _, _, _, _, _, _, _, _, _, _, _, _, rhsStoryData, _):
|
||||
if (lhsStoryData == nil) != (rhsStoryData == nil) {
|
||||
if lhsStoryData != nil {
|
||||
return true
|
||||
@ -551,7 +559,7 @@ private func contactListNodeEntries(accountPeer: EnginePeer?, peers: [ContactLis
|
||||
}
|
||||
|
||||
let presence = presences[peer.id]
|
||||
entries.append(.peer(index, .peer(peer: peer._asPeer(), isGlobal: false, participantCount: nil), presence, header, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, false, true, nil, false))
|
||||
entries.append(.peer(index, .peer(peer: peer._asPeer(), isGlobal: false, participantCount: nil), presence, header, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, false, false, true, nil, false))
|
||||
|
||||
index += 1
|
||||
}
|
||||
@ -608,7 +616,7 @@ private func contactListNodeEntries(accountPeer: EnginePeer?, peers: [ContactLis
|
||||
}
|
||||
|
||||
let presence = presences[peer.id]
|
||||
entries.append(.peer(index, .peer(peer: peer._asPeer(), isGlobal: false, participantCount: nil), presence, header, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, false, true, nil, false))
|
||||
entries.append(.peer(index, .peer(peer: peer._asPeer(), isGlobal: false, participantCount: nil), presence, header, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, false, true, true, nil, false))
|
||||
|
||||
index += 1
|
||||
}
|
||||
@ -657,7 +665,7 @@ private func contactListNodeEntries(accountPeer: EnginePeer?, peers: [ContactLis
|
||||
}
|
||||
|
||||
let presence = presences[peer.id]
|
||||
entries.append(.peer(index, .peer(peer: peer._asPeer(), isGlobal: false, participantCount: nil), presence, header, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, false, true, nil, false))
|
||||
entries.append(.peer(index, .peer(peer: peer._asPeer(), isGlobal: false, participantCount: nil), presence, header, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, false, false, true, nil, false))
|
||||
|
||||
index += 1
|
||||
}
|
||||
@ -701,7 +709,7 @@ private func contactListNodeEntries(accountPeer: EnginePeer?, peers: [ContactLis
|
||||
enabled = true
|
||||
}
|
||||
|
||||
entries.append(.peer(index, peer, presence, nil, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, displayCallIcons, enabled, nil, false))
|
||||
entries.append(.peer(index, peer, presence, nil, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, displayCallIcons, false, enabled, nil, false))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
@ -748,7 +756,7 @@ private func contactListNodeEntries(accountPeer: EnginePeer?, peers: [ContactLis
|
||||
}
|
||||
|
||||
|
||||
entries.append(.peer(index, peer, presence, header, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, displayCallIcons, enabled, nil, requiresPremiumForMessaging))
|
||||
entries.append(.peer(index, peer, presence, header, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, displayCallIcons, false, enabled, nil, requiresPremiumForMessaging))
|
||||
index += 1
|
||||
}
|
||||
return entries
|
||||
@ -772,7 +780,7 @@ private func preparedContactListNodeTransition(context: AccountContext, presenta
|
||||
case .search:
|
||||
//indexSections.apend(CollectionIndexNode.searchIndex)
|
||||
break
|
||||
case let .peer(_, _, _, header, _, _, _, _, _, _, _, _, _, _):
|
||||
case let .peer(_, _, _, header, _, _, _, _, _, _, _, _, _, _, _):
|
||||
if let header = header as? ContactListNameIndexHeader {
|
||||
if !existingSections.contains(header.letter) {
|
||||
existingSections.insert(header.letter)
|
||||
@ -1036,7 +1044,7 @@ public final class ContactListNode: ASDisplayNode {
|
||||
public var contentScrollingEnded: ((ListView) -> Bool)?
|
||||
|
||||
public var activateSearch: (() -> Void)?
|
||||
public var openPeer: ((ContactListPeer, ContactListAction) -> Void)?
|
||||
public var openPeer: ((ContactListPeer, ContactListAction, ASDisplayNode?, ContextGesture?) -> Void)?
|
||||
public var openDisabledPeer: ((EnginePeer, ChatListDisabledPeerReason) -> Void)?
|
||||
public var deselectedAll: (() -> Void)?
|
||||
public var updatedSelection: (([EnginePeer], Bool) -> Void)?
|
||||
@ -1136,7 +1144,7 @@ public final class ContactListNode: ASDisplayNode {
|
||||
authorizeImpl?()
|
||||
}, suppressWarning: { [weak self] in
|
||||
self?.suppressPermissionWarning?()
|
||||
}, openPeer: { [weak self] peer, action in
|
||||
}, openPeer: { [weak self] peer, action, sourceNode, gesture in
|
||||
if let strongSelf = self {
|
||||
if strongSelf.multipleSelection {
|
||||
var updated = false
|
||||
@ -1151,10 +1159,10 @@ public final class ContactListNode: ASDisplayNode {
|
||||
}
|
||||
})
|
||||
if !updated {
|
||||
strongSelf.openPeer?(peer, action)
|
||||
strongSelf.openPeer?(peer, action, sourceNode, gesture)
|
||||
}
|
||||
} else {
|
||||
strongSelf.openPeer?(peer, action)
|
||||
strongSelf.openPeer?(peer, action, sourceNode, gesture)
|
||||
}
|
||||
}
|
||||
}, openDisabledPeer: { [weak self] peer, reason in
|
||||
@ -1224,7 +1232,7 @@ public final class ContactListNode: ASDisplayNode {
|
||||
strongSelf.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.PreferSynchronousDrawing, .PreferSynchronousResourceLoading], scrollToItem: ListViewScrollToItem(index: index, position: .top(-navigationBarSearchContentHeight), animated: false, curve: .Default(duration: nil), directionHint: .Down), additionalScrollDistance: 0.0, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
break loop
|
||||
}
|
||||
case let .peer(_, _, _, header, _, _, _, _, _, _, _, _, _, _):
|
||||
case let .peer(_, _, _, header, _, _, _, _, _, _, _, _, _, _, _):
|
||||
if let header = header as? ContactListNameIndexHeader {
|
||||
if let scalar = UnicodeScalar(header.letter) {
|
||||
let title = "\(Character(scalar))"
|
||||
|
@ -345,7 +345,7 @@ public class ContactsController: ViewController {
|
||||
self?.activateSearch()
|
||||
}
|
||||
|
||||
self.contactsNode.contactListNode.openPeer = { [weak self] peer, _ in
|
||||
self.contactsNode.contactListNode.openPeer = { [weak self] peer, _, _, _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/MultiAnimationRenderer",
|
||||
"//submodules/TelegramUI/Components/EmojiStatusComponent",
|
||||
"//submodules/TelegramUI/Components/Stories/AvatarStoryIndicatorComponent",
|
||||
"//submodules/MoreButtonNode",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -20,6 +20,7 @@ import ComponentFlow
|
||||
import AnimationCache
|
||||
import MultiAnimationRenderer
|
||||
import EmojiStatusComponent
|
||||
import MoreButtonNode
|
||||
|
||||
public final class ContactItemHighlighting {
|
||||
public var chatLocation: ChatLocation?
|
||||
@ -88,13 +89,14 @@ public enum ContactsPeerItemActionIcon {
|
||||
case add
|
||||
case voiceCall
|
||||
case videoCall
|
||||
case more
|
||||
}
|
||||
|
||||
public struct ContactsPeerItemAction {
|
||||
public let icon: ContactsPeerItemActionIcon
|
||||
public let action: ((ContactsPeerItemPeer) -> Void)?
|
||||
public let action: ((ContactsPeerItemPeer, ASDisplayNode, ContextGesture?) -> Void)?
|
||||
|
||||
public init(icon: ContactsPeerItemActionIcon, action: @escaping (ContactsPeerItemPeer) -> Void) {
|
||||
public init(icon: ContactsPeerItemActionIcon, action: @escaping (ContactsPeerItemPeer, ASDisplayNode, ContextGesture?) -> Void) {
|
||||
self.icon = icon
|
||||
self.action = action
|
||||
}
|
||||
@ -417,6 +419,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
private var badgeTextNode: TextNode?
|
||||
private var selectionNode: CheckNode?
|
||||
private var actionButtonNodes: [HighlightableButtonNode]?
|
||||
private var moreButtonNode: MoreButtonNode?
|
||||
private var arrowButtonNode: HighlightableButtonNode?
|
||||
|
||||
private var avatarTapRecognizer: UITapGestureRecognizer?
|
||||
@ -744,10 +747,11 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
var actionButtons: [ActionButton]?
|
||||
struct ActionButton {
|
||||
let type: ContactsPeerItemActionIcon
|
||||
let image: UIImage?
|
||||
let action: ((ContactsPeerItemPeer) -> Void)?
|
||||
let action: ((ContactsPeerItemPeer, ASDisplayNode, ContextGesture?) -> Void)?
|
||||
|
||||
init(theme: PresentationTheme, icon: ContactsPeerItemActionIcon, action: ((ContactsPeerItemPeer) -> Void)?) {
|
||||
init(theme: PresentationTheme, icon: ContactsPeerItemActionIcon, action: ((ContactsPeerItemPeer, ASDisplayNode, ContextGesture?) -> Void)?) {
|
||||
let image: UIImage?
|
||||
switch icon {
|
||||
case .none:
|
||||
@ -758,7 +762,10 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
image = PresentationResourcesItemList.voiceCallIcon(theme)
|
||||
case .videoCall:
|
||||
image = PresentationResourcesItemList.videoCallIcon(theme)
|
||||
case .more:
|
||||
image = PresentationResourcesItemList.videoCallIcon(theme)
|
||||
}
|
||||
self.type = icon
|
||||
self.image = image
|
||||
self.action = action
|
||||
}
|
||||
@ -1357,7 +1364,23 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
verifiedIconView.removeFromSuperview()
|
||||
}
|
||||
|
||||
if let actionButtons = actionButtons {
|
||||
if let actionButtons, actionButtons.count == 1, let actionButton = actionButtons.first, case .more = actionButton.type {
|
||||
let moreButtonNode: MoreButtonNode
|
||||
if let current = strongSelf.moreButtonNode {
|
||||
moreButtonNode = current
|
||||
} else {
|
||||
moreButtonNode = MoreButtonNode(theme: item.presentationData.theme)
|
||||
moreButtonNode.iconNode.enqueueState(.more, animated: false)
|
||||
moreButtonNode.hitTestSlop = UIEdgeInsets(top: -8.0, left: -8.0, bottom: -8.0, right: -8.0)
|
||||
strongSelf.offsetContainerNode.addSubnode(moreButtonNode)
|
||||
strongSelf.moreButtonNode = moreButtonNode
|
||||
}
|
||||
moreButtonNode.action = { sourceNode, gesture in
|
||||
actionButton.action?(item.peer, sourceNode, gesture)
|
||||
}
|
||||
let moreButtonSize = moreButtonNode.measure(CGSize(width: 100.0, height: nodeLayout.contentSize.height))
|
||||
moreButtonNode.frame = CGRect(origin: CGPoint(x: revealOffset + params.width - params.rightInset - 18.0 - moreButtonSize.width, y:floor((nodeLayout.contentSize.height - moreButtonSize.height) / 2.0)), size: moreButtonSize)
|
||||
} else if let actionButtons = actionButtons {
|
||||
if strongSelf.actionButtonNodes == nil {
|
||||
var actionButtonNodes: [HighlightableButtonNode] = []
|
||||
for action in actionButtons {
|
||||
@ -1524,7 +1547,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
guard let actionButtonNodes = self.actionButtonNodes, let index = actionButtonNodes.firstIndex(of: sender), let item = self.item, index < item.additionalActions.count else {
|
||||
return
|
||||
}
|
||||
item.additionalActions[index].action?(item.peer)
|
||||
item.additionalActions[index].action?(item.peer, sender, nil)
|
||||
}
|
||||
|
||||
override public func updateRevealOffset(offset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
|
@ -1599,7 +1599,9 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
videoNode.setBaseRate(self.playbackRate ?? 1.0)
|
||||
}
|
||||
} else {
|
||||
if self.shouldAutoplayOnCentrality() {
|
||||
if isAnimated {
|
||||
self.playOnContentOwnership = true
|
||||
} else if self.shouldAutoplayOnCentrality() {
|
||||
self.playOnContentOwnership = true
|
||||
}
|
||||
}
|
||||
|
@ -1592,11 +1592,14 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
if case let .noAccess(cameraAccess) = self.state {
|
||||
var hasCamera = cameraAccess == .authorized
|
||||
var story = false
|
||||
if let subject = self.controller?.subject, case .assets(_, .story) = subject {
|
||||
hasCamera = false
|
||||
story = true
|
||||
|
||||
self.controller?.navigationItem.rightBarButtonItem = nil
|
||||
if let subject = self.controller?.subject {
|
||||
if case .assets(_, .story) = subject {
|
||||
hasCamera = false
|
||||
story = true
|
||||
self.controller?.navigationItem.rightBarButtonItem = nil
|
||||
} else if case .assets(_, .createSticker) = subject {
|
||||
hasCamera = false
|
||||
}
|
||||
}
|
||||
|
||||
var placeholderTransition = transition
|
||||
|
@ -166,7 +166,7 @@ public final class ReplyAccessoryPanelNode: AccessoryPanelNode {
|
||||
}
|
||||
let textColor = strongSelf.theme.chat.inputPanel.primaryTextColor
|
||||
if entities.count > 0 {
|
||||
messageText = stringWithAppliedEntities(trimToLineCount(message.text, lineCount: 1), entities: entities, baseColor: textColor, linkColor: textColor, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: textFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, underlineLinks: false, message: message)
|
||||
messageText = stringWithAppliedEntities(trimToLineCount(message.text, lineCount: 1), entities: entities, baseColor: textColor, linkColor: textColor, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: textFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, underlineLinks: false, message: message)
|
||||
} else {
|
||||
messageText = NSAttributedString(string: text, font: textFont, textColor: isMedia ? strongSelf.theme.chat.inputPanel.secondaryTextColor : strongSelf.theme.chat.inputPanel.primaryTextColor)
|
||||
}
|
||||
|
@ -112,6 +112,10 @@ private final class MediaCutoutScreenComponent: Component {
|
||||
x: location.x / controller.drawingView.bounds.width,
|
||||
y: location.y / controller.drawingView.bounds.height
|
||||
)
|
||||
let validRange: Range<CGFloat> = 0.0 ..< 1.0
|
||||
guard validRange.contains(point.x) && validRange.contains(point.y) else {
|
||||
return
|
||||
}
|
||||
|
||||
component.mediaEditor.processImage { [weak self] originalImage, _ in
|
||||
cutoutImage(from: originalImage, values: nil, target: .point(point), includeExtracted: false, completion: { [weak self] results in
|
||||
|
@ -1177,8 +1177,10 @@ final class MediaEditorScreenComponent: Component {
|
||||
let authorName = forwardAuthor.displayTitle(strings: environment.strings, displayOrder: .firstLast)
|
||||
header = AnyComponent(
|
||||
ForwardInfoPanelComponent(
|
||||
context: component.context,
|
||||
authorName: authorName,
|
||||
text: forwardStory.text,
|
||||
entities: forwardStory.entities,
|
||||
isChannel: forwardAuthor.id.isGroupOrChannel,
|
||||
isVibrant: true,
|
||||
fillsWidth: true
|
||||
|
@ -228,20 +228,48 @@ func findEdgePoints(in pixelBuffer: CVPixelBuffer) -> [CGPoint] {
|
||||
return pixel >= 235
|
||||
}
|
||||
|
||||
let directions = [(1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1)]
|
||||
var lastDirectionIndex = 0
|
||||
|
||||
var startPoint: Point? = nil
|
||||
outerLoop: for y in 0..<height {
|
||||
var visited = Set<Point>()
|
||||
var componentSize = 0
|
||||
|
||||
func floodFill(from point: Point) -> Int {
|
||||
var stack = [point]
|
||||
var size = 0
|
||||
|
||||
while let current = stack.popLast() {
|
||||
let x = Int(current.x)
|
||||
let y = Int(current.y)
|
||||
|
||||
if x < 0 || x >= width || y < 0 || y >= height || visited.contains(current) || !isPixelWhiteAt(x: x, y: y) {
|
||||
continue
|
||||
}
|
||||
|
||||
visited.insert(current)
|
||||
size += 1
|
||||
stack.append(contentsOf: [Point(x: x+1, y: y), Point(x: x-1, y: y), Point(x: x, y: y+1), Point(x: x, y: y-1)])
|
||||
}
|
||||
|
||||
return size
|
||||
}
|
||||
|
||||
for y in 0..<height {
|
||||
for x in 0..<width {
|
||||
if isPixelWhiteAt(x: x, y: y) {
|
||||
startPoint = Point(x: x, y: y)
|
||||
break outerLoop
|
||||
let point = Point(x: x, y: y)
|
||||
if isPixelWhiteAt(x: x, y: y) && !visited.contains(point) {
|
||||
let size = floodFill(from: point)
|
||||
if size > componentSize {
|
||||
componentSize = size
|
||||
startPoint = point
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
guard let startingPoint = startPoint else { return [] }
|
||||
let directions = [(1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1)]
|
||||
var lastDirectionIndex = 0
|
||||
|
||||
guard let startingPoint = startPoint, componentSize > 60 else { return [] }
|
||||
|
||||
edgePoints.insert(startingPoint)
|
||||
edgePath.append(startingPoint)
|
||||
var currentPoint = startingPoint
|
||||
@ -326,7 +354,7 @@ private func getEdgesBitmap(_ ciImage: CIImage) -> CVPixelBuffer? {
|
||||
context.fill(CGRect(origin: .zero, size: size))
|
||||
image.draw(in: CGRect(origin: .zero, size: size))
|
||||
UIGraphicsPopContext()
|
||||
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
||||
|
@ -1365,7 +1365,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
||||
contactListNode.activateSearch = { [weak self] in
|
||||
self?.requestActivateSearch?()
|
||||
}
|
||||
contactListNode.openPeer = { [weak self] peer, _ in
|
||||
contactListNode.openPeer = { [weak self] peer, _, _, _ in
|
||||
if case let .peer(peer, _, _) = peer {
|
||||
self?.contactListNode?.listNode.clearHighlightAnimated(true)
|
||||
self?.requestOpenPeer?(EnginePeer(peer), nil)
|
||||
|
@ -12,9 +12,13 @@ swift_library(
|
||||
deps = [
|
||||
"//submodules/Display",
|
||||
"//submodules/ComponentFlow",
|
||||
"//submodules/TelegramCore",
|
||||
"//submodules/TelegramPresentationData",
|
||||
"//submodules/Components/MultilineTextComponent",
|
||||
"//submodules/Components/MultilineTextWithEntitiesComponent",
|
||||
"//submodules/TelegramUI/Components/Chat/MessageInlineBlockBackgroundView",
|
||||
"//submodules/AccountContext",
|
||||
"//submodules/TextFormat",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -2,25 +2,35 @@ import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import ComponentFlow
|
||||
import TelegramCore
|
||||
import MultilineTextComponent
|
||||
import MultilineTextWithEntitiesComponent
|
||||
import MessageInlineBlockBackgroundView
|
||||
import AccountContext
|
||||
import TextFormat
|
||||
|
||||
public final class ForwardInfoPanelComponent: Component {
|
||||
public let context: AccountContext
|
||||
public let authorName: String
|
||||
public let text: String
|
||||
public let entities: [MessageTextEntity]
|
||||
public let isChannel: Bool
|
||||
public let isVibrant: Bool
|
||||
public let fillsWidth: Bool
|
||||
|
||||
public init(
|
||||
context: AccountContext,
|
||||
authorName: String,
|
||||
text: String,
|
||||
entities: [MessageTextEntity],
|
||||
isChannel: Bool,
|
||||
isVibrant: Bool,
|
||||
fillsWidth: Bool
|
||||
) {
|
||||
self.context = context
|
||||
self.authorName = authorName
|
||||
self.text = text
|
||||
self.entities = entities
|
||||
self.isChannel = isChannel
|
||||
self.isVibrant = isVibrant
|
||||
self.fillsWidth = fillsWidth
|
||||
@ -33,6 +43,9 @@ public final class ForwardInfoPanelComponent: Component {
|
||||
if lhs.text != rhs.text {
|
||||
return false
|
||||
}
|
||||
if lhs.entities != rhs.entities {
|
||||
return false
|
||||
}
|
||||
if lhs.isChannel != rhs.isChannel {
|
||||
return false
|
||||
}
|
||||
@ -47,7 +60,6 @@ public final class ForwardInfoPanelComponent: Component {
|
||||
|
||||
public final class View: UIView {
|
||||
public let backgroundView: UIImageView
|
||||
// private let blurBackgroundView: BlurredBackgroundView
|
||||
private let blurBackgroundView: UIVisualEffectView
|
||||
private let blockView: MessageInlineBlockBackgroundView
|
||||
private var iconView: UIImageView?
|
||||
@ -58,8 +70,6 @@ public final class ForwardInfoPanelComponent: Component {
|
||||
private weak var state: EmptyComponentState?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
// self.blurBackgroundView = BlurredBackgroundView(color: UIColor(rgb: 0x000000, alpha: 0.4))
|
||||
|
||||
if #available(iOS 13.0, *) {
|
||||
self.blurBackgroundView = UIVisualEffectView(effect: UIBlurEffect(style: .systemUltraThinMaterialDark))
|
||||
} else {
|
||||
@ -102,7 +112,7 @@ public final class ForwardInfoPanelComponent: Component {
|
||||
iconView.frame = CGRect(origin: CGPoint(x: sideInset + UIScreenPixel, y: 5.0), size: image.size)
|
||||
}
|
||||
titleOffset += 13.0
|
||||
|
||||
|
||||
let titleSize = self.title.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(MultilineTextComponent(
|
||||
@ -124,14 +134,20 @@ public final class ForwardInfoPanelComponent: Component {
|
||||
view.frame = titleFrame
|
||||
}
|
||||
|
||||
let textFont = Font.regular(14.0)
|
||||
let textColor = UIColor.white
|
||||
let attributedText = stringWithAppliedEntities(component.text, entities: component.entities, baseColor: textColor, linkColor: textColor, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: textFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, underlineLinks: false, message: nil)
|
||||
|
||||
let textSize = self.text.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: component.text,
|
||||
font: Font.regular(14.0),
|
||||
textColor: .white
|
||||
)),
|
||||
component: AnyComponent(MultilineTextWithEntitiesComponent(
|
||||
context: component.context,
|
||||
animationCache: component.context.animationCache,
|
||||
animationRenderer: component.context.animationRenderer,
|
||||
placeholderColor: UIColor(rgb: 0xffffff, alpha: 0.4),
|
||||
text: .plain(attributedText),
|
||||
horizontalAlignment: .natural,
|
||||
truncationType: .end,
|
||||
maximumNumberOfLines: 1
|
||||
)),
|
||||
environment: {},
|
||||
|
@ -698,6 +698,7 @@ final class StoryContentCaptionComponent: Component {
|
||||
let authorName: String
|
||||
let isChannel: Bool
|
||||
let text: String?
|
||||
let entities: [MessageTextEntity]
|
||||
|
||||
switch forwardInfo {
|
||||
case let .known(peer, _, _):
|
||||
@ -706,6 +707,7 @@ final class StoryContentCaptionComponent: Component {
|
||||
|
||||
if let story = self.forwardInfoStory {
|
||||
text = story.text
|
||||
entities = story.entities
|
||||
} else if self.forwardInfoDisposable == nil, let forwardInfoStory = component.forwardInfoStory {
|
||||
self.forwardInfoDisposable = (forwardInfoStory
|
||||
|> deliverOnMainQueue).start(next: { story in
|
||||
@ -717,13 +719,16 @@ final class StoryContentCaptionComponent: Component {
|
||||
}
|
||||
})
|
||||
text = ""
|
||||
entities = []
|
||||
} else {
|
||||
text = ""
|
||||
entities = []
|
||||
}
|
||||
case let .unknown(name, _):
|
||||
authorName = name
|
||||
isChannel = false
|
||||
text = ""
|
||||
entities = []
|
||||
}
|
||||
|
||||
if let text {
|
||||
@ -741,8 +746,10 @@ final class StoryContentCaptionComponent: Component {
|
||||
PlainButtonComponent(
|
||||
content: AnyComponent(
|
||||
ForwardInfoPanelComponent(
|
||||
context: component.context,
|
||||
authorName: authorName,
|
||||
text: text,
|
||||
entities: entities,
|
||||
isChannel: isChannel,
|
||||
isVibrant: false,
|
||||
fillsWidth: false
|
||||
|
@ -1164,6 +1164,8 @@ extension ChatControllerImpl {
|
||||
controller.openCamera = { [weak self] cameraView in
|
||||
if let cameraView = cameraView as? TGAttachmentCameraView {
|
||||
self?.openCamera(cameraView: cameraView)
|
||||
} else {
|
||||
self?.openCamera(cameraView: nil)
|
||||
}
|
||||
}
|
||||
controller.presentWebSearch = { [weak self, weak controller] mediaGroups, activateOnDisplay in
|
||||
|
@ -670,10 +670,8 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
if messages.count == 1 {
|
||||
for media in messages[0].media {
|
||||
if let file = media as? TelegramMediaFile {
|
||||
for attribute in file.attributes {
|
||||
if case let .Sticker(_, packInfo, _) = attribute, packInfo != nil {
|
||||
loadStickerSaveStatus = file.fileId
|
||||
}
|
||||
if file.isSticker {
|
||||
loadStickerSaveStatus = file.fileId
|
||||
}
|
||||
if loadStickerSaveStatus == nil {
|
||||
loadCopyMediaResource = file.resource
|
||||
|
@ -116,7 +116,7 @@ public class ComposeControllerImpl: ViewController, ComposeController {
|
||||
self?.activateSearch()
|
||||
}
|
||||
|
||||
self.contactsNode.contactListNode.openPeer = { [weak self] peer, _ in
|
||||
self.contactsNode.contactListNode.openPeer = { [weak self] peer, _, _, _ in
|
||||
if case let .peer(peer, _, _) = peer {
|
||||
self?.openPeer(peerId: peer.id)
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import CounterContollerTitleView
|
||||
import EditableTokenListNode
|
||||
import PremiumUI
|
||||
import UndoUI
|
||||
import ContextUI
|
||||
|
||||
private func peerTokenTitle(accountPeerId: PeerId, peer: Peer, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder) -> String {
|
||||
if peer.id == accountPeerId {
|
||||
@ -415,6 +416,38 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
|
||||
}
|
||||
}
|
||||
|
||||
self.contactsNode.openPeerMore = { [weak self] peer, node, gesture in
|
||||
guard let self, case let .peer(peer, _, _) = peer, let node = node as? ContextReferenceContentNode else {
|
||||
return
|
||||
}
|
||||
|
||||
let presentationData = self.presentationData
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.stings.Premium_Gift_ContactSelection_SendMessage, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MessageBubble"), color: theme.contextMenu.primaryColor)
|
||||
}, iconPosition: .left, action: { [weak self] _, a in
|
||||
a(.default)
|
||||
|
||||
if let self {
|
||||
self.params.sendMessage?(EnginePeer(peer))
|
||||
}
|
||||
})))
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.stings.Premium_Gift_ContactSelection_OpenProfile, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/User"), color: theme.contextMenu.primaryColor)
|
||||
}, iconPosition: .left, action: { [weak self] _, a in
|
||||
a(.default)
|
||||
|
||||
if let self {
|
||||
self.params.openProfile?(EnginePeer(peer))
|
||||
}
|
||||
})))
|
||||
|
||||
let contextController = ContextController(presentationData: presentationData, source: .reference(ContactContextReferenceContentSource(controller: self, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
self.present(contextController, in: .window(.root))
|
||||
}
|
||||
|
||||
self.contactsNode.openDisabledPeer = { [weak self] peer, reason in
|
||||
guard let self else {
|
||||
return
|
||||
@ -765,3 +798,17 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
|
||||
self._result.set(.single(.result(peerIds: peerIds, additionalOptionIds: additionalOptionIds)))
|
||||
}
|
||||
}
|
||||
|
||||
private final class ContactContextReferenceContentSource: ContextReferenceContentSource {
|
||||
private let controller: ViewController
|
||||
private let sourceNode: ContextReferenceContentNode
|
||||
|
||||
init(controller: ViewController, sourceNode: ContextReferenceContentNode) {
|
||||
self.controller = controller
|
||||
self.sourceNode = sourceNode
|
||||
}
|
||||
|
||||
func transitionInfo() -> ContextControllerReferenceViewInfo? {
|
||||
return ContextControllerReferenceViewInfo(referenceView: self.sourceNode.view, contentAreaInScreenSpace: UIScreen.main.bounds)
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import AnimationCache
|
||||
import MultiAnimationRenderer
|
||||
import EditableTokenListNode
|
||||
import SolidRoundedButtonNode
|
||||
import ContextUI
|
||||
|
||||
private struct SearchResultEntry: Identifiable {
|
||||
let index: Int
|
||||
@ -58,6 +59,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
||||
var requestDeactivateSearch: (() -> Void)?
|
||||
var requestOpenPeerFromSearch: ((ContactListPeerId) -> Void)?
|
||||
var openPeer: ((ContactListPeer) -> Void)?
|
||||
var openPeerMore: ((ContactListPeer, ASDisplayNode?, ContextGesture?) -> Void)?
|
||||
var openDisabledPeer: ((EnginePeer, ChatListDisabledPeerReason) -> Void)?
|
||||
var removeSelectedPeer: ((ContactListPeerId) -> Void)?
|
||||
var removeSelectedCategory: ((Int) -> Void)?
|
||||
@ -262,8 +264,12 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
||||
|
||||
switch self.contentNode {
|
||||
case let .contacts(contactsNode):
|
||||
contactsNode.openPeer = { [weak self] peer, _ in
|
||||
self?.openPeer?(peer)
|
||||
contactsNode.openPeer = { [weak self] peer, action, sourceNode, gesture in
|
||||
if case .more = action {
|
||||
self?.openPeerMore?(peer, sourceNode, gesture)
|
||||
} else {
|
||||
self?.openPeer?(peer)
|
||||
}
|
||||
}
|
||||
contactsNode.openDisabledPeer = { [weak self] peer, reason in
|
||||
guard let self else {
|
||||
@ -362,7 +368,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
||||
globalSearch: globalSearch,
|
||||
displaySavedMessages: displaySavedMessages
|
||||
))), filters: filters, onlyWriteable: strongSelf.onlyWriteable, isGroupInvitation: strongSelf.isGroupInvitation, isPeerEnabled: strongSelf.isPeerEnabled, selectionState: selectionState, isSearch: true)
|
||||
searchResultsNode.openPeer = { peer, _ in
|
||||
searchResultsNode.openPeer = { peer, _, _, _ in
|
||||
self?.tokenListNode.setText("")
|
||||
self?.openPeer?(peer)
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
||||
self?.activateSearch()
|
||||
}
|
||||
|
||||
self.contactsNode.contactListNode.openPeer = { [weak self] peer, action in
|
||||
self.contactsNode.contactListNode.openPeer = { [weak self] peer, action, _, _ in
|
||||
self?.openPeer(peer: peer, action: action)
|
||||
}
|
||||
|
||||
|
@ -2164,15 +2164,33 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
mode = .premiumGifting(birthdays: nil, selectToday: false)
|
||||
}
|
||||
|
||||
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: mode, options: [], isPeerEnabled: { peer in
|
||||
if case let .user(user) = peer, user.botInfo == nil && !peer.isService && !user.flags.contains(.isSupport) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}, limit: limit, reachedLimit: { limit in
|
||||
reachedLimitImpl?(limit)
|
||||
}))
|
||||
var openProfileImpl: ((EnginePeer) -> Void)?
|
||||
var sendMessageImpl: ((EnginePeer) -> Void)?
|
||||
|
||||
let controller = context.sharedContext.makeContactMultiselectionController(
|
||||
ContactMultiselectionControllerParams(
|
||||
context: context,
|
||||
mode: mode,
|
||||
options: [],
|
||||
isPeerEnabled: { peer in
|
||||
if case let .user(user) = peer, user.botInfo == nil && !peer.isService && !user.flags.contains(.isSupport) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
limit: limit,
|
||||
reachedLimit: { limit in
|
||||
reachedLimitImpl?(limit)
|
||||
},
|
||||
openProfile: { peer in
|
||||
openProfileImpl?(peer)
|
||||
},
|
||||
sendMessage: { peer in
|
||||
sendMessageImpl?(peer)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
reachedLimitImpl = { [weak controller] limit in
|
||||
guard let controller else {
|
||||
@ -2227,6 +2245,36 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
controller.push(giftController)
|
||||
})
|
||||
|
||||
sendMessageImpl = { [weak self, weak controller] peer in
|
||||
guard let self, let controller, let navigationController = controller.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
self.navigateToChatController(
|
||||
NavigateToChatControllerParams(
|
||||
navigationController: navigationController,
|
||||
context: context,
|
||||
chatLocation: .peer(peer)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
openProfileImpl = { [weak self, weak controller] peer in
|
||||
guard let self, let controller else {
|
||||
return
|
||||
}
|
||||
if let infoController = self.makePeerInfoController(
|
||||
context: context,
|
||||
updatedPresentationData: nil,
|
||||
peer: peer._asPeer(),
|
||||
mode: .generic,
|
||||
avatarInitiallyExpanded: true,
|
||||
fromChat: false,
|
||||
requestsContext: nil
|
||||
) {
|
||||
controller.replace(with: infoController)
|
||||
}
|
||||
}
|
||||
|
||||
return controller
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user