Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Mike Renoir 2022-10-11 11:25:12 +04:00
commit 6c73f79acf
14 changed files with 737 additions and 97 deletions

View File

@ -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";

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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
@ -368,9 +408,208 @@ 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 {

View File

@ -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, _):
referenceId = toUsername.username
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,18 +601,26 @@ public func usernameSetupController(context: AccountContext) -> ViewController {
}
if !inserted {
didReorder = previousIndex != currentUsernames.count
currentUsernames.append(fromUsername.username)
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
currentUsernames.append(fromUsername.username)
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?()

View File

@ -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
}

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)"
}

View File

@ -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,

View File

@ -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
}