mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-25 17:43:18 +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.LinkActive" = "active";
|
||||||
"Group.Setup.LinkInactive" = "inactive";
|
"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.PublicLink" = "PUBLIC LINK";
|
||||||
"Channel.Setup.LinksOrder" = "LINKS ORDER";
|
"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.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.Username" = "USERNAME";
|
||||||
"Username.LinksOrder" = "USERNAMES ORDER";
|
"Username.LinksOrder" = "USERNAMES ORDER";
|
||||||
"Username.LinksOrderInfo" = "Drag and drop links to change the order in which they will be displayed on your info page.";
|
"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.ActivateAlertText" = "Do you want to show this link on your info page?";
|
||||||
"Username.ActivateAlertShow" = "Show";
|
"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.DeactivateAlertText" = "Do you want to hide this link from your info page?";
|
||||||
"Username.DeactivateAlertHide" = "Hide";
|
"Username.DeactivateAlertHide" = "Hide";
|
||||||
|
|
||||||
|
|||||||
@ -2677,10 +2677,6 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
self.animateRevealOptionsFill {
|
self.animateRevealOptionsFill {
|
||||||
self.revealOptionsInteractivelyClosed()
|
self.revealOptionsInteractivelyClosed()
|
||||||
}
|
}
|
||||||
case RevealOptionKey.open.rawValue:
|
|
||||||
break
|
|
||||||
case RevealOptionKey.close.rawValue:
|
|
||||||
break
|
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -2688,6 +2684,10 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
switch option.key {
|
switch option.key {
|
||||||
case RevealOptionKey.delete.rawValue:
|
case RevealOptionKey.delete.rawValue:
|
||||||
item.interaction.deletePeerThread(peerId, threadId)
|
item.interaction.deletePeerThread(peerId, threadId)
|
||||||
|
case RevealOptionKey.open.rawValue:
|
||||||
|
break
|
||||||
|
case RevealOptionKey.close.rawValue:
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@ -156,7 +156,7 @@ private func generateRectsImage(color: UIColor, rects: [CGRect], inset: CGFloat,
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class LinkHighlightingNode: ASDisplayNode {
|
public final class LinkHighlightingNode: ASDisplayNode {
|
||||||
private var rects: [CGRect] = []
|
public private(set) var rects: [CGRect] = []
|
||||||
public let imageNode: ASImageNode
|
public let imageNode: ASImageNode
|
||||||
|
|
||||||
public var innerRadius: CGFloat = 4.0
|
public var innerRadius: CGFloat = 4.0
|
||||||
|
|||||||
@ -44,7 +44,7 @@ public class AdditionalLinkItem: ListViewItem, ItemListItem {
|
|||||||
last = true
|
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)
|
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem), firstWithHeader, last)
|
||||||
|
|
||||||
node.contentSize = layout.contentSize
|
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) {
|
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 {
|
Queue.mainQueue().async {
|
||||||
if let nodeValue = node() as? ItemListInviteLinkItemNode {
|
if let nodeValue = node() as? AdditionalLinkItemNode {
|
||||||
let makeLayout = nodeValue.asyncLayout()
|
let makeLayout = nodeValue.asyncLayout()
|
||||||
|
|
||||||
async {
|
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 backgroundNode: ASDisplayNode
|
||||||
private let topStripeNode: ASDisplayNode
|
private let topStripeNode: ASDisplayNode
|
||||||
private let bottomStripeNode: 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))
|
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)
|
let reorderControlNode = reorderControlSizeAndApply.1(layout.contentSize.height, false, .immediate)
|
||||||
strongSelf.reorderControlNode = reorderControlNode
|
strongSelf.reorderControlNode = reorderControlNode
|
||||||
strongSelf.addSubnode(reorderControlNode)
|
strongSelf.addSubnode(reorderControlNode)
|
||||||
reorderControlNode.alpha = 0.0
|
reorderControlNode.alpha = 0.0
|
||||||
transition.updateAlpha(node: reorderControlNode, alpha: 1.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))
|
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
|
strongSelf.reorderControlNode?.frame = reorderControlFrame
|
||||||
|
|
||||||
@ -39,8 +39,10 @@ private final class ChannelVisibilityControllerArguments {
|
|||||||
let toggleForwarding: (Bool) -> Void
|
let toggleForwarding: (Bool) -> Void
|
||||||
let updateJoinToSend: (CurrentChannelJoinToSend) -> Void
|
let updateJoinToSend: (CurrentChannelJoinToSend) -> Void
|
||||||
let toggleApproveMembers: (Bool) -> 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.context = context
|
||||||
self.updateCurrentType = updateCurrentType
|
self.updateCurrentType = updateCurrentType
|
||||||
self.updatePublicLinkText = updatePublicLinkText
|
self.updatePublicLinkText = updatePublicLinkText
|
||||||
@ -55,6 +57,8 @@ private final class ChannelVisibilityControllerArguments {
|
|||||||
self.toggleForwarding = toggleForwarding
|
self.toggleForwarding = toggleForwarding
|
||||||
self.updateJoinToSend = updateJoinToSend
|
self.updateJoinToSend = updateJoinToSend
|
||||||
self.toggleApproveMembers = toggleApproveMembers
|
self.toggleApproveMembers = toggleApproveMembers
|
||||||
|
self.activateLink = activateLink
|
||||||
|
self.deactivateLink = deactivateLink
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,6 +67,7 @@ private enum ChannelVisibilitySection: Int32 {
|
|||||||
case limitInfo
|
case limitInfo
|
||||||
case link
|
case link
|
||||||
case linkActions
|
case linkActions
|
||||||
|
case additional
|
||||||
case joinToSend
|
case joinToSend
|
||||||
case approveMembers
|
case approveMembers
|
||||||
case forwarding
|
case forwarding
|
||||||
@ -81,6 +86,11 @@ private enum ChannelVisibilityEntryTag: ItemListItemTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum ChannelVisibilityEntryId: Hashable {
|
||||||
|
case index(Int32)
|
||||||
|
case username(String)
|
||||||
|
}
|
||||||
|
|
||||||
private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
||||||
case typeHeader(PresentationTheme, String)
|
case typeHeader(PresentationTheme, String)
|
||||||
case typePublic(PresentationTheme, String, Bool)
|
case typePublic(PresentationTheme, String, Bool)
|
||||||
@ -103,6 +113,10 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
|||||||
case existingLinksInfo(PresentationTheme, String)
|
case existingLinksInfo(PresentationTheme, String)
|
||||||
case existingLinkPeerItem(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, Peer, ItemListPeerItemEditing, Bool)
|
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 joinToSendHeader(PresentationTheme, String)
|
||||||
case joinToSendEveryone(PresentationTheme, String, Bool)
|
case joinToSendEveryone(PresentationTheme, String, Bool)
|
||||||
case joinToSendMembers(PresentationTheme, String, Bool)
|
case joinToSendMembers(PresentationTheme, String, Bool)
|
||||||
@ -122,6 +136,8 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
|||||||
return ChannelVisibilitySection.limitInfo.rawValue
|
return ChannelVisibilitySection.limitInfo.rawValue
|
||||||
case .publicLinkHeader, .publicLinkAvailability, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkInfo, .publicLinkStatus:
|
case .publicLinkHeader, .publicLinkAvailability, .privateLinkHeader, .privateLink, .editablePublicLink, .privateLinkInfo, .publicLinkInfo, .publicLinkStatus:
|
||||||
return ChannelVisibilitySection.link.rawValue
|
return ChannelVisibilitySection.link.rawValue
|
||||||
|
case .additionalLinkHeader, .additionalLink, .additionalLinkInfo:
|
||||||
|
return ChannelVisibilitySection.additional.rawValue
|
||||||
case .privateLinkManage, .privateLinkManageInfo:
|
case .privateLinkManage, .privateLinkManageInfo:
|
||||||
return ChannelVisibilitySection.linkActions.rawValue
|
return ChannelVisibilitySection.linkActions.rawValue
|
||||||
case .existingLinksInfo, .existingLinkPeerItem:
|
case .existingLinksInfo, .existingLinkPeerItem:
|
||||||
@ -135,58 +151,64 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var stableId: Int32 {
|
var stableId: ChannelVisibilityEntryId {
|
||||||
switch self {
|
switch self {
|
||||||
case .typeHeader:
|
case .typeHeader:
|
||||||
return 0
|
return .index(0)
|
||||||
case .typePublic:
|
case .typePublic:
|
||||||
return 1
|
return .index(1)
|
||||||
case .typePrivate:
|
case .typePrivate:
|
||||||
return 2
|
return .index(2)
|
||||||
case .typeInfo:
|
case .typeInfo:
|
||||||
return 3
|
return .index(3)
|
||||||
case .publicLinkHeader:
|
case .publicLinkHeader:
|
||||||
return 4
|
return .index(4)
|
||||||
case .publicLinkAvailability:
|
case .publicLinkAvailability:
|
||||||
return 5
|
return .index(5)
|
||||||
case .linksLimitInfo:
|
case .linksLimitInfo:
|
||||||
return 6
|
return .index(6)
|
||||||
case .privateLinkHeader:
|
case .privateLinkHeader:
|
||||||
return 7
|
return .index(7)
|
||||||
case .privateLink:
|
case .privateLink:
|
||||||
return 8
|
return .index(8)
|
||||||
case .editablePublicLink:
|
case .editablePublicLink:
|
||||||
return 9
|
return .index(9)
|
||||||
case .privateLinkInfo:
|
case .privateLinkInfo:
|
||||||
return 10
|
return .index(10)
|
||||||
case .publicLinkStatus:
|
case .publicLinkStatus:
|
||||||
return 11
|
return .index(11)
|
||||||
case .publicLinkInfo:
|
case .publicLinkInfo:
|
||||||
return 12
|
return .index(12)
|
||||||
case .existingLinksInfo:
|
case .existingLinksInfo:
|
||||||
return 13
|
return .index(13)
|
||||||
case let .existingLinkPeerItem(index, _, _, _, _, _, _, _):
|
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:
|
case .privateLinkManage:
|
||||||
return 1000
|
return .index(2001)
|
||||||
case .privateLinkManageInfo:
|
case .privateLinkManageInfo:
|
||||||
return 1001
|
return .index(2002)
|
||||||
case .joinToSendHeader:
|
case .joinToSendHeader:
|
||||||
return 1002
|
return .index(2003)
|
||||||
case .joinToSendEveryone:
|
case .joinToSendEveryone:
|
||||||
return 1003
|
return .index(2004)
|
||||||
case .joinToSendMembers:
|
case .joinToSendMembers:
|
||||||
return 1004
|
return .index(2005)
|
||||||
case .approveMembers:
|
case .approveMembers:
|
||||||
return 1005
|
return .index(2006)
|
||||||
case .approveMembersInfo:
|
case .approveMembersInfo:
|
||||||
return 1006
|
return .index(2007)
|
||||||
case .forwardingHeader:
|
case .forwardingHeader:
|
||||||
return 1007
|
return .index(2008)
|
||||||
case .forwardingDisabled:
|
case .forwardingDisabled:
|
||||||
return 1008
|
return .index(2009)
|
||||||
case .forwardingInfo:
|
case .forwardingInfo:
|
||||||
return 1009
|
return .index(2010)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,6 +256,24 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
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):
|
case let .privateLinkHeader(lhsTheme, lhsTitle):
|
||||||
if case let .privateLinkHeader(rhsTheme, rhsTitle) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle {
|
if case let .privateLinkHeader(rhsTheme, rhsTitle) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle {
|
||||||
return true
|
return true
|
||||||
@ -370,7 +410,206 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static func <(lhs: ChannelVisibilityEntry, rhs: ChannelVisibilityEntry) -> Bool {
|
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 {
|
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
||||||
@ -465,6 +704,20 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
|||||||
}, removePeer: { peerId in
|
}, removePeer: { peerId in
|
||||||
arguments.revokePeerId(peerId)
|
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):
|
case let .joinToSendHeader(_, title):
|
||||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
|
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
|
||||||
case let .joinToSendEveryone(_, text, selected):
|
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] = []
|
var entries: [ChannelVisibilityEntry] = []
|
||||||
|
|
||||||
let isInitialSetup: Bool
|
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 {
|
if case .revokeNames = mode {
|
||||||
let count = Int32(publicChannelsToRevoke?.count ?? 0)
|
let count = Int32(publicChannelsToRevoke?.count ?? 0)
|
||||||
|
|
||||||
@ -821,6 +1076,33 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
|||||||
} else {
|
} else {
|
||||||
entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Channel_Username_CreatePublicLinkHelp))
|
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 {
|
switch mode {
|
||||||
case .initialSetup, .revokeNames:
|
case .initialSetup, .revokeNames:
|
||||||
break
|
break
|
||||||
@ -1110,6 +1392,7 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
var dismissImpl: (() -> Void)?
|
var dismissImpl: (() -> Void)?
|
||||||
|
var dismissInputImpl: (() -> Void)?
|
||||||
var nextImpl: (() -> Void)?
|
var nextImpl: (() -> Void)?
|
||||||
var scrollToPublicLinkTextImpl: (() -> Void)?
|
var scrollToPublicLinkTextImpl: (() -> Void)?
|
||||||
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
||||||
@ -1142,6 +1425,8 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
|||||||
let toggleRequestToJoinDisposable = MetaDisposable()
|
let toggleRequestToJoinDisposable = MetaDisposable()
|
||||||
actionsDisposable.add(toggleRequestToJoinDisposable)
|
actionsDisposable.add(toggleRequestToJoinDisposable)
|
||||||
|
|
||||||
|
let temporaryOrder = Promise<[String]?>(nil)
|
||||||
|
|
||||||
let arguments = ChannelVisibilityControllerArguments(context: context, updateCurrentType: { type in
|
let arguments = ChannelVisibilityControllerArguments(context: context, updateCurrentType: { type in
|
||||||
if type == .publicChannel {
|
if type == .publicChannel {
|
||||||
let _ = combineLatest(
|
let _ = combineLatest(
|
||||||
@ -1363,6 +1648,63 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
|||||||
updateState { state in
|
updateState { state in
|
||||||
return state.withUpdatedApproveMembers(value)
|
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)
|
let peerView = context.account.viewTracker.peerView(peerId)
|
||||||
@ -1370,6 +1712,7 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
|||||||
|
|
||||||
let previousHadNamesToRevoke = Atomic<Bool?>(value: nil)
|
let previousHadNamesToRevoke = Atomic<Bool?>(value: nil)
|
||||||
let previousInvitation = Atomic<ExportedInvitation?>(value: nil)
|
let previousInvitation = Atomic<ExportedInvitation?>(value: nil)
|
||||||
|
let previousUsernames = Atomic<[String]?>(value: nil)
|
||||||
|
|
||||||
let mainLink = context.engine.data.subscribe(
|
let mainLink = context.engine.data.subscribe(
|
||||||
TelegramEngine.EngineData.Item.Peer.ExportedInvitation(id: peerId)
|
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: false),
|
||||||
TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: true),
|
TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: true),
|
||||||
TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)
|
TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)
|
||||||
)
|
),
|
||||||
|
temporaryOrder.get()
|
||||||
)
|
)
|
||||||
|> deliverOnMainQueue
|
|> 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 peer = peerViewMainPeer(view)
|
||||||
|
|
||||||
let (limits, premiumLimits, accountPeer) = data
|
let (limits, premiumLimits, accountPeer) = data
|
||||||
@ -1653,7 +1997,11 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
|||||||
|
|
||||||
let hasNamesToRevoke = publicChannelsToRevoke != nil && !publicChannelsToRevoke!.isEmpty
|
let hasNamesToRevoke = publicChannelsToRevoke != nil && !publicChannelsToRevoke!.isEmpty
|
||||||
let hadNamesToRevoke = previousHadNamesToRevoke.swap(hasNamesToRevoke)
|
let hadNamesToRevoke = previousHadNamesToRevoke.swap(hasNamesToRevoke)
|
||||||
|
|
||||||
if let peer = view.peers[view.peerId] as? TelegramChannel {
|
if let peer = view.peers[view.peerId] as? TelegramChannel {
|
||||||
|
let currentUsernames = peer.usernames.map { $0.username }
|
||||||
|
let previousUsernames = previousUsernames.swap(currentUsernames)
|
||||||
|
|
||||||
let selectedType: CurrentChannelType
|
let selectedType: CurrentChannelType
|
||||||
if case .privateLink = mode {
|
if case .privateLink = mode {
|
||||||
selectedType = .privateChannel
|
selectedType = .privateChannel
|
||||||
@ -1678,6 +2026,10 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
|||||||
if let hadNamesToRevoke = hadNamesToRevoke {
|
if let hadNamesToRevoke = hadNamesToRevoke {
|
||||||
animateChanges = hadNamesToRevoke != hasNamesToRevoke
|
animateChanges = hadNamesToRevoke != hasNamesToRevoke
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if temporaryOrder != nil || previousUsernames != currentUsernames {
|
||||||
|
animateChanges = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let title: String
|
let title: String
|
||||||
@ -1694,7 +2046,7 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
|||||||
title = presentationData.strings.Premium_LimitReached
|
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?
|
var focusItemTag: ItemListItemTag?
|
||||||
if entries.count > 1, let cachedChannelData = view.cachedData as? CachedChannelData, cachedChannelData.peerGeoLocation != nil {
|
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
|
controller.willDisappear = { _ in
|
||||||
dismissTooltipsImpl?()
|
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
|
dismissImpl = { [weak controller, weak onDismissRemoveController] in
|
||||||
guard let controller = controller else {
|
guard let controller = controller else {
|
||||||
return
|
return
|
||||||
@ -1730,6 +2201,9 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
|||||||
controller.dismiss()
|
controller.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
dismissInputImpl = { [weak controller] in
|
||||||
|
controller?.view.endEditing(true)
|
||||||
|
}
|
||||||
nextImpl = { [weak controller] in
|
nextImpl = { [weak controller] in
|
||||||
if let controller = controller {
|
if let controller = controller {
|
||||||
if case .initialSetup = mode {
|
if case .initialSetup = mode {
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import PresentationDataUtils
|
|||||||
import AccountContext
|
import AccountContext
|
||||||
import ShareController
|
import ShareController
|
||||||
import UndoUI
|
import UndoUI
|
||||||
|
import InviteLinksUI
|
||||||
|
|
||||||
private final class UsernameSetupControllerArguments {
|
private final class UsernameSetupControllerArguments {
|
||||||
let account: Account
|
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 {
|
private enum UsernameSetupEntry: ItemListNodeEntry {
|
||||||
case publicLinkHeader(PresentationTheme, String)
|
case publicLinkHeader(PresentationTheme, String)
|
||||||
@ -66,22 +71,22 @@ private enum UsernameSetupEntry: ItemListNodeEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var stableId: Int32 {
|
var stableId: UsernameSetupEntryId {
|
||||||
switch self {
|
switch self {
|
||||||
case .publicLinkHeader:
|
case .publicLinkHeader:
|
||||||
return 0
|
return .index(0)
|
||||||
case .editablePublicLink:
|
case .editablePublicLink:
|
||||||
return 1
|
return .index(1)
|
||||||
case .publicLinkStatus:
|
case .publicLinkStatus:
|
||||||
return 2
|
return .index(2)
|
||||||
case .publicLinkInfo:
|
case .publicLinkInfo:
|
||||||
return 3
|
return .index(3)
|
||||||
case .additionalLinkHeader:
|
case .additionalLinkHeader:
|
||||||
return 4
|
return .index(4)
|
||||||
case let .additionalLink(_, _, index):
|
case let .additionalLink(_, username, _):
|
||||||
return 5 + index
|
return .username(username.username)
|
||||||
case .additionalLinkInfo:
|
case .additionalLinkInfo:
|
||||||
return 1000
|
return .index(5)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +138,57 @@ private enum UsernameSetupEntry: ItemListNodeEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static func <(lhs: UsernameSetupEntry, rhs: UsernameSetupEntry) -> Bool {
|
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 {
|
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
||||||
@ -482,10 +537,32 @@ public func usernameSetupController(context: AccountContext) -> ViewController {
|
|||||||
var referenceId: String?
|
var referenceId: String?
|
||||||
var beforeAll = false
|
var beforeAll = false
|
||||||
var afterAll = 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 {
|
if toIndex < entries.count {
|
||||||
switch entries[toIndex] {
|
switch entries[toIndex] {
|
||||||
case let .additionalLink(_, toUsername, _):
|
case let .additionalLink(_, toUsername, _):
|
||||||
|
if toUsername.flags.contains(.isActive) {
|
||||||
referenceId = toUsername.username
|
referenceId = toUsername.username
|
||||||
|
} else {
|
||||||
|
afterAll = true
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
if entries[toIndex] < fromEntry {
|
if entries[toIndex] < fromEntry {
|
||||||
beforeAll = true
|
beforeAll = true
|
||||||
@ -497,16 +574,6 @@ public func usernameSetupController(context: AccountContext) -> ViewController {
|
|||||||
afterAll = true
|
afterAll = true
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentUsernames: [String] = []
|
|
||||||
for entry in entries {
|
|
||||||
switch entry {
|
|
||||||
case let .additionalLink(_, link, _):
|
|
||||||
currentUsernames.append(link.username)
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var previousIndex: Int?
|
var previousIndex: Int?
|
||||||
for i in 0 ..< currentUsernames.count {
|
for i in 0 ..< currentUsernames.count {
|
||||||
if currentUsernames[i] == fromUsername.username {
|
if currentUsernames[i] == fromUsername.username {
|
||||||
@ -517,7 +584,6 @@ public func usernameSetupController(context: AccountContext) -> ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var didReorder = false
|
var didReorder = false
|
||||||
|
|
||||||
if let referenceId = referenceId {
|
if let referenceId = referenceId {
|
||||||
var inserted = false
|
var inserted = false
|
||||||
for i in 0 ..< currentUsernames.count {
|
for i in 0 ..< currentUsernames.count {
|
||||||
@ -535,15 +601,23 @@ public func usernameSetupController(context: AccountContext) -> ViewController {
|
|||||||
}
|
}
|
||||||
if !inserted {
|
if !inserted {
|
||||||
didReorder = previousIndex != currentUsernames.count
|
didReorder = previousIndex != currentUsernames.count
|
||||||
|
if let maxIndex = maxIndex {
|
||||||
|
currentUsernames.insert(fromUsername.username, at: maxIndex)
|
||||||
|
} else {
|
||||||
currentUsernames.append(fromUsername.username)
|
currentUsernames.append(fromUsername.username)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if beforeAll {
|
} else if beforeAll {
|
||||||
didReorder = previousIndex != 0
|
didReorder = previousIndex != 0
|
||||||
currentUsernames.insert(fromUsername.username, at: 0)
|
currentUsernames.insert(fromUsername.username, at: 0)
|
||||||
} else if afterAll {
|
} else if afterAll {
|
||||||
didReorder = previousIndex != currentUsernames.count
|
didReorder = previousIndex != currentUsernames.count
|
||||||
|
if let maxIndex = maxIndex {
|
||||||
|
currentUsernames.insert(fromUsername.username, at: maxIndex)
|
||||||
|
} else {
|
||||||
currentUsernames.append(fromUsername.username)
|
currentUsernames.append(fromUsername.username)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
temporaryOrder.set(.single(currentUsernames))
|
temporaryOrder.set(.single(currentUsernames))
|
||||||
|
|
||||||
|
|||||||
@ -190,14 +190,40 @@ func _internal_toggleAddressNameActive(account: Account, domain: AddressNameDoma
|
|||||||
var updatedNames = peer.usernames
|
var updatedNames = peer.usernames
|
||||||
if let index = updatedNames.firstIndex(where: { $0.username == name }) {
|
if let index = updatedNames.firstIndex(where: { $0.username == name }) {
|
||||||
var updatedFlags = updatedNames[index].flags
|
var updatedFlags = updatedNames[index].flags
|
||||||
|
var updateOrder = true
|
||||||
|
var updatedIndex = index
|
||||||
if active {
|
if active {
|
||||||
|
if updatedFlags.contains(.isActive) {
|
||||||
|
updateOrder = false
|
||||||
|
}
|
||||||
updatedFlags.insert(.isActive)
|
updatedFlags.insert(.isActive)
|
||||||
} else {
|
} else {
|
||||||
|
if !updatedFlags.contains(.isActive) {
|
||||||
|
updateOrder = false
|
||||||
|
}
|
||||||
updatedFlags.remove(.isActive)
|
updatedFlags.remove(.isActive)
|
||||||
}
|
}
|
||||||
let updatedName = TelegramPeerUsername(flags: updatedFlags, username: name)
|
let updatedName = TelegramPeerUsername(flags: updatedFlags, username: name)
|
||||||
updatedNames.remove(at: index)
|
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)
|
let updatedUser = peer.withUpdatedUsernames(updatedNames)
|
||||||
updatePeers(transaction: transaction, peers: [updatedUser], update: { _, updated in
|
updatePeers(transaction: transaction, peers: [updatedUser], update: { _, updated in
|
||||||
@ -218,14 +244,40 @@ func _internal_toggleAddressNameActive(account: Account, domain: AddressNameDoma
|
|||||||
var updatedNames = peer.usernames
|
var updatedNames = peer.usernames
|
||||||
if let index = updatedNames.firstIndex(where: { $0.username == name }) {
|
if let index = updatedNames.firstIndex(where: { $0.username == name }) {
|
||||||
var updatedFlags = updatedNames[index].flags
|
var updatedFlags = updatedNames[index].flags
|
||||||
|
var updateOrder = true
|
||||||
|
var updatedIndex = index
|
||||||
if active {
|
if active {
|
||||||
|
if updatedFlags.contains(.isActive) {
|
||||||
|
updateOrder = false
|
||||||
|
}
|
||||||
updatedFlags.insert(.isActive)
|
updatedFlags.insert(.isActive)
|
||||||
} else {
|
} else {
|
||||||
|
if !updatedFlags.contains(.isActive) {
|
||||||
|
updateOrder = false
|
||||||
|
}
|
||||||
updatedFlags.remove(.isActive)
|
updatedFlags.remove(.isActive)
|
||||||
}
|
}
|
||||||
let updatedName = TelegramPeerUsername(flags: updatedFlags, username: name)
|
let updatedName = TelegramPeerUsername(flags: updatedFlags, username: name)
|
||||||
updatedNames.remove(at: index)
|
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)
|
let updatedPeer = peer.withUpdatedAddressNames(updatedNames)
|
||||||
updatePeers(transaction: transaction, peers: [updatedPeer], update: { _, updated in
|
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
|
return account.postbox.transaction { transaction -> Signal<Void, ReorderAddressNamesError> in
|
||||||
switch domain {
|
switch domain {
|
||||||
case .account:
|
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
|
|> mapError { _ -> ReorderAddressNamesError in
|
||||||
return .generic
|
return .generic
|
||||||
}
|
}
|
||||||
@ -267,7 +319,7 @@ func _internal_reorderAddressNames(account: Account, domain: AddressNameDomain,
|
|||||||
}
|
}
|
||||||
case let .peer(peerId):
|
case let .peer(peerId):
|
||||||
if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) {
|
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
|
|> mapError { _ -> ReorderAddressNamesError in
|
||||||
return .generic
|
return .generic
|
||||||
}
|
}
|
||||||
|
|||||||
@ -300,6 +300,7 @@ swift_library(
|
|||||||
"//submodules/TelegramUI/Components/ForumTopicListScreen:ForumTopicListScreen",
|
"//submodules/TelegramUI/Components/ForumTopicListScreen:ForumTopicListScreen",
|
||||||
"//submodules/TelegramUI/Components/ForumCreateTopicScreen:ForumCreateTopicScreen",
|
"//submodules/TelegramUI/Components/ForumCreateTopicScreen:ForumCreateTopicScreen",
|
||||||
"//submodules/TelegramUI/Components/ChatTitleView",
|
"//submodules/TelegramUI/Components/ChatTitleView",
|
||||||
|
"//submodules/InviteLinksUI:InviteLinksUI",
|
||||||
] + select({
|
] + select({
|
||||||
"@build_bazel_rules_apple//apple:ios_armv7": [],
|
"@build_bazel_rules_apple//apple:ios_armv7": [],
|
||||||
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
|
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
|
||||||
|
|||||||
@ -3906,7 +3906,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
var animateReplyNodeIn = false
|
var animateReplyNodeIn = false
|
||||||
if (translation.x < -45.0) != (self.currentSwipeToReplyTranslation < -45.0) {
|
if (translation.x < -45.0) != (self.currentSwipeToReplyTranslation < -45.0) {
|
||||||
if translation.x < -45.0, self.swipeToReplyNode == nil, let item = self.item {
|
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))
|
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
|
self.swipeToReplyNode = swipeToReplyNode
|
||||||
|
|||||||
@ -998,7 +998,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
|||||||
var animateReplyNodeIn = false
|
var animateReplyNodeIn = false
|
||||||
if (translation.x < -45.0) != (self.currentSwipeToReplyTranslation < -45.0) {
|
if (translation.x < -45.0) != (self.currentSwipeToReplyTranslation < -45.0) {
|
||||||
if translation.x < -45.0, self.swipeToReplyNode == nil, let item = self.item {
|
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))
|
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
|
self.swipeToReplyNode = swipeToReplyNode
|
||||||
|
|||||||
@ -1250,7 +1250,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
|||||||
var animateReplyNodeIn = false
|
var animateReplyNodeIn = false
|
||||||
if (translation.x < -45.0) != (self.currentSwipeToReplyTranslation < -45.0) {
|
if (translation.x < -45.0) != (self.currentSwipeToReplyTranslation < -45.0) {
|
||||||
if translation.x < -45.0, self.swipeToReplyNode == nil, let item = self.item {
|
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))
|
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
|
self.swipeToReplyNode = swipeToReplyNode
|
||||||
|
|||||||
@ -578,7 +578,7 @@ final class ChatQrCodeScreen: ViewController {
|
|||||||
} else {
|
} else {
|
||||||
result = "t_me-\(Int32.random(in: 0 ..< Int32.max))"
|
result = "t_me-\(Int32.random(in: 0 ..< Int32.max))"
|
||||||
}
|
}
|
||||||
if let threadId = threadId {
|
if let threadId = threadId, threadId != 0 {
|
||||||
result.append("-\(threadId)")
|
result.append("-\(threadId)")
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
@ -1519,7 +1519,7 @@ private class QrContentNode: ASDisplayNode, ContentNode {
|
|||||||
} else {
|
} else {
|
||||||
codeText = peer.debugDisplayTitle.uppercased()
|
codeText = peer.debugDisplayTitle.uppercased()
|
||||||
}
|
}
|
||||||
if let threadId = self.threadId {
|
if let threadId = self.threadId, threadId != 0 {
|
||||||
codeText += "/\(threadId)"
|
codeText += "/\(threadId)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@ final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem {
|
|||||||
let icon: PeerInfoScreenLabeledValueIcon?
|
let icon: PeerInfoScreenLabeledValueIcon?
|
||||||
let action: ((ASDisplayNode) -> Void)?
|
let action: ((ASDisplayNode) -> Void)?
|
||||||
let longTapAction: ((ASDisplayNode) -> Void)?
|
let longTapAction: ((ASDisplayNode) -> Void)?
|
||||||
let linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)?
|
let linkItemAction: ((TextLinkItemActionType, TextLinkItem, ASDisplayNode, CGRect?) -> Void)?
|
||||||
let iconAction: (() -> Void)?
|
let iconAction: (() -> Void)?
|
||||||
let contextAction: ((ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?
|
let contextAction: ((ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?
|
||||||
let requestLayout: () -> Void
|
let requestLayout: () -> Void
|
||||||
@ -47,7 +47,7 @@ final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem {
|
|||||||
icon: PeerInfoScreenLabeledValueIcon? = nil,
|
icon: PeerInfoScreenLabeledValueIcon? = nil,
|
||||||
action: ((ASDisplayNode) -> Void)?,
|
action: ((ASDisplayNode) -> Void)?,
|
||||||
longTapAction: ((ASDisplayNode) -> Void)? = nil,
|
longTapAction: ((ASDisplayNode) -> Void)? = nil,
|
||||||
linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)? = nil,
|
linkItemAction: ((TextLinkItemActionType, TextLinkItem, ASDisplayNode, CGRect?) -> Void)? = nil,
|
||||||
iconAction: (() -> Void)? = nil,
|
iconAction: (() -> Void)? = nil,
|
||||||
contextAction: ((ASDisplayNode, ContextGesture?, CGPoint?) -> Void)? = nil,
|
contextAction: ((ASDisplayNode, ContextGesture?, CGPoint?) -> Void)? = nil,
|
||||||
requestLayout: @escaping () -> Void
|
requestLayout: @escaping () -> Void
|
||||||
@ -313,7 +313,7 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
|||||||
case .tap, .longTap:
|
case .tap, .longTap:
|
||||||
if let item = self.item {
|
if let item = self.item {
|
||||||
if let linkItem = self.linkItemAtPoint(location) {
|
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 {
|
} else if case .longTap = gesture {
|
||||||
item.longTapAction?(self)
|
item.longTapAction?(self)
|
||||||
} else if case .tap = gesture {
|
} else if case .tap = gesture {
|
||||||
@ -601,7 +601,8 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
|||||||
}
|
}
|
||||||
if textNode == nil {
|
if textNode == nil {
|
||||||
let additionalTextNodeFrame = self.additionalTextNode.frame
|
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] = [
|
let possibleNames: [String] = [
|
||||||
TelegramTextAttributes.URL,
|
TelegramTextAttributes.URL,
|
||||||
TelegramTextAttributes.PeerMention,
|
TelegramTextAttributes.PeerMention,
|
||||||
|
|||||||
@ -488,7 +488,7 @@ private final class PeerInfoInteraction {
|
|||||||
let editingOpenSetupLocation: () -> Void
|
let editingOpenSetupLocation: () -> Void
|
||||||
let openPeerInfo: (Peer, Bool) -> Void
|
let openPeerInfo: (Peer, Bool) -> Void
|
||||||
let performMemberAction: (PeerInfoMember, PeerInfoMemberAction) -> Void
|
let performMemberAction: (PeerInfoMember, PeerInfoMemberAction) -> Void
|
||||||
let openPeerInfoContextMenu: (PeerInfoContextSubject, ASDisplayNode) -> Void
|
let openPeerInfoContextMenu: (PeerInfoContextSubject, ASDisplayNode, CGRect?) -> Void
|
||||||
let performBioLinkAction: (TextLinkItemActionType, TextLinkItem) -> Void
|
let performBioLinkAction: (TextLinkItemActionType, TextLinkItem) -> Void
|
||||||
let requestLayout: (Bool) -> Void
|
let requestLayout: (Bool) -> Void
|
||||||
let openEncryptionKey: () -> Void
|
let openEncryptionKey: () -> Void
|
||||||
@ -533,7 +533,7 @@ private final class PeerInfoInteraction {
|
|||||||
editingOpenSetupLocation: @escaping () -> Void,
|
editingOpenSetupLocation: @escaping () -> Void,
|
||||||
openPeerInfo: @escaping (Peer, Bool) -> Void,
|
openPeerInfo: @escaping (Peer, Bool) -> Void,
|
||||||
performMemberAction: @escaping (PeerInfoMember, PeerInfoMemberAction) -> Void,
|
performMemberAction: @escaping (PeerInfoMember, PeerInfoMemberAction) -> Void,
|
||||||
openPeerInfoContextMenu: @escaping (PeerInfoContextSubject, ASDisplayNode) -> Void,
|
openPeerInfoContextMenu: @escaping (PeerInfoContextSubject, ASDisplayNode, CGRect?) -> Void,
|
||||||
performBioLinkAction: @escaping (TextLinkItemActionType, TextLinkItem) -> Void,
|
performBioLinkAction: @escaping (TextLinkItemActionType, TextLinkItem) -> Void,
|
||||||
requestLayout: @escaping (Bool) -> Void,
|
requestLayout: @escaping (Bool) -> Void,
|
||||||
openEncryptionKey: @escaping () -> Void,
|
openEncryptionKey: @escaping () -> Void,
|
||||||
@ -934,9 +934,9 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
}
|
}
|
||||||
|
|
||||||
let bioContextAction: (ASDisplayNode) -> Void = { sourceNode in
|
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)
|
interaction.performBioLinkAction(action, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -974,8 +974,8 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
action: { _ in
|
action: { _ in
|
||||||
interaction.openUsername(username)
|
interaction.openUsername(username)
|
||||||
}, longTapAction: { sourceNode in
|
}, longTapAction: { sourceNode in
|
||||||
interaction.openPeerInfoContextMenu(.link(customLink: nil), sourceNode)
|
interaction.openPeerInfoContextMenu(.link(customLink: nil), sourceNode, nil)
|
||||||
}, linkItemAction: { type, item in
|
}, linkItemAction: { type, item, _, _ in
|
||||||
if case .tap = type {
|
if case .tap = type {
|
||||||
if case let .mention(username) = item {
|
if case let .mention(username) = item {
|
||||||
interaction.openUsername(String(username[username.index(username.startIndex, offsetBy: 1)...]))
|
interaction.openUsername(String(username[username.index(username.startIndex, offsetBy: 1)...]))
|
||||||
@ -1103,8 +1103,8 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
action: { _ in
|
action: { _ in
|
||||||
interaction.openUsername(linkText)
|
interaction.openUsername(linkText)
|
||||||
}, longTapAction: { sourceNode in
|
}, longTapAction: { sourceNode in
|
||||||
interaction.openPeerInfoContextMenu(.link(customLink: linkText), sourceNode)
|
interaction.openPeerInfoContextMenu(.link(customLink: linkText), sourceNode, nil)
|
||||||
}, linkItemAction: { type, item in
|
}, linkItemAction: { type, item, _, _ in
|
||||||
if case .tap = type {
|
if case .tap = type {
|
||||||
if case let .mention(username) = item {
|
if case let .mention(username) = item {
|
||||||
interaction.openUsername(String(username.suffix(from: username.index(username.startIndex, offsetBy: 1))))
|
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
|
action: { _ in
|
||||||
interaction.openUsername(username)
|
interaction.openUsername(username)
|
||||||
}, longTapAction: { sourceNode in
|
}, longTapAction: { sourceNode in
|
||||||
interaction.openPeerInfoContextMenu(.link(customLink: nil), sourceNode)
|
interaction.openPeerInfoContextMenu(.link(customLink: nil), sourceNode, nil)
|
||||||
}, linkItemAction: { type, item in
|
}, linkItemAction: { type, item, sourceNode, sourceRect in
|
||||||
if case .tap = type {
|
if case .tap = type {
|
||||||
if case let .mention(username) = item {
|
if case let .mention(username) = item {
|
||||||
interaction.openUsername(String(username.suffix(from: username.index(username.startIndex, offsetBy: 1))))
|
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: {
|
}, iconAction: {
|
||||||
interaction.openQrCode()
|
interaction.openQrCode()
|
||||||
@ -1987,8 +1991,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
performMemberAction: { [weak self] member, action in
|
performMemberAction: { [weak self] member, action in
|
||||||
self?.performMemberAction(member: member, action: action)
|
self?.performMemberAction(member: member, action: action)
|
||||||
},
|
},
|
||||||
openPeerInfoContextMenu: { [weak self] subject, sourceNode in
|
openPeerInfoContextMenu: { [weak self] subject, sourceNode, sourceRect in
|
||||||
self?.openPeerInfoContextMenu(subject: subject, sourceNode: sourceNode)
|
self?.openPeerInfoContextMenu(subject: subject, sourceNode: sourceNode, sourceRect: sourceRect)
|
||||||
},
|
},
|
||||||
performBioLinkAction: { [weak self] action, item in
|
performBioLinkAction: { [weak self] action, item in
|
||||||
self?.performBioLinkAction(action: action, item: item)
|
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 {
|
guard let data = self.data, let peer = data.peer, let controller = self.controller else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -6144,7 +6148,11 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
let contextMenuController = ContextMenuController(actions: actions)
|
let contextMenuController = ContextMenuController(actions: actions)
|
||||||
controller.present(contextMenuController, in: .window(.root), with: ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self, weak sourceNode] in
|
controller.present(contextMenuController, in: .window(.root), with: ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self, weak sourceNode] in
|
||||||
if let controller = self?.controller, let sourceNode = sourceNode {
|
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 {
|
} else {
|
||||||
return nil
|
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
|
controller.present(contextMenuController, in: .window(.root), with: ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self, weak sourceNode] in
|
||||||
if let controller = self?.controller, let sourceNode = sourceNode {
|
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 {
|
} else {
|
||||||
return nil
|
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
|
controller.present(contextMenuController, in: .window(.root), with: ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self, weak sourceNode] in
|
||||||
if let controller = self?.controller, let sourceNode = sourceNode {
|
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 {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user