mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 11:23:48 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
6c73f79acf
@ -8089,10 +8089,26 @@ Sorry for the inconvenience.";
|
||||
"Group.Setup.LinkActive" = "active";
|
||||
"Group.Setup.LinkInactive" = "inactive";
|
||||
|
||||
"Group.Setup.ActivateAlertTitle" = "Activate Link";
|
||||
"Group.Setup.ActivateAlertText" = "Do you want to show this link on the group info page?";
|
||||
"Group.Setup.ActivateAlertShow" = "Show";
|
||||
|
||||
"Group.Setup.DeactivateAlertTitle" = "Deactivate Link";
|
||||
"Group.Setup.DeactivateAlertText" = "Do you want to hide this link from the group info page?";
|
||||
"Group.Setup.DeactivateAlertHide" = "Hide";
|
||||
|
||||
"Channel.Setup.PublicLink" = "PUBLIC LINK";
|
||||
"Channel.Setup.LinksOrder" = "LINKS ORDER";
|
||||
"Channel.Setup.LinksOrderInfo" = "Drag and drop links to change the order in which they will be displayed on the channel info page.";
|
||||
|
||||
"Channel.Setup.ActivateAlertTitle" = "Activate Link";
|
||||
"Channel.Setup.ActivateAlertText" = "Do you want to show this link on the channel info page?";
|
||||
"Channel.Setup.ActivateAlertShow" = "Show";
|
||||
|
||||
"Channel.Setup.DeactivateAlertTitle" = "Deactivate Link";
|
||||
"Channel.Setup.DeactivateAlertText" = "Do you want to hide this link from the channel info page?";
|
||||
"Channel.Setup.DeactivateAlertHide" = "Hide";
|
||||
|
||||
"Username.Username" = "USERNAME";
|
||||
"Username.LinksOrder" = "USERNAMES ORDER";
|
||||
"Username.LinksOrderInfo" = "Drag and drop links to change the order in which they will be displayed on your info page.";
|
||||
@ -8101,7 +8117,7 @@ Sorry for the inconvenience.";
|
||||
"Username.ActivateAlertText" = "Do you want to show this link on your info page?";
|
||||
"Username.ActivateAlertShow" = "Show";
|
||||
|
||||
"Username.DeactivateAlertTitle" = "Deativate Username";
|
||||
"Username.DeactivateAlertTitle" = "Deactivate Username";
|
||||
"Username.DeactivateAlertText" = "Do you want to hide this link from your info page?";
|
||||
"Username.DeactivateAlertHide" = "Hide";
|
||||
|
||||
|
@ -2677,10 +2677,6 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
self.animateRevealOptionsFill {
|
||||
self.revealOptionsInteractivelyClosed()
|
||||
}
|
||||
case RevealOptionKey.open.rawValue:
|
||||
break
|
||||
case RevealOptionKey.close.rawValue:
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
@ -2688,6 +2684,10 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
switch option.key {
|
||||
case RevealOptionKey.delete.rawValue:
|
||||
item.interaction.deletePeerThread(peerId, threadId)
|
||||
case RevealOptionKey.open.rawValue:
|
||||
break
|
||||
case RevealOptionKey.close.rawValue:
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ private func generateRectsImage(color: UIColor, rects: [CGRect], inset: CGFloat,
|
||||
}
|
||||
|
||||
public final class LinkHighlightingNode: ASDisplayNode {
|
||||
private var rects: [CGRect] = []
|
||||
public private(set) var rects: [CGRect] = []
|
||||
public let imageNode: ASImageNode
|
||||
|
||||
public var innerRadius: CGFloat = 4.0
|
||||
|
@ -44,7 +44,7 @@ public class AdditionalLinkItem: ListViewItem, ItemListItem {
|
||||
last = true
|
||||
}
|
||||
}
|
||||
let node = ItemListInviteLinkItemNode()
|
||||
let node = AdditionalLinkItemNode()
|
||||
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem), firstWithHeader, last)
|
||||
|
||||
node.contentSize = layout.contentSize
|
||||
@ -60,7 +60,7 @@ public class AdditionalLinkItem: ListViewItem, ItemListItem {
|
||||
|
||||
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||
Queue.mainQueue().async {
|
||||
if let nodeValue = node() as? ItemListInviteLinkItemNode {
|
||||
if let nodeValue = node() as? AdditionalLinkItemNode {
|
||||
let makeLayout = nodeValue.asyncLayout()
|
||||
|
||||
async {
|
||||
@ -94,7 +94,7 @@ public class AdditionalLinkItem: ListViewItem, ItemListItem {
|
||||
}
|
||||
}
|
||||
|
||||
public class ItemListInviteLinkItemNode: ListViewItemNode, ItemListItemNode {
|
||||
public class AdditionalLinkItemNode: ListViewItemNode, ItemListItemNode {
|
||||
private let backgroundNode: ASDisplayNode
|
||||
private let topStripeNode: ASDisplayNode
|
||||
private let bottomStripeNode: ASDisplayNode
|
||||
@ -384,13 +384,19 @@ public class ItemListInviteLinkItemNode: ListViewItemNode, ItemListItemNode {
|
||||
|
||||
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: contentSize.height + UIScreenPixel + UIScreenPixel))
|
||||
|
||||
if strongSelf.reorderControlNode == nil {
|
||||
if strongSelf.reorderControlNode == nil && item.username?.flags.contains(.isActive) == true {
|
||||
let reorderControlNode = reorderControlSizeAndApply.1(layout.contentSize.height, false, .immediate)
|
||||
strongSelf.reorderControlNode = reorderControlNode
|
||||
strongSelf.addSubnode(reorderControlNode)
|
||||
reorderControlNode.alpha = 0.0
|
||||
transition.updateAlpha(node: reorderControlNode, alpha: 1.0)
|
||||
} else if let reorderControlNode = strongSelf.reorderControlNode, item.username?.flags.contains(.isActive) == false {
|
||||
strongSelf.reorderControlNode = nil
|
||||
reorderControlNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak reorderControlNode] _ in
|
||||
reorderControlNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
|
||||
let reorderControlFrame = CGRect(origin: CGPoint(x: params.width - params.rightInset - reorderControlSizeAndApply.0, y: 0.0), size: CGSize(width: reorderControlSizeAndApply.0, height: layout.contentSize.height))
|
||||
strongSelf.reorderControlNode?.frame = reorderControlFrame
|
||||
|
@ -39,8 +39,10 @@ private final class ChannelVisibilityControllerArguments {
|
||||
let toggleForwarding: (Bool) -> Void
|
||||
let updateJoinToSend: (CurrentChannelJoinToSend) -> Void
|
||||
let toggleApproveMembers: (Bool) -> Void
|
||||
let activateLink: (String) -> Void
|
||||
let deactivateLink: (String) -> Void
|
||||
|
||||
init(context: AccountContext, updateCurrentType: @escaping (CurrentChannelType) -> Void, updatePublicLinkText: @escaping (String?, String) -> Void, scrollToPublicLinkText: @escaping () -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, revokePeerId: @escaping (PeerId) -> Void, copyLink: @escaping (ExportedInvitation) -> Void, shareLink: @escaping (ExportedInvitation) -> Void, linkContextAction: @escaping (ASDisplayNode, ContextGesture?) -> Void, manageInviteLinks: @escaping () -> Void, openLink: @escaping (ExportedInvitation) -> Void, toggleForwarding: @escaping (Bool) -> Void, updateJoinToSend: @escaping (CurrentChannelJoinToSend) -> Void, toggleApproveMembers: @escaping (Bool) -> Void) {
|
||||
init(context: AccountContext, updateCurrentType: @escaping (CurrentChannelType) -> Void, updatePublicLinkText: @escaping (String?, String) -> Void, scrollToPublicLinkText: @escaping () -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, revokePeerId: @escaping (PeerId) -> Void, copyLink: @escaping (ExportedInvitation) -> Void, shareLink: @escaping (ExportedInvitation) -> Void, linkContextAction: @escaping (ASDisplayNode, ContextGesture?) -> Void, manageInviteLinks: @escaping () -> Void, openLink: @escaping (ExportedInvitation) -> Void, toggleForwarding: @escaping (Bool) -> Void, updateJoinToSend: @escaping (CurrentChannelJoinToSend) -> Void, toggleApproveMembers: @escaping (Bool) -> Void, activateLink: @escaping (String) -> Void, deactivateLink: @escaping (String) -> Void) {
|
||||
self.context = context
|
||||
self.updateCurrentType = updateCurrentType
|
||||
self.updatePublicLinkText = updatePublicLinkText
|
||||
@ -55,6 +57,8 @@ private final class ChannelVisibilityControllerArguments {
|
||||
self.toggleForwarding = toggleForwarding
|
||||
self.updateJoinToSend = updateJoinToSend
|
||||
self.toggleApproveMembers = toggleApproveMembers
|
||||
self.activateLink = activateLink
|
||||
self.deactivateLink = deactivateLink
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,6 +67,7 @@ private enum ChannelVisibilitySection: Int32 {
|
||||
case limitInfo
|
||||
case link
|
||||
case linkActions
|
||||
case additional
|
||||
case joinToSend
|
||||
case approveMembers
|
||||
case forwarding
|
||||
@ -81,6 +86,11 @@ private enum ChannelVisibilityEntryTag: ItemListItemTag {
|
||||
}
|
||||
}
|
||||
|
||||
private enum ChannelVisibilityEntryId: Hashable {
|
||||
case index(Int32)
|
||||
case username(String)
|
||||
}
|
||||
|
||||
private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
||||
case typeHeader(PresentationTheme, String)
|
||||
case typePublic(PresentationTheme, String, Bool)
|
||||
@ -103,6 +113,10 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
||||
case existingLinksInfo(PresentationTheme, String)
|
||||
case existingLinkPeerItem(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, Peer, ItemListPeerItemEditing, Bool)
|
||||
|
||||
case additionalLinkHeader(PresentationTheme, String)
|
||||
case additionalLink(PresentationTheme, TelegramPeerUsername, Int32)
|
||||
case additionalLinkInfo(PresentationTheme, String)
|
||||
|
||||
case joinToSendHeader(PresentationTheme, String)
|
||||
case joinToSendEveryone(PresentationTheme, String, Bool)
|
||||
case joinToSendMembers(PresentationTheme, String, Bool)
|
||||
@ -122,6 +136,8 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
||||
return ChannelVisibilitySection.limitInfo.rawValue
|
||||
case .publicLinkHeader, .publicLinkAvailability, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkInfo, .publicLinkStatus:
|
||||
return ChannelVisibilitySection.link.rawValue
|
||||
case .additionalLinkHeader, .additionalLink, .additionalLinkInfo:
|
||||
return ChannelVisibilitySection.additional.rawValue
|
||||
case .privateLinkManage, .privateLinkManageInfo:
|
||||
return ChannelVisibilitySection.linkActions.rawValue
|
||||
case .existingLinksInfo, .existingLinkPeerItem:
|
||||
@ -135,58 +151,64 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
||||
}
|
||||
}
|
||||
|
||||
var stableId: Int32 {
|
||||
var stableId: ChannelVisibilityEntryId {
|
||||
switch self {
|
||||
case .typeHeader:
|
||||
return 0
|
||||
return .index(0)
|
||||
case .typePublic:
|
||||
return 1
|
||||
return .index(1)
|
||||
case .typePrivate:
|
||||
return 2
|
||||
return .index(2)
|
||||
case .typeInfo:
|
||||
return 3
|
||||
return .index(3)
|
||||
case .publicLinkHeader:
|
||||
return 4
|
||||
return .index(4)
|
||||
case .publicLinkAvailability:
|
||||
return 5
|
||||
return .index(5)
|
||||
case .linksLimitInfo:
|
||||
return 6
|
||||
return .index(6)
|
||||
case .privateLinkHeader:
|
||||
return 7
|
||||
return .index(7)
|
||||
case .privateLink:
|
||||
return 8
|
||||
return .index(8)
|
||||
case .editablePublicLink:
|
||||
return 9
|
||||
return .index(9)
|
||||
case .privateLinkInfo:
|
||||
return 10
|
||||
return .index(10)
|
||||
case .publicLinkStatus:
|
||||
return 11
|
||||
return .index(11)
|
||||
case .publicLinkInfo:
|
||||
return 12
|
||||
return .index(12)
|
||||
case .existingLinksInfo:
|
||||
return 13
|
||||
return .index(13)
|
||||
case let .existingLinkPeerItem(index, _, _, _, _, _, _, _):
|
||||
return 14 + index
|
||||
return .index(14 + index)
|
||||
case .additionalLinkHeader:
|
||||
return .index(1000)
|
||||
case let .additionalLink(_, username, _):
|
||||
return .username(username.username)
|
||||
case .additionalLinkInfo:
|
||||
return .index(2000)
|
||||
case .privateLinkManage:
|
||||
return 1000
|
||||
return .index(2001)
|
||||
case .privateLinkManageInfo:
|
||||
return 1001
|
||||
return .index(2002)
|
||||
case .joinToSendHeader:
|
||||
return 1002
|
||||
return .index(2003)
|
||||
case .joinToSendEveryone:
|
||||
return 1003
|
||||
return .index(2004)
|
||||
case .joinToSendMembers:
|
||||
return 1004
|
||||
return .index(2005)
|
||||
case .approveMembers:
|
||||
return 1005
|
||||
return .index(2006)
|
||||
case .approveMembersInfo:
|
||||
return 1006
|
||||
return .index(2007)
|
||||
case .forwardingHeader:
|
||||
return 1007
|
||||
return .index(2008)
|
||||
case .forwardingDisabled:
|
||||
return 1008
|
||||
return .index(2009)
|
||||
case .forwardingInfo:
|
||||
return 1009
|
||||
return .index(2010)
|
||||
}
|
||||
}
|
||||
|
||||
@ -234,6 +256,24 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .additionalLinkHeader(lhsTheme, lhsText):
|
||||
if case let .additionalLinkHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .additionalLink(lhsTheme, lhsAddressName, lhsIndex):
|
||||
if case let .additionalLink(rhsTheme, rhsAddressName, rhsIndex) = rhs, lhsTheme === rhsTheme, lhsAddressName == rhsAddressName, lhsIndex == rhsIndex {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .additionalLinkInfo(lhsTheme, lhsText):
|
||||
if case let .additionalLinkInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .privateLinkHeader(lhsTheme, lhsTitle):
|
||||
if case let .privateLinkHeader(rhsTheme, rhsTitle) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle {
|
||||
return true
|
||||
@ -370,7 +410,206 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
||||
}
|
||||
|
||||
static func <(lhs: ChannelVisibilityEntry, rhs: ChannelVisibilityEntry) -> Bool {
|
||||
return lhs.stableId < rhs.stableId
|
||||
switch lhs {
|
||||
case .typeHeader:
|
||||
switch rhs {
|
||||
case .typeHeader:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .typePublic:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .typePrivate:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .typeInfo:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .publicLinkHeader:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .publicLinkAvailability:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .linksLimitInfo:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .privateLinkHeader:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .privateLink:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .editablePublicLink:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink, .editablePublicLink:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .privateLinkInfo:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .publicLinkStatus:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkStatus:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .publicLinkInfo:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkStatus, .publicLinkInfo:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .existingLinksInfo:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkStatus, .publicLinkInfo, .existingLinksInfo:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case let .existingLinkPeerItem(lhsIndex, _, _, _, _, _, _, _):
|
||||
switch rhs {
|
||||
case let .existingLinkPeerItem(rhsIndex, _, _, _, _, _, _, _):
|
||||
return lhsIndex < rhsIndex
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkStatus, .publicLinkInfo, .existingLinksInfo:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .additionalLinkHeader:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkStatus, .publicLinkInfo, .existingLinksInfo, .existingLinkPeerItem, .additionalLinkHeader:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case let .additionalLink(_, _, lhsIndex):
|
||||
switch rhs {
|
||||
case let .additionalLink(_, _, rhsIndex):
|
||||
return lhsIndex < rhsIndex
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkStatus, .publicLinkInfo, .existingLinksInfo, .existingLinkPeerItem, .additionalLinkHeader:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .additionalLinkInfo:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkStatus, .publicLinkInfo, .existingLinksInfo, .existingLinkPeerItem, .additionalLinkHeader, .additionalLink, .additionalLinkInfo:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .privateLinkManage:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkStatus, .publicLinkInfo, .existingLinksInfo, .existingLinkPeerItem, .additionalLinkHeader, .additionalLink, .additionalLinkInfo, .privateLinkManage:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .privateLinkManageInfo:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkStatus, .publicLinkInfo, .existingLinksInfo, .existingLinkPeerItem, .additionalLinkHeader, .additionalLink, .additionalLinkInfo, .privateLinkManage, .privateLinkManageInfo:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .joinToSendHeader:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkStatus, .publicLinkInfo, .existingLinksInfo, .existingLinkPeerItem, .additionalLinkHeader, .additionalLink, .additionalLinkInfo, .privateLinkManage, .privateLinkManageInfo, .joinToSendHeader:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .joinToSendEveryone:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkStatus, .publicLinkInfo, .existingLinksInfo, .existingLinkPeerItem, .additionalLinkHeader, .additionalLink, .additionalLinkInfo, .privateLinkManage, .privateLinkManageInfo, .joinToSendHeader, .joinToSendEveryone:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .joinToSendMembers:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkStatus, .publicLinkInfo, .existingLinksInfo, .existingLinkPeerItem, .additionalLinkHeader, .additionalLink, .additionalLinkInfo, .privateLinkManage, .privateLinkManageInfo, .joinToSendHeader, .joinToSendEveryone, .joinToSendMembers:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .approveMembers:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkStatus, .publicLinkInfo, .existingLinksInfo, .existingLinkPeerItem, .additionalLinkHeader, .additionalLink, .additionalLinkInfo, .privateLinkManage, .privateLinkManageInfo, .joinToSendHeader, .joinToSendEveryone, .joinToSendMembers, .approveMembers:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .approveMembersInfo:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkStatus, .publicLinkInfo, .existingLinksInfo, .existingLinkPeerItem, .additionalLinkHeader, .additionalLink, .additionalLinkInfo, .privateLinkManage, .privateLinkManageInfo, .joinToSendHeader, .joinToSendEveryone, .joinToSendMembers, .approveMembers, .approveMembersInfo:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .forwardingHeader:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkStatus, .publicLinkInfo, .existingLinksInfo, .existingLinkPeerItem, .additionalLinkHeader, .additionalLink, .additionalLinkInfo, .privateLinkManage, .privateLinkManageInfo, .joinToSendHeader, .joinToSendEveryone, .joinToSendMembers, .approveMembers, .approveMembersInfo, .forwardingHeader:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .forwardingDisabled:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkStatus, .publicLinkInfo, .existingLinksInfo, .existingLinkPeerItem, .additionalLinkHeader, .additionalLink, .additionalLinkInfo, .privateLinkManage, .privateLinkManageInfo, .joinToSendHeader, .joinToSendEveryone, .joinToSendMembers, .approveMembers, .approveMembersInfo, .forwardingHeader, .forwardingDisabled:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .forwardingInfo:
|
||||
switch rhs {
|
||||
case .typeHeader, .typePublic, .typePrivate, .typeInfo, .publicLinkHeader, .publicLinkAvailability, .linksLimitInfo, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkStatus, .publicLinkInfo, .existingLinksInfo, .existingLinkPeerItem, .additionalLinkHeader, .additionalLink, .additionalLinkInfo, .privateLinkManage, .privateLinkManageInfo, .joinToSendHeader, .joinToSendEveryone, .joinToSendMembers, .approveMembers, .approveMembersInfo, .forwardingHeader, .forwardingDisabled, .forwardingInfo:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
||||
@ -465,6 +704,20 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
||||
}, removePeer: { peerId in
|
||||
arguments.revokePeerId(peerId)
|
||||
})
|
||||
case let .additionalLinkHeader(_, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .additionalLink(_, link, _):
|
||||
return AdditionalLinkItem(presentationData: presentationData, username: link, sectionId: self.section, style: .blocks, tapAction: {
|
||||
if !link.flags.contains(.isEditable) {
|
||||
if link.flags.contains(.isActive) {
|
||||
arguments.deactivateLink(link.username)
|
||||
} else {
|
||||
arguments.activateLink(link.username)
|
||||
}
|
||||
}
|
||||
})
|
||||
case let .additionalLinkInfo(_, text):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
||||
case let .joinToSendHeader(_, title):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
|
||||
case let .joinToSendEveryone(_, text, selected):
|
||||
@ -622,7 +875,7 @@ private struct ChannelVisibilityControllerState: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
private func channelVisibilityControllerEntries(presentationData: PresentationData, mode: ChannelVisibilityControllerMode, view: PeerView, publicChannelsToRevoke: [Peer]?, importers: PeerInvitationImportersState?, state: ChannelVisibilityControllerState, limits: EngineConfiguration.UserLimits, premiumLimits: EngineConfiguration.UserLimits, isPremium: Bool, isPremiumDisabled: Bool) -> [ChannelVisibilityEntry] {
|
||||
private func channelVisibilityControllerEntries(presentationData: PresentationData, mode: ChannelVisibilityControllerMode, view: PeerView, publicChannelsToRevoke: [Peer]?, importers: PeerInvitationImportersState?, state: ChannelVisibilityControllerState, limits: EngineConfiguration.UserLimits, premiumLimits: EngineConfiguration.UserLimits, isPremium: Bool, isPremiumDisabled: Bool, temporaryOrder: [String]?) -> [ChannelVisibilityEntry] {
|
||||
var entries: [ChannelVisibilityEntry] = []
|
||||
|
||||
let isInitialSetup: Bool
|
||||
@ -728,6 +981,8 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
||||
}
|
||||
}
|
||||
|
||||
let otherUsernames = peer.usernames.filter { !$0.flags.contains(.isEditable) }
|
||||
|
||||
if case .revokeNames = mode {
|
||||
let count = Int32(publicChannelsToRevoke?.count ?? 0)
|
||||
|
||||
@ -821,6 +1076,33 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
||||
} else {
|
||||
entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Channel_Username_CreatePublicLinkHelp))
|
||||
}
|
||||
|
||||
if !otherUsernames.isEmpty {
|
||||
entries.append(.additionalLinkHeader(presentationData.theme, isGroup ? presentationData.strings.Group_Setup_LinksOrder : presentationData.strings.Channel_Setup_LinksOrder))
|
||||
|
||||
var usernames = peer.usernames
|
||||
if let temporaryOrder = temporaryOrder {
|
||||
var usernamesMap: [String: TelegramPeerUsername] = [:]
|
||||
for username in usernames {
|
||||
usernamesMap[username.username] = username
|
||||
}
|
||||
var sortedUsernames: [TelegramPeerUsername] = []
|
||||
for username in temporaryOrder {
|
||||
if let username = usernamesMap[username] {
|
||||
sortedUsernames.append(username)
|
||||
}
|
||||
}
|
||||
usernames = sortedUsernames
|
||||
}
|
||||
var i: Int32 = 0
|
||||
for username in usernames {
|
||||
entries.append(.additionalLink(presentationData.theme, username, i))
|
||||
i += 1
|
||||
}
|
||||
|
||||
entries.append(.additionalLinkInfo(presentationData.theme, isGroup ? presentationData.strings.Group_Setup_LinksOrderInfo : presentationData.strings.Channel_Setup_LinksOrderInfo))
|
||||
}
|
||||
|
||||
switch mode {
|
||||
case .initialSetup, .revokeNames:
|
||||
break
|
||||
@ -1110,6 +1392,7 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
}))
|
||||
|
||||
var dismissImpl: (() -> Void)?
|
||||
var dismissInputImpl: (() -> Void)?
|
||||
var nextImpl: (() -> Void)?
|
||||
var scrollToPublicLinkTextImpl: (() -> Void)?
|
||||
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
||||
@ -1142,6 +1425,8 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
let toggleRequestToJoinDisposable = MetaDisposable()
|
||||
actionsDisposable.add(toggleRequestToJoinDisposable)
|
||||
|
||||
let temporaryOrder = Promise<[String]?>(nil)
|
||||
|
||||
let arguments = ChannelVisibilityControllerArguments(context: context, updateCurrentType: { type in
|
||||
if type == .publicChannel {
|
||||
let _ = combineLatest(
|
||||
@ -1363,6 +1648,63 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
updateState { state in
|
||||
return state.withUpdatedApproveMembers(value)
|
||||
}
|
||||
}, activateLink: { name in
|
||||
dismissInputImpl?()
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
let isGroup: Bool
|
||||
if case let .channel(channel) = peer, case .broadcast = channel.info {
|
||||
isGroup = false
|
||||
} else {
|
||||
isGroup = true
|
||||
}
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let title: String
|
||||
let text: String
|
||||
let action: String
|
||||
if isGroup {
|
||||
title = presentationData.strings.Group_Setup_ActivateAlertTitle
|
||||
text = presentationData.strings.Group_Setup_ActivateAlertText
|
||||
action = presentationData.strings.Group_Setup_ActivateAlertShow
|
||||
} else {
|
||||
title = presentationData.strings.Channel_Setup_ActivateAlertTitle
|
||||
text = presentationData.strings.Channel_Setup_ActivateAlertText
|
||||
action = presentationData.strings.Channel_Setup_ActivateAlertShow
|
||||
}
|
||||
presentControllerImpl?(textAlertController(context: context, title: title, text: text, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: action, action: {
|
||||
let _ = context.engine.peers.toggleAddressNameActive(domain: .peer(peerId), name: name, active: true).start()
|
||||
})]), nil)
|
||||
})
|
||||
}, deactivateLink: { name in
|
||||
dismissInputImpl?()
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
let isGroup: Bool
|
||||
if case let .channel(channel) = peer, case .broadcast = channel.info {
|
||||
isGroup = false
|
||||
} else {
|
||||
isGroup = true
|
||||
}
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let title: String
|
||||
let text: String
|
||||
let action: String
|
||||
|
||||
if isGroup {
|
||||
title = presentationData.strings.Group_Setup_DeactivateAlertTitle
|
||||
text = presentationData.strings.Group_Setup_DeactivateAlertText
|
||||
action = presentationData.strings.Group_Setup_DeactivateAlertHide
|
||||
} else {
|
||||
title = presentationData.strings.Channel_Setup_DeactivateAlertTitle
|
||||
text = presentationData.strings.Channel_Setup_DeactivateAlertText
|
||||
action = presentationData.strings.Channel_Setup_DeactivateAlertHide
|
||||
}
|
||||
presentControllerImpl?(textAlertController(context: context, title: title, text: text, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: action, action: {
|
||||
let _ = context.engine.peers.toggleAddressNameActive(domain: .peer(peerId), name: name, active: false).start()
|
||||
})]), nil)
|
||||
})
|
||||
})
|
||||
|
||||
let peerView = context.account.viewTracker.peerView(peerId)
|
||||
@ -1370,6 +1712,7 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
|
||||
let previousHadNamesToRevoke = Atomic<Bool?>(value: nil)
|
||||
let previousInvitation = Atomic<ExportedInvitation?>(value: nil)
|
||||
let previousUsernames = Atomic<[String]?>(value: nil)
|
||||
|
||||
let mainLink = context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Peer.ExportedInvitation(id: peerId)
|
||||
@ -1403,10 +1746,11 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: false),
|
||||
TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: true),
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)
|
||||
)
|
||||
),
|
||||
temporaryOrder.get()
|
||||
)
|
||||
|> deliverOnMainQueue
|
||||
|> map { presentationData, state, view, publicChannelsToRevoke, importersContext, importers, data -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
|> map { presentationData, state, view, publicChannelsToRevoke, importersContext, importers, data, temporaryOrder -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
let peer = peerViewMainPeer(view)
|
||||
|
||||
let (limits, premiumLimits, accountPeer) = data
|
||||
@ -1653,7 +1997,11 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
|
||||
let hasNamesToRevoke = publicChannelsToRevoke != nil && !publicChannelsToRevoke!.isEmpty
|
||||
let hadNamesToRevoke = previousHadNamesToRevoke.swap(hasNamesToRevoke)
|
||||
|
||||
if let peer = view.peers[view.peerId] as? TelegramChannel {
|
||||
let currentUsernames = peer.usernames.map { $0.username }
|
||||
let previousUsernames = previousUsernames.swap(currentUsernames)
|
||||
|
||||
let selectedType: CurrentChannelType
|
||||
if case .privateLink = mode {
|
||||
selectedType = .privateChannel
|
||||
@ -1678,6 +2026,10 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
if let hadNamesToRevoke = hadNamesToRevoke {
|
||||
animateChanges = hadNamesToRevoke != hasNamesToRevoke
|
||||
}
|
||||
|
||||
if temporaryOrder != nil || previousUsernames != currentUsernames {
|
||||
animateChanges = true
|
||||
}
|
||||
}
|
||||
|
||||
let title: String
|
||||
@ -1694,7 +2046,7 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
title = presentationData.strings.Premium_LimitReached
|
||||
}
|
||||
|
||||
let entries = channelVisibilityControllerEntries(presentationData: presentationData, mode: mode, view: view, publicChannelsToRevoke: publicChannelsToRevoke, importers: importers, state: state, limits: limits, premiumLimits: premiumLimits, isPremium: isPremium, isPremiumDisabled: premiumConfiguration.isPremiumDisabled)
|
||||
let entries = channelVisibilityControllerEntries(presentationData: presentationData, mode: mode, view: view, publicChannelsToRevoke: publicChannelsToRevoke, importers: importers, state: state, limits: limits, premiumLimits: premiumLimits, isPremium: isPremium, isPremiumDisabled: premiumConfiguration.isPremiumDisabled, temporaryOrder: temporaryOrder)
|
||||
|
||||
var focusItemTag: ItemListItemTag?
|
||||
if entries.count > 1, let cachedChannelData = view.cachedData as? CachedChannelData, cachedChannelData.peerGeoLocation != nil {
|
||||
@ -1713,6 +2065,125 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
controller.willDisappear = { _ in
|
||||
dismissTooltipsImpl?()
|
||||
}
|
||||
controller.setReorderEntry({ (fromIndex: Int, toIndex: Int, entries: [ChannelVisibilityEntry]) -> Signal<Bool, NoError> in
|
||||
let fromEntry = entries[fromIndex]
|
||||
guard case let .additionalLink(_, fromUsername, _) = fromEntry else {
|
||||
return .single(false)
|
||||
}
|
||||
var referenceId: String?
|
||||
var beforeAll = false
|
||||
var afterAll = false
|
||||
|
||||
var maxIndex: Int?
|
||||
|
||||
var currentUsernames: [String] = []
|
||||
var i = 0
|
||||
for entry in entries {
|
||||
switch entry {
|
||||
case let .additionalLink(_, link, _):
|
||||
currentUsernames.append(link.username)
|
||||
if !link.flags.contains(.isActive) && maxIndex == nil {
|
||||
maxIndex = max(0, i - 1)
|
||||
}
|
||||
i += 1
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if toIndex < entries.count {
|
||||
switch entries[toIndex] {
|
||||
case let .additionalLink(_, toUsername, _):
|
||||
if toUsername.flags.contains(.isActive) {
|
||||
referenceId = toUsername.username
|
||||
} else {
|
||||
afterAll = true
|
||||
}
|
||||
default:
|
||||
if entries[toIndex] < fromEntry {
|
||||
beforeAll = true
|
||||
} else {
|
||||
afterAll = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
afterAll = true
|
||||
}
|
||||
|
||||
var previousIndex: Int?
|
||||
for i in 0 ..< currentUsernames.count {
|
||||
if currentUsernames[i] == fromUsername.username {
|
||||
previousIndex = i
|
||||
currentUsernames.remove(at: i)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var didReorder = false
|
||||
if let referenceId = referenceId {
|
||||
var inserted = false
|
||||
for i in 0 ..< currentUsernames.count {
|
||||
if currentUsernames[i] == referenceId {
|
||||
if fromIndex < toIndex {
|
||||
didReorder = previousIndex != i + 1
|
||||
currentUsernames.insert(fromUsername.username, at: i + 1)
|
||||
} else {
|
||||
didReorder = previousIndex != i
|
||||
currentUsernames.insert(fromUsername.username, at: i)
|
||||
}
|
||||
inserted = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !inserted {
|
||||
didReorder = previousIndex != currentUsernames.count
|
||||
if let maxIndex = maxIndex {
|
||||
currentUsernames.insert(fromUsername.username, at: maxIndex)
|
||||
} else {
|
||||
currentUsernames.append(fromUsername.username)
|
||||
}
|
||||
}
|
||||
} else if beforeAll {
|
||||
didReorder = previousIndex != 0
|
||||
currentUsernames.insert(fromUsername.username, at: 0)
|
||||
} else if afterAll {
|
||||
didReorder = previousIndex != currentUsernames.count
|
||||
if let maxIndex = maxIndex {
|
||||
currentUsernames.insert(fromUsername.username, at: maxIndex)
|
||||
} else {
|
||||
currentUsernames.append(fromUsername.username)
|
||||
}
|
||||
}
|
||||
|
||||
temporaryOrder.set(.single(currentUsernames))
|
||||
|
||||
if didReorder {
|
||||
DispatchQueue.main.async {
|
||||
dismissInputImpl?()
|
||||
}
|
||||
}
|
||||
|
||||
return .single(didReorder)
|
||||
})
|
||||
|
||||
controller.setReorderCompleted({ (entries: [ChannelVisibilityEntry]) -> Void in
|
||||
var currentUsernames: [TelegramPeerUsername] = []
|
||||
for entry in entries {
|
||||
switch entry {
|
||||
case let .additionalLink(_, username, _):
|
||||
currentUsernames.append(username)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
let _ = (context.engine.peers.reorderAddressNames(domain: .peer(peerId), names: currentUsernames)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
temporaryOrder.set(.single(nil))
|
||||
})
|
||||
})
|
||||
controller.beganInteractiveDragging = {
|
||||
dismissInputImpl?()
|
||||
}
|
||||
dismissImpl = { [weak controller, weak onDismissRemoveController] in
|
||||
guard let controller = controller else {
|
||||
return
|
||||
@ -1730,6 +2201,9 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
controller.dismiss()
|
||||
}
|
||||
}
|
||||
dismissInputImpl = { [weak controller] in
|
||||
controller?.view.endEditing(true)
|
||||
}
|
||||
nextImpl = { [weak controller] in
|
||||
if let controller = controller {
|
||||
if case .initialSetup = mode {
|
||||
|
@ -10,6 +10,7 @@ import PresentationDataUtils
|
||||
import AccountContext
|
||||
import ShareController
|
||||
import UndoUI
|
||||
import InviteLinksUI
|
||||
|
||||
private final class UsernameSetupControllerArguments {
|
||||
let account: Account
|
||||
@ -46,6 +47,10 @@ public enum UsernameEntryTag: ItemListItemTag {
|
||||
}
|
||||
}
|
||||
|
||||
private enum UsernameSetupEntryId: Hashable {
|
||||
case index(Int32)
|
||||
case username(String)
|
||||
}
|
||||
|
||||
private enum UsernameSetupEntry: ItemListNodeEntry {
|
||||
case publicLinkHeader(PresentationTheme, String)
|
||||
@ -66,22 +71,22 @@ private enum UsernameSetupEntry: ItemListNodeEntry {
|
||||
}
|
||||
}
|
||||
|
||||
var stableId: Int32 {
|
||||
var stableId: UsernameSetupEntryId {
|
||||
switch self {
|
||||
case .publicLinkHeader:
|
||||
return 0
|
||||
return .index(0)
|
||||
case .editablePublicLink:
|
||||
return 1
|
||||
return .index(1)
|
||||
case .publicLinkStatus:
|
||||
return 2
|
||||
return .index(2)
|
||||
case .publicLinkInfo:
|
||||
return 3
|
||||
return .index(3)
|
||||
case .additionalLinkHeader:
|
||||
return 4
|
||||
case let .additionalLink(_, _, index):
|
||||
return 5 + index
|
||||
return .index(4)
|
||||
case let .additionalLink(_, username, _):
|
||||
return .username(username.username)
|
||||
case .additionalLinkInfo:
|
||||
return 1000
|
||||
return .index(5)
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,7 +138,57 @@ private enum UsernameSetupEntry: ItemListNodeEntry {
|
||||
}
|
||||
|
||||
static func <(lhs: UsernameSetupEntry, rhs: UsernameSetupEntry) -> Bool {
|
||||
return lhs.stableId < rhs.stableId
|
||||
switch lhs {
|
||||
case .publicLinkHeader:
|
||||
switch rhs {
|
||||
case .publicLinkHeader:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .editablePublicLink:
|
||||
switch rhs {
|
||||
case .publicLinkHeader, .editablePublicLink:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .publicLinkStatus:
|
||||
switch rhs {
|
||||
case .publicLinkHeader, .editablePublicLink, .publicLinkStatus:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .publicLinkInfo:
|
||||
switch rhs {
|
||||
case .publicLinkHeader, .editablePublicLink, .publicLinkStatus, .publicLinkInfo:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .additionalLinkHeader:
|
||||
switch rhs {
|
||||
case .publicLinkHeader, .editablePublicLink, .publicLinkStatus, .publicLinkInfo, .additionalLinkHeader:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case let .additionalLink(_, _, lhsIndex):
|
||||
switch rhs {
|
||||
case let .additionalLink(_, _, rhsIndex):
|
||||
return lhsIndex < rhsIndex
|
||||
case .publicLinkHeader, .editablePublicLink, .publicLinkStatus, .publicLinkInfo, .additionalLinkHeader:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .additionalLinkInfo:
|
||||
switch rhs {
|
||||
case .publicLinkHeader, .editablePublicLink, .publicLinkStatus, .publicLinkInfo, .additionalLinkHeader, .additionalLink, .additionalLinkInfo:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
||||
@ -482,10 +537,32 @@ public func usernameSetupController(context: AccountContext) -> ViewController {
|
||||
var referenceId: String?
|
||||
var beforeAll = false
|
||||
var afterAll = false
|
||||
|
||||
var maxIndex: Int?
|
||||
|
||||
var currentUsernames: [String] = []
|
||||
var i = 0
|
||||
for entry in entries {
|
||||
switch entry {
|
||||
case let .additionalLink(_, link, _):
|
||||
currentUsernames.append(link.username)
|
||||
if !link.flags.contains(.isActive) && maxIndex == nil {
|
||||
maxIndex = max(0, i - 1)
|
||||
}
|
||||
i += 1
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if toIndex < entries.count {
|
||||
switch entries[toIndex] {
|
||||
case let .additionalLink(_, toUsername, _):
|
||||
if toUsername.flags.contains(.isActive) {
|
||||
referenceId = toUsername.username
|
||||
} else {
|
||||
afterAll = true
|
||||
}
|
||||
default:
|
||||
if entries[toIndex] < fromEntry {
|
||||
beforeAll = true
|
||||
@ -497,16 +574,6 @@ public func usernameSetupController(context: AccountContext) -> ViewController {
|
||||
afterAll = true
|
||||
}
|
||||
|
||||
var currentUsernames: [String] = []
|
||||
for entry in entries {
|
||||
switch entry {
|
||||
case let .additionalLink(_, link, _):
|
||||
currentUsernames.append(link.username)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var previousIndex: Int?
|
||||
for i in 0 ..< currentUsernames.count {
|
||||
if currentUsernames[i] == fromUsername.username {
|
||||
@ -517,7 +584,6 @@ public func usernameSetupController(context: AccountContext) -> ViewController {
|
||||
}
|
||||
|
||||
var didReorder = false
|
||||
|
||||
if let referenceId = referenceId {
|
||||
var inserted = false
|
||||
for i in 0 ..< currentUsernames.count {
|
||||
@ -535,15 +601,23 @@ public func usernameSetupController(context: AccountContext) -> ViewController {
|
||||
}
|
||||
if !inserted {
|
||||
didReorder = previousIndex != currentUsernames.count
|
||||
if let maxIndex = maxIndex {
|
||||
currentUsernames.insert(fromUsername.username, at: maxIndex)
|
||||
} else {
|
||||
currentUsernames.append(fromUsername.username)
|
||||
}
|
||||
}
|
||||
} else if beforeAll {
|
||||
didReorder = previousIndex != 0
|
||||
currentUsernames.insert(fromUsername.username, at: 0)
|
||||
} else if afterAll {
|
||||
didReorder = previousIndex != currentUsernames.count
|
||||
if let maxIndex = maxIndex {
|
||||
currentUsernames.insert(fromUsername.username, at: maxIndex)
|
||||
} else {
|
||||
currentUsernames.append(fromUsername.username)
|
||||
}
|
||||
}
|
||||
|
||||
temporaryOrder.set(.single(currentUsernames))
|
||||
|
||||
|
@ -190,14 +190,40 @@ func _internal_toggleAddressNameActive(account: Account, domain: AddressNameDoma
|
||||
var updatedNames = peer.usernames
|
||||
if let index = updatedNames.firstIndex(where: { $0.username == name }) {
|
||||
var updatedFlags = updatedNames[index].flags
|
||||
var updateOrder = true
|
||||
var updatedIndex = index
|
||||
if active {
|
||||
if updatedFlags.contains(.isActive) {
|
||||
updateOrder = false
|
||||
}
|
||||
updatedFlags.insert(.isActive)
|
||||
} else {
|
||||
if !updatedFlags.contains(.isActive) {
|
||||
updateOrder = false
|
||||
}
|
||||
updatedFlags.remove(.isActive)
|
||||
}
|
||||
let updatedName = TelegramPeerUsername(flags: updatedFlags, username: name)
|
||||
updatedNames.remove(at: index)
|
||||
updatedNames.insert(updatedName, at: index)
|
||||
if updateOrder {
|
||||
if active {
|
||||
updatedIndex = 0
|
||||
} else {
|
||||
updatedIndex = updatedNames.count
|
||||
}
|
||||
var i = 0
|
||||
for name in updatedNames {
|
||||
if active && !name.flags.contains(.isActive) {
|
||||
updatedIndex = i
|
||||
break
|
||||
} else if !active && !name.flags.contains(.isActive) {
|
||||
updatedIndex = i
|
||||
break
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
updatedNames.insert(updatedName, at: updatedIndex)
|
||||
}
|
||||
let updatedUser = peer.withUpdatedUsernames(updatedNames)
|
||||
updatePeers(transaction: transaction, peers: [updatedUser], update: { _, updated in
|
||||
@ -218,14 +244,40 @@ func _internal_toggleAddressNameActive(account: Account, domain: AddressNameDoma
|
||||
var updatedNames = peer.usernames
|
||||
if let index = updatedNames.firstIndex(where: { $0.username == name }) {
|
||||
var updatedFlags = updatedNames[index].flags
|
||||
var updateOrder = true
|
||||
var updatedIndex = index
|
||||
if active {
|
||||
if updatedFlags.contains(.isActive) {
|
||||
updateOrder = false
|
||||
}
|
||||
updatedFlags.insert(.isActive)
|
||||
} else {
|
||||
if !updatedFlags.contains(.isActive) {
|
||||
updateOrder = false
|
||||
}
|
||||
updatedFlags.remove(.isActive)
|
||||
}
|
||||
let updatedName = TelegramPeerUsername(flags: updatedFlags, username: name)
|
||||
updatedNames.remove(at: index)
|
||||
updatedNames.insert(updatedName, at: index)
|
||||
if updateOrder {
|
||||
if active {
|
||||
updatedIndex = 0
|
||||
} else {
|
||||
updatedIndex = updatedNames.count
|
||||
}
|
||||
var i = 0
|
||||
for name in updatedNames {
|
||||
if active && !name.flags.contains(.isActive) {
|
||||
updatedIndex = i
|
||||
break
|
||||
} else if !active && !name.flags.contains(.isActive) {
|
||||
updatedIndex = i
|
||||
break
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
updatedNames.insert(updatedName, at: updatedIndex)
|
||||
}
|
||||
let updatedPeer = peer.withUpdatedAddressNames(updatedNames)
|
||||
updatePeers(transaction: transaction, peers: [updatedPeer], update: { _, updated in
|
||||
@ -251,7 +303,7 @@ func _internal_reorderAddressNames(account: Account, domain: AddressNameDomain,
|
||||
return account.postbox.transaction { transaction -> Signal<Void, ReorderAddressNamesError> in
|
||||
switch domain {
|
||||
case .account:
|
||||
return account.network.request(Api.functions.account.reorderUsernames(order: names.map { $0.username }), automaticFloodWait: false)
|
||||
return account.network.request(Api.functions.account.reorderUsernames(order: names.filter { $0.flags.contains(.isActive) }.map { $0.username }), automaticFloodWait: false)
|
||||
|> mapError { _ -> ReorderAddressNamesError in
|
||||
return .generic
|
||||
}
|
||||
@ -267,7 +319,7 @@ func _internal_reorderAddressNames(account: Account, domain: AddressNameDomain,
|
||||
}
|
||||
case let .peer(peerId):
|
||||
if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) {
|
||||
return account.network.request(Api.functions.channels.reorderUsernames(channel: inputChannel, order: names.map { $0.username }), automaticFloodWait: false)
|
||||
return account.network.request(Api.functions.channels.reorderUsernames(channel: inputChannel, order: names.filter { $0.flags.contains(.isActive) }.map { $0.username }), automaticFloodWait: false)
|
||||
|> mapError { _ -> ReorderAddressNamesError in
|
||||
return .generic
|
||||
}
|
||||
|
@ -300,6 +300,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/ForumTopicListScreen:ForumTopicListScreen",
|
||||
"//submodules/TelegramUI/Components/ForumCreateTopicScreen:ForumCreateTopicScreen",
|
||||
"//submodules/TelegramUI/Components/ChatTitleView",
|
||||
"//submodules/InviteLinksUI:InviteLinksUI",
|
||||
] + select({
|
||||
"@build_bazel_rules_apple//apple:ios_armv7": [],
|
||||
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
|
||||
|
@ -3906,7 +3906,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
var animateReplyNodeIn = false
|
||||
if (translation.x < -45.0) != (self.currentSwipeToReplyTranslation < -45.0) {
|
||||
if translation.x < -45.0, self.swipeToReplyNode == nil, let item = self.item {
|
||||
self.swipeToReplyFeedback?.impact()
|
||||
self.swipeToReplyFeedback?.impact(.heavy)
|
||||
|
||||
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction))
|
||||
self.swipeToReplyNode = swipeToReplyNode
|
||||
|
@ -998,7 +998,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
||||
var animateReplyNodeIn = false
|
||||
if (translation.x < -45.0) != (self.currentSwipeToReplyTranslation < -45.0) {
|
||||
if translation.x < -45.0, self.swipeToReplyNode == nil, let item = self.item {
|
||||
self.swipeToReplyFeedback?.impact()
|
||||
self.swipeToReplyFeedback?.impact(.heavy)
|
||||
|
||||
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction))
|
||||
self.swipeToReplyNode = swipeToReplyNode
|
||||
|
@ -1250,7 +1250,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
var animateReplyNodeIn = false
|
||||
if (translation.x < -45.0) != (self.currentSwipeToReplyTranslation < -45.0) {
|
||||
if translation.x < -45.0, self.swipeToReplyNode == nil, let item = self.item {
|
||||
self.swipeToReplyFeedback?.impact()
|
||||
self.swipeToReplyFeedback?.impact(.heavy)
|
||||
|
||||
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction))
|
||||
self.swipeToReplyNode = swipeToReplyNode
|
||||
|
@ -578,7 +578,7 @@ final class ChatQrCodeScreen: ViewController {
|
||||
} else {
|
||||
result = "t_me-\(Int32.random(in: 0 ..< Int32.max))"
|
||||
}
|
||||
if let threadId = threadId {
|
||||
if let threadId = threadId, threadId != 0 {
|
||||
result.append("-\(threadId)")
|
||||
}
|
||||
return result
|
||||
@ -1519,7 +1519,7 @@ private class QrContentNode: ASDisplayNode, ContentNode {
|
||||
} else {
|
||||
codeText = peer.debugDisplayTitle.uppercased()
|
||||
}
|
||||
if let threadId = self.threadId {
|
||||
if let threadId = self.threadId, threadId != 0 {
|
||||
codeText += "/\(threadId)"
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem {
|
||||
let icon: PeerInfoScreenLabeledValueIcon?
|
||||
let action: ((ASDisplayNode) -> Void)?
|
||||
let longTapAction: ((ASDisplayNode) -> Void)?
|
||||
let linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)?
|
||||
let linkItemAction: ((TextLinkItemActionType, TextLinkItem, ASDisplayNode, CGRect?) -> Void)?
|
||||
let iconAction: (() -> Void)?
|
||||
let contextAction: ((ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?
|
||||
let requestLayout: () -> Void
|
||||
@ -47,7 +47,7 @@ final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem {
|
||||
icon: PeerInfoScreenLabeledValueIcon? = nil,
|
||||
action: ((ASDisplayNode) -> Void)?,
|
||||
longTapAction: ((ASDisplayNode) -> Void)? = nil,
|
||||
linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)? = nil,
|
||||
linkItemAction: ((TextLinkItemActionType, TextLinkItem, ASDisplayNode, CGRect?) -> Void)? = nil,
|
||||
iconAction: (() -> Void)? = nil,
|
||||
contextAction: ((ASDisplayNode, ContextGesture?, CGPoint?) -> Void)? = nil,
|
||||
requestLayout: @escaping () -> Void
|
||||
@ -313,7 +313,7 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
||||
case .tap, .longTap:
|
||||
if let item = self.item {
|
||||
if let linkItem = self.linkItemAtPoint(location) {
|
||||
item.linkItemAction?(gesture == .tap ? .tap : .longTap, linkItem)
|
||||
item.linkItemAction?(gesture == .tap ? .tap : .longTap, linkItem, self.linkHighlightingNode ?? self, self.linkHighlightingNode?.rects.first)
|
||||
} else if case .longTap = gesture {
|
||||
item.longTapAction?(self)
|
||||
} else if case .tap = gesture {
|
||||
@ -601,7 +601,8 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
||||
}
|
||||
if textNode == nil {
|
||||
let additionalTextNodeFrame = self.additionalTextNode.frame
|
||||
if let (index, attributes) = self.additionalTextNode.attributesAtPoint(CGPoint(x: point.x - additionalTextNodeFrame.minX, y: point.y - additionalTextNodeFrame.minY)) {
|
||||
let mappedPoint = CGPoint(x: point.x - additionalTextNodeFrame.minX, y: point.y - additionalTextNodeFrame.minY)
|
||||
if mappedPoint.y > 0.0, let (index, attributes) = self.additionalTextNode.attributesAtPoint(mappedPoint) {
|
||||
let possibleNames: [String] = [
|
||||
TelegramTextAttributes.URL,
|
||||
TelegramTextAttributes.PeerMention,
|
||||
|
@ -488,7 +488,7 @@ private final class PeerInfoInteraction {
|
||||
let editingOpenSetupLocation: () -> Void
|
||||
let openPeerInfo: (Peer, Bool) -> Void
|
||||
let performMemberAction: (PeerInfoMember, PeerInfoMemberAction) -> Void
|
||||
let openPeerInfoContextMenu: (PeerInfoContextSubject, ASDisplayNode) -> Void
|
||||
let openPeerInfoContextMenu: (PeerInfoContextSubject, ASDisplayNode, CGRect?) -> Void
|
||||
let performBioLinkAction: (TextLinkItemActionType, TextLinkItem) -> Void
|
||||
let requestLayout: (Bool) -> Void
|
||||
let openEncryptionKey: () -> Void
|
||||
@ -533,7 +533,7 @@ private final class PeerInfoInteraction {
|
||||
editingOpenSetupLocation: @escaping () -> Void,
|
||||
openPeerInfo: @escaping (Peer, Bool) -> Void,
|
||||
performMemberAction: @escaping (PeerInfoMember, PeerInfoMemberAction) -> Void,
|
||||
openPeerInfoContextMenu: @escaping (PeerInfoContextSubject, ASDisplayNode) -> Void,
|
||||
openPeerInfoContextMenu: @escaping (PeerInfoContextSubject, ASDisplayNode, CGRect?) -> Void,
|
||||
performBioLinkAction: @escaping (TextLinkItemActionType, TextLinkItem) -> Void,
|
||||
requestLayout: @escaping (Bool) -> Void,
|
||||
openEncryptionKey: @escaping () -> Void,
|
||||
@ -934,9 +934,9 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
||||
}
|
||||
|
||||
let bioContextAction: (ASDisplayNode) -> Void = { sourceNode in
|
||||
interaction.openPeerInfoContextMenu(.bio, sourceNode)
|
||||
interaction.openPeerInfoContextMenu(.bio, sourceNode, nil)
|
||||
}
|
||||
let bioLinkAction: (TextLinkItemActionType, TextLinkItem) -> Void = { action, item in
|
||||
let bioLinkAction: (TextLinkItemActionType, TextLinkItem, ASDisplayNode, CGRect?) -> Void = { action, item, _, _ in
|
||||
interaction.performBioLinkAction(action, item)
|
||||
}
|
||||
|
||||
@ -974,8 +974,8 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
||||
action: { _ in
|
||||
interaction.openUsername(username)
|
||||
}, longTapAction: { sourceNode in
|
||||
interaction.openPeerInfoContextMenu(.link(customLink: nil), sourceNode)
|
||||
}, linkItemAction: { type, item in
|
||||
interaction.openPeerInfoContextMenu(.link(customLink: nil), sourceNode, nil)
|
||||
}, linkItemAction: { type, item, _, _ in
|
||||
if case .tap = type {
|
||||
if case let .mention(username) = item {
|
||||
interaction.openUsername(String(username[username.index(username.startIndex, offsetBy: 1)...]))
|
||||
@ -1103,8 +1103,8 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
||||
action: { _ in
|
||||
interaction.openUsername(linkText)
|
||||
}, longTapAction: { sourceNode in
|
||||
interaction.openPeerInfoContextMenu(.link(customLink: linkText), sourceNode)
|
||||
}, linkItemAction: { type, item in
|
||||
interaction.openPeerInfoContextMenu(.link(customLink: linkText), sourceNode, nil)
|
||||
}, linkItemAction: { type, item, _, _ in
|
||||
if case .tap = type {
|
||||
if case let .mention(username) = item {
|
||||
interaction.openUsername(String(username.suffix(from: username.index(username.startIndex, offsetBy: 1))))
|
||||
@ -1153,12 +1153,16 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
||||
action: { _ in
|
||||
interaction.openUsername(username)
|
||||
}, longTapAction: { sourceNode in
|
||||
interaction.openPeerInfoContextMenu(.link(customLink: nil), sourceNode)
|
||||
}, linkItemAction: { type, item in
|
||||
interaction.openPeerInfoContextMenu(.link(customLink: nil), sourceNode, nil)
|
||||
}, linkItemAction: { type, item, sourceNode, sourceRect in
|
||||
if case .tap = type {
|
||||
if case let .mention(username) = item {
|
||||
interaction.openUsername(String(username.suffix(from: username.index(username.startIndex, offsetBy: 1))))
|
||||
}
|
||||
} else if case .longTap = type {
|
||||
if case let .mention(username) = item {
|
||||
interaction.openPeerInfoContextMenu(.link(customLink: username), sourceNode, sourceRect)
|
||||
}
|
||||
}
|
||||
}, iconAction: {
|
||||
interaction.openQrCode()
|
||||
@ -1987,8 +1991,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
performMemberAction: { [weak self] member, action in
|
||||
self?.performMemberAction(member: member, action: action)
|
||||
},
|
||||
openPeerInfoContextMenu: { [weak self] subject, sourceNode in
|
||||
self?.openPeerInfoContextMenu(subject: subject, sourceNode: sourceNode)
|
||||
openPeerInfoContextMenu: { [weak self] subject, sourceNode, sourceRect in
|
||||
self?.openPeerInfoContextMenu(subject: subject, sourceNode: sourceNode, sourceRect: sourceRect)
|
||||
},
|
||||
performBioLinkAction: { [weak self] action, item in
|
||||
self?.performBioLinkAction(action: action, item: item)
|
||||
@ -6092,7 +6096,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
private func openPeerInfoContextMenu(subject: PeerInfoContextSubject, sourceNode: ASDisplayNode) {
|
||||
private func openPeerInfoContextMenu(subject: PeerInfoContextSubject, sourceNode: ASDisplayNode, sourceRect: CGRect?) {
|
||||
guard let data = self.data, let peer = data.peer, let controller = self.controller else {
|
||||
return
|
||||
}
|
||||
@ -6144,7 +6148,11 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
let contextMenuController = ContextMenuController(actions: actions)
|
||||
controller.present(contextMenuController, in: .window(.root), with: ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self, weak sourceNode] in
|
||||
if let controller = self?.controller, let sourceNode = sourceNode {
|
||||
return (sourceNode, sourceNode.bounds.insetBy(dx: 0.0, dy: 2.0), controller.displayNode, controller.view.bounds)
|
||||
var rect = sourceNode.bounds.insetBy(dx: 0.0, dy: 2.0)
|
||||
if let sourceRect = sourceRect {
|
||||
rect = sourceRect.insetBy(dx: 0.0, dy: 2.0)
|
||||
}
|
||||
return (sourceNode, rect, controller.displayNode, controller.view.bounds)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
@ -6160,7 +6168,11 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
})])
|
||||
controller.present(contextMenuController, in: .window(.root), with: ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self, weak sourceNode] in
|
||||
if let controller = self?.controller, let sourceNode = sourceNode {
|
||||
return (sourceNode, sourceNode.bounds.insetBy(dx: 0.0, dy: 2.0), controller.displayNode, controller.view.bounds)
|
||||
var rect = sourceNode.bounds.insetBy(dx: 0.0, dy: 2.0)
|
||||
if let sourceRect = sourceRect {
|
||||
rect = sourceRect.insetBy(dx: 0.0, dy: 2.0)
|
||||
}
|
||||
return (sourceNode, rect, controller.displayNode, controller.view.bounds)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
@ -6192,7 +6204,11 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
})])
|
||||
controller.present(contextMenuController, in: .window(.root), with: ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self, weak sourceNode] in
|
||||
if let controller = self?.controller, let sourceNode = sourceNode {
|
||||
return (sourceNode, sourceNode.bounds.insetBy(dx: 0.0, dy: 2.0), controller.displayNode, controller.view.bounds)
|
||||
var rect = sourceNode.bounds.insetBy(dx: 0.0, dy: 2.0)
|
||||
if let sourceRect = sourceRect {
|
||||
rect = sourceRect.insetBy(dx: 0.0, dy: 2.0)
|
||||
}
|
||||
return (sourceNode, rect, controller.displayNode, controller.view.bounds)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user