mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-02 00:17:02 +00:00
Merge commit '0b1e72044aeb8a1286d90bb0ac5d61cf6e4c13d9'
This commit is contained in:
commit
b13a0e9a06
@ -5922,6 +5922,8 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"Conversation.ImportedMessageHint" = "The messages was imported from another app. We can't guarantee it's real.";
|
"Conversation.ImportedMessageHint" = "The messages was imported from another app. We can't guarantee it's real.";
|
||||||
|
|
||||||
|
"Conversation.GreetingText" = "Send a message or tap on the greeting below.";
|
||||||
|
|
||||||
"CallList.DeleteAllForMe" = "Delete for me";
|
"CallList.DeleteAllForMe" = "Delete for me";
|
||||||
"CallList.DeleteAllForEveryone" = "Delete for me and Others";
|
"CallList.DeleteAllForEveryone" = "Delete for me and Others";
|
||||||
"Conversation.ImportProgress" = "Importing Messages... %@%";
|
"Conversation.ImportProgress" = "Importing Messages... %@%";
|
||||||
|
@ -583,7 +583,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
strongSelf.deletePeerChat(peerId: peerId, joined: joined)
|
strongSelf.deletePeerChat(peerId: peerId, joined: joined)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.chatListDisplayNode.containerNode.peerSelected = { [weak self] peer, animated, promoInfo in
|
self.chatListDisplayNode.containerNode.peerSelected = { [weak self] peer, animated, activateInput, promoInfo in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let navigationController = strongSelf.navigationController as? NavigationController {
|
if let navigationController = strongSelf.navigationController as? NavigationController {
|
||||||
var scrollToEndIfExists = false
|
var scrollToEndIfExists = false
|
||||||
@ -591,7 +591,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
scrollToEndIfExists = true
|
scrollToEndIfExists = true
|
||||||
}
|
}
|
||||||
|
|
||||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id), scrollToEndIfExists: scrollToEndIfExists, animated: !scrollToEndIfExists, options: strongSelf.groupId == PeerGroupId.root ? [.removeOnMasterDetails] : [], parentGroupId: strongSelf.groupId, completion: { [weak self] controller in
|
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id), activateInput: activateInput, scrollToEndIfExists: scrollToEndIfExists, animated: !scrollToEndIfExists, options: strongSelf.groupId == PeerGroupId.root ? [.removeOnMasterDetails] : [], parentGroupId: strongSelf.groupId, completion: { [weak self] controller in
|
||||||
self?.chatListDisplayNode.containerNode.currentItemNode.clearHighlightAnimated(true)
|
self?.chatListDisplayNode.containerNode.currentItemNode.clearHighlightAnimated(true)
|
||||||
if let promoInfo = promoInfo {
|
if let promoInfo = promoInfo {
|
||||||
switch promoInfo {
|
switch promoInfo {
|
||||||
|
@ -475,8 +475,8 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
itemNode.listNode.deletePeerChat = { [weak self] peerId, joined in
|
itemNode.listNode.deletePeerChat = { [weak self] peerId, joined in
|
||||||
self?.deletePeerChat?(peerId, joined)
|
self?.deletePeerChat?(peerId, joined)
|
||||||
}
|
}
|
||||||
itemNode.listNode.peerSelected = { [weak self] peerId, a, b in
|
itemNode.listNode.peerSelected = { [weak self] peerId, animated, activateInput, promoInfo in
|
||||||
self?.peerSelected?(peerId, a, b)
|
self?.peerSelected?(peerId, animated, activateInput, promoInfo)
|
||||||
}
|
}
|
||||||
itemNode.listNode.groupSelected = { [weak self] groupId in
|
itemNode.listNode.groupSelected = { [weak self] groupId in
|
||||||
self?.groupSelected?(groupId)
|
self?.groupSelected?(groupId)
|
||||||
@ -522,7 +522,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
var toggleArchivedFolderHiddenByDefault: (() -> Void)?
|
var toggleArchivedFolderHiddenByDefault: (() -> Void)?
|
||||||
var hidePsa: ((PeerId) -> Void)?
|
var hidePsa: ((PeerId) -> Void)?
|
||||||
var deletePeerChat: ((PeerId, Bool) -> Void)?
|
var deletePeerChat: ((PeerId, Bool) -> Void)?
|
||||||
var peerSelected: ((Peer, Bool, ChatListNodeEntryPromoInfo?) -> Void)?
|
var peerSelected: ((Peer, Bool, Bool, ChatListNodeEntryPromoInfo?) -> Void)?
|
||||||
var groupSelected: ((PeerGroupId) -> Void)?
|
var groupSelected: ((PeerGroupId) -> Void)?
|
||||||
var updatePeerGrouping: ((PeerId, Bool) -> Void)?
|
var updatePeerGrouping: ((PeerId, Bool) -> Void)?
|
||||||
var contentOffsetChanged: ((ListViewVisibleContentOffset) -> Void)?
|
var contentOffsetChanged: ((ListViewVisibleContentOffset) -> Void)?
|
||||||
|
@ -440,7 +440,7 @@ public final class ChatListNode: ListView {
|
|||||||
return _contentsReady.get()
|
return _contentsReady.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
public var peerSelected: ((Peer, Bool, ChatListNodeEntryPromoInfo?) -> Void)?
|
public var peerSelected: ((Peer, Bool, Bool, ChatListNodeEntryPromoInfo?) -> Void)?
|
||||||
public var disabledPeerSelected: ((Peer) -> Void)?
|
public var disabledPeerSelected: ((Peer) -> Void)?
|
||||||
public var additionalCategorySelected: ((Int) -> Void)?
|
public var additionalCategorySelected: ((Int) -> Void)?
|
||||||
public var groupSelected: ((PeerGroupId) -> Void)?
|
public var groupSelected: ((PeerGroupId) -> Void)?
|
||||||
@ -565,7 +565,7 @@ public final class ChatListNode: ListView {
|
|||||||
}
|
}
|
||||||
}, peerSelected: { [weak self] peer, promoInfo in
|
}, peerSelected: { [weak self] peer, promoInfo in
|
||||||
if let strongSelf = self, let peerSelected = strongSelf.peerSelected {
|
if let strongSelf = self, let peerSelected = strongSelf.peerSelected {
|
||||||
peerSelected(peer, true, promoInfo)
|
peerSelected(peer, true, true, promoInfo)
|
||||||
}
|
}
|
||||||
}, disabledPeerSelected: { [weak self] peer in
|
}, disabledPeerSelected: { [weak self] peer in
|
||||||
if let strongSelf = self, let disabledPeerSelected = strongSelf.disabledPeerSelected {
|
if let strongSelf = self, let disabledPeerSelected = strongSelf.disabledPeerSelected {
|
||||||
@ -594,7 +594,18 @@ public final class ChatListNode: ListView {
|
|||||||
self?.additionalCategorySelected?(id)
|
self?.additionalCategorySelected?(id)
|
||||||
}, messageSelected: { [weak self] peer, message, promoInfo in
|
}, messageSelected: { [weak self] peer, message, promoInfo in
|
||||||
if let strongSelf = self, let peerSelected = strongSelf.peerSelected {
|
if let strongSelf = self, let peerSelected = strongSelf.peerSelected {
|
||||||
peerSelected(peer, true, promoInfo)
|
var activateInput = false
|
||||||
|
for media in message.media {
|
||||||
|
if let action = media as? TelegramMediaAction {
|
||||||
|
switch action.action {
|
||||||
|
case .peerJoined, .groupCreated, .channelMigratedFromGroup, .historyCleared:
|
||||||
|
activateInput = true
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
peerSelected(peer, true, activateInput, promoInfo)
|
||||||
}
|
}
|
||||||
}, groupSelected: { [weak self] groupId in
|
}, groupSelected: { [weak self] groupId in
|
||||||
if let strongSelf = self, let groupSelected = strongSelf.groupSelected {
|
if let strongSelf = self, let groupSelected = strongSelf.groupSelected {
|
||||||
@ -1750,7 +1761,7 @@ public final class ChatListNode: ListView {
|
|||||||
}
|
}
|
||||||
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: strongSelf.currentlyVisibleLatestChatListIndex() ?? .absoluteUpperBound, scrollPosition: .center(.top), animated: true, filter: strongSelf.chatListFilter)
|
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: strongSelf.currentlyVisibleLatestChatListIndex() ?? .absoluteUpperBound, scrollPosition: .center(.top), animated: true, filter: strongSelf.chatListFilter)
|
||||||
strongSelf.setChatListLocation(location)
|
strongSelf.setChatListLocation(location)
|
||||||
strongSelf.peerSelected?(peer, false, nil)
|
strongSelf.peerSelected?(peer, false, false, nil)
|
||||||
})
|
})
|
||||||
case .previous(unread: false), .next(unread: false):
|
case .previous(unread: false), .next(unread: false):
|
||||||
var target: (ChatListIndex, Peer)? = nil
|
var target: (ChatListIndex, Peer)? = nil
|
||||||
@ -1774,7 +1785,7 @@ public final class ChatListNode: ListView {
|
|||||||
if let target = target {
|
if let target = target {
|
||||||
let location: ChatListNodeLocation = .scroll(index: target.0, sourceIndex: .absoluteLowerBound, scrollPosition: .center(.top), animated: true, filter: self.chatListFilter)
|
let location: ChatListNodeLocation = .scroll(index: target.0, sourceIndex: .absoluteLowerBound, scrollPosition: .center(.top), animated: true, filter: self.chatListFilter)
|
||||||
self.setChatListLocation(location)
|
self.setChatListLocation(location)
|
||||||
self.peerSelected?(target.1, false, nil)
|
self.peerSelected?(target.1, false, false, nil)
|
||||||
}
|
}
|
||||||
case let .peerId(peerId):
|
case let .peerId(peerId):
|
||||||
let _ = (self.context.account.postbox.transaction { transaction -> Peer? in
|
let _ = (self.context.account.postbox.transaction { transaction -> Peer? in
|
||||||
@ -1784,7 +1795,7 @@ public final class ChatListNode: ListView {
|
|||||||
guard let strongSelf = self, let peer = peer else {
|
guard let strongSelf = self, let peer = peer else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.peerSelected?(peer, false, nil)
|
strongSelf.peerSelected?(peer, false, false, nil)
|
||||||
})
|
})
|
||||||
case let .index(index):
|
case let .index(index):
|
||||||
guard index < 10 else {
|
guard index < 10 else {
|
||||||
@ -1803,7 +1814,7 @@ public final class ChatListNode: ListView {
|
|||||||
if entries.count > index, case let .MessageEntry(index, _, _, _, _, renderedPeer, _, _, _, _) = entries[10 - index - 1] {
|
if entries.count > index, case let .MessageEntry(index, _, _, _, _, renderedPeer, _, _, _, _) = entries[10 - index - 1] {
|
||||||
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: .absoluteLowerBound, scrollPosition: .center(.top), animated: true, filter: filter)
|
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: .absoluteLowerBound, scrollPosition: .center(.top), animated: true, filter: filter)
|
||||||
self.setChatListLocation(location)
|
self.setChatListLocation(location)
|
||||||
self.peerSelected?(renderedPeer.peer!, false, nil)
|
self.peerSelected?(renderedPeer.peer!, false, false, nil)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -352,16 +352,16 @@ public final class InviteLinkInviteController: ViewController {
|
|||||||
}
|
}
|
||||||
})))
|
})))
|
||||||
|
|
||||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in
|
// items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor)
|
// return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor)
|
||||||
}, action: { _, f in
|
// }, action: { _, f in
|
||||||
f(.dismissWithoutContent)
|
// f(.dismissWithoutContent)
|
||||||
|
//
|
||||||
if let invite = invite {
|
// if let invite = invite {
|
||||||
let controller = InviteLinkQRCodeController(context: context, invite: invite)
|
// let controller = InviteLinkQRCodeController(context: context, invite: invite)
|
||||||
self?.controller?.present(controller, in: .window(.root))
|
// self?.controller?.present(controller, in: .window(.root))
|
||||||
}
|
// }
|
||||||
})))
|
// })))
|
||||||
|
|
||||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextRevoke, textColor: .destructive, icon: { theme in
|
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextRevoke, textColor: .destructive, icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor)
|
||||||
@ -407,7 +407,8 @@ public final class InviteLinkInviteController: ViewController {
|
|||||||
let previousEntries = Atomic<[InviteLinkInviteEntry]?>(value: nil)
|
let previousEntries = Atomic<[InviteLinkInviteEntry]?>(value: nil)
|
||||||
|
|
||||||
let peerView = context.account.postbox.peerView(id: peerId)
|
let peerView = context.account.postbox.peerView(id: peerId)
|
||||||
self.disposable = (combineLatest(self.presentationDataPromise.get(), peerView, self.invitesContext.state)
|
let invites: Signal<PeerExportedInvitationsState, NoError> = .single(PeerExportedInvitationsState())
|
||||||
|
self.disposable = (combineLatest(self.presentationDataPromise.get(), peerView, invites)
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData, view, invites in
|
|> deliverOnMainQueue).start(next: { [weak self] presentationData, view, invites in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
var entries: [InviteLinkInviteEntry] = []
|
var entries: [InviteLinkInviteEntry] = []
|
||||||
@ -426,19 +427,19 @@ public final class InviteLinkInviteController: ViewController {
|
|||||||
entries.append(.mainLink(presentationData.theme, mainInvite))
|
entries.append(.mainLink(presentationData.theme, mainInvite))
|
||||||
}
|
}
|
||||||
|
|
||||||
let additionalInvites = invites.invitations.filter { $0.link != mainInvite?.link }
|
// let additionalInvites = invites.invitations.filter { $0.link != mainInvite?.link }
|
||||||
var index: Int32 = 0
|
// var index: Int32 = 0
|
||||||
for i in stride(from: 0, to: additionalInvites.endIndex, by: 2) {
|
// for i in stride(from: 0, to: additionalInvites.endIndex, by: 2) {
|
||||||
var invitesPair: [ExportedInvitation] = []
|
// var invitesPair: [ExportedInvitation] = []
|
||||||
invitesPair.append(additionalInvites[i])
|
// invitesPair.append(additionalInvites[i])
|
||||||
if i + 1 < additionalInvites.count {
|
// if i + 1 < additionalInvites.count {
|
||||||
invitesPair.append(additionalInvites[i + 1])
|
// invitesPair.append(additionalInvites[i + 1])
|
||||||
}
|
// }
|
||||||
entries.append(.links(index, presentationData.theme, invitesPair))
|
// entries.append(.links(index, presentationData.theme, invitesPair))
|
||||||
index += 1
|
// index += 1
|
||||||
}
|
// }
|
||||||
|
|
||||||
entries.append(.manage(presentationData.theme, presentationData.strings.InviteLink_Manage, additionalInvites.isEmpty))
|
// entries.append(.manage(presentationData.theme, presentationData.strings.InviteLink_Manage, additionalInvites.isEmpty))
|
||||||
|
|
||||||
let previousEntries = previousEntries.swap(entries)
|
let previousEntries = previousEntries.swap(entries)
|
||||||
|
|
||||||
@ -467,7 +468,6 @@ public final class InviteLinkInviteController: ViewController {
|
|||||||
self.contentNode.addSubnode(self.headerNode)
|
self.contentNode.addSubnode(self.headerNode)
|
||||||
|
|
||||||
self.headerNode.addSubnode(self.headerBackgroundNode)
|
self.headerNode.addSubnode(self.headerBackgroundNode)
|
||||||
// self.headerNode.addSubnode(self.titleNode)
|
|
||||||
self.headerNode.addSubnode(self.doneButton)
|
self.headerNode.addSubnode(self.doneButton)
|
||||||
|
|
||||||
self.doneButton.addTarget(self, action: #selector(self.doneButtonPressed), forControlEvents: .touchUpInside)
|
self.doneButton.addTarget(self, action: #selector(self.doneButtonPressed), forControlEvents: .touchUpInside)
|
||||||
|
@ -53,23 +53,6 @@ private enum InviteLinkViewEntryId: Hashable {
|
|||||||
case importer(PeerId)
|
case importer(PeerId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func color(for invite: ExportedInvitation) -> UIColor? {
|
|
||||||
let color: UIColor?
|
|
||||||
let availability = invitationAvailability(invite)
|
|
||||||
if invite.isRevoked {
|
|
||||||
color = nil
|
|
||||||
} else if invite.expireDate == nil && invite.usageLimit == nil {
|
|
||||||
color = nil
|
|
||||||
} else if availability >= 0.5 {
|
|
||||||
color = UIColor(rgb: 0x4aca62)
|
|
||||||
} else if availability > 0.0 {
|
|
||||||
color = UIColor(rgb: 0xf8a953)
|
|
||||||
} else {
|
|
||||||
color = UIColor(rgb: 0xf2656a)
|
|
||||||
}
|
|
||||||
return color
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum InviteLinkViewEntry: Comparable, Identifiable {
|
private enum InviteLinkViewEntry: Comparable, Identifiable {
|
||||||
case link(PresentationTheme, ExportedInvitation)
|
case link(PresentationTheme, ExportedInvitation)
|
||||||
case creatorHeader(PresentationTheme, String)
|
case creatorHeader(PresentationTheme, String)
|
||||||
@ -170,9 +153,8 @@ private enum InviteLinkViewEntry: Comparable, Identifiable {
|
|||||||
func item(account: Account, presentationData: PresentationData, interaction: InviteLinkViewInteraction) -> ListViewItem {
|
func item(account: Account, presentationData: PresentationData, interaction: InviteLinkViewInteraction) -> ListViewItem {
|
||||||
switch self {
|
switch self {
|
||||||
case let .link(_, invite):
|
case let .link(_, invite):
|
||||||
let buttonColor = color(for: invite)
|
|
||||||
let availability = invitationAvailability(invite)
|
let availability = invitationAvailability(invite)
|
||||||
return ItemListPermanentInviteLinkItem(context: interaction.context, presentationData: ItemListPresentationData(presentationData), invite: invite, count: 0, peers: [], displayButton: !invite.isRevoked && !availability.isZero, displayImporters: false, buttonColor: buttonColor, sectionId: 0, style: .plain, copyAction: {
|
return ItemListPermanentInviteLinkItem(context: interaction.context, presentationData: ItemListPresentationData(presentationData), invite: invite, count: 0, peers: [], displayButton: !invite.isRevoked && !availability.isZero, displayImporters: false, buttonColor: nil, sectionId: 0, style: .plain, copyAction: {
|
||||||
interaction.copyLink(invite)
|
interaction.copyLink(invite)
|
||||||
}, shareAction: {
|
}, shareAction: {
|
||||||
interaction.shareLink(invite)
|
interaction.shareLink(invite)
|
||||||
@ -383,13 +365,13 @@ public final class InviteLinkViewController: ViewController {
|
|||||||
self.subtitleNode.maximumNumberOfLines = 1
|
self.subtitleNode.maximumNumberOfLines = 1
|
||||||
self.subtitleNode.textAlignment = .center
|
self.subtitleNode.textAlignment = .center
|
||||||
|
|
||||||
let buttonColor = color(for: invite) ?? presentationData.theme.actionSheet.controlAccentColor
|
let accentColor = presentationData.theme.actionSheet.controlAccentColor
|
||||||
|
|
||||||
self.editButton = HighlightableButtonNode()
|
self.editButton = HighlightableButtonNode()
|
||||||
self.editButton.setTitle(self.presentationData.strings.Common_Edit, with: Font.regular(17.0), with: buttonColor, for: .normal)
|
self.editButton.setTitle(self.presentationData.strings.Common_Edit, with: Font.regular(17.0), with: accentColor, for: .normal)
|
||||||
|
|
||||||
self.doneButton = HighlightableButtonNode()
|
self.doneButton = HighlightableButtonNode()
|
||||||
self.doneButton.setTitle(self.presentationData.strings.Common_Done, with: Font.bold(17.0), with: buttonColor, for: .normal)
|
self.doneButton.setTitle(self.presentationData.strings.Common_Done, with: Font.bold(17.0), with: accentColor, for: .normal)
|
||||||
|
|
||||||
self.historyBackgroundNode = ASDisplayNode()
|
self.historyBackgroundNode = ASDisplayNode()
|
||||||
self.historyBackgroundNode.isLayerBacked = true
|
self.historyBackgroundNode.isLayerBacked = true
|
||||||
@ -617,9 +599,9 @@ public final class InviteLinkViewController: ViewController {
|
|||||||
self.titleNode.attributedText = NSAttributedString(string: self.presentationData.strings.InviteLink_InviteLink, font: titleFont, textColor: self.presentationData.theme.actionSheet.primaryTextColor)
|
self.titleNode.attributedText = NSAttributedString(string: self.presentationData.strings.InviteLink_InviteLink, font: titleFont, textColor: self.presentationData.theme.actionSheet.primaryTextColor)
|
||||||
self.subtitleNode.attributedText = NSAttributedString(string: self.subtitleNode.attributedText?.string ?? "", font: subtitleFont, textColor: self.presentationData.theme.list.itemSecondaryTextColor)
|
self.subtitleNode.attributedText = NSAttributedString(string: self.subtitleNode.attributedText?.string ?? "", font: subtitleFont, textColor: self.presentationData.theme.list.itemSecondaryTextColor)
|
||||||
|
|
||||||
let buttonColor = color(for: invite) ?? self.presentationData.theme.actionSheet.controlAccentColor
|
let accentColor = self.presentationData.theme.actionSheet.controlAccentColor
|
||||||
self.editButton.setTitle(self.presentationData.strings.Common_Edit, with: Font.regular(17.0), with: buttonColor, for: .normal)
|
self.editButton.setTitle(self.presentationData.strings.Common_Edit, with: Font.regular(17.0), with: accentColor, for: .normal)
|
||||||
self.doneButton.setTitle(self.presentationData.strings.Common_Done, with: Font.bold(17.0), with: buttonColor, for: .normal)
|
self.doneButton.setTitle(self.presentationData.strings.Common_Done, with: Font.bold(17.0), with: accentColor, for: .normal)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func enqueueTransition(_ transition: InviteLinkViewTransaction) {
|
private func enqueueTransition(_ transition: InviteLinkViewTransaction) {
|
||||||
|
@ -218,17 +218,29 @@ private class ItemNode: ASDisplayNode {
|
|||||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||||
|
|
||||||
let availability = invitationAvailability(invite)
|
let availability = invitationAvailability(invite)
|
||||||
|
let transitionFraction: CGFloat
|
||||||
let color: ItemBackgroundColor
|
let color: ItemBackgroundColor
|
||||||
|
let nextColor: ItemBackgroundColor
|
||||||
if invite.isRevoked {
|
if invite.isRevoked {
|
||||||
color = .gray
|
color = .gray
|
||||||
|
nextColor = .gray
|
||||||
|
transitionFraction = 0.0
|
||||||
} else if invite.expireDate == nil && invite.usageLimit == nil {
|
} else if invite.expireDate == nil && invite.usageLimit == nil {
|
||||||
color = .blue
|
color = .blue
|
||||||
|
nextColor = .blue
|
||||||
|
transitionFraction = 0.0
|
||||||
} else if availability >= 0.5 {
|
} else if availability >= 0.5 {
|
||||||
color = .green
|
color = .green
|
||||||
|
nextColor = .yellow
|
||||||
|
transitionFraction = (availability - 0.5) / 0.5
|
||||||
} else if availability > 0.0 {
|
} else if availability > 0.0 {
|
||||||
color = .yellow
|
color = .yellow
|
||||||
|
nextColor = .red
|
||||||
|
transitionFraction = availability / 0.5
|
||||||
} else {
|
} else {
|
||||||
color = .red
|
color = .red
|
||||||
|
nextColor = .red
|
||||||
|
transitionFraction = 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
let previousParams = self.params
|
let previousParams = self.params
|
||||||
@ -239,8 +251,9 @@ private class ItemNode: ASDisplayNode {
|
|||||||
self.updateTimer?.invalidate()
|
self.updateTimer?.invalidate()
|
||||||
self.updateTimer = nil
|
self.updateTimer = nil
|
||||||
|
|
||||||
if let _ = invite.expireDate, availability > 0.0 {
|
if let expireDate = invite.expireDate, availability > 0.0 {
|
||||||
let updateTimer = SwiftSignalKit.Timer(timeout: 5.0, repeat: true, completion: { [weak self] in
|
let timeout = min(2.0, max(0.001, Double(expireDate - currentTime)))
|
||||||
|
let updateTimer = SwiftSignalKit.Timer(timeout: timeout, repeat: true, completion: { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let (size, wide, invite, _, presentationData) = strongSelf.params {
|
if let (size, wide, invite, _, presentationData) = strongSelf.params {
|
||||||
let _ = strongSelf.update(size: size, wide: wide, share: share, invite: invite, presentationData: presentationData, transition: .animated(duration: 0.3, curve: .linear))
|
let _ = strongSelf.update(size: size, wide: wide, share: share, invite: invite, presentationData: presentationData, transition: .animated(duration: 0.3, curve: .linear))
|
||||||
@ -255,9 +268,14 @@ private class ItemNode: ASDisplayNode {
|
|||||||
self.updateTimer = nil
|
self.updateTimer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
let colors: NSArray = [color.colors.top.cgColor, color.colors.bottom.cgColor]
|
let topColor = color.colors.top
|
||||||
|
let bottomColor = color.colors.bottom
|
||||||
|
let nextTopColor = nextColor.colors.top
|
||||||
|
let nextBottomColor = nextColor.colors.bottom
|
||||||
|
let colors: NSArray = [nextTopColor.mixedWith(topColor, alpha: transitionFraction).cgColor, nextBottomColor.mixedWith(bottomColor, alpha: transitionFraction).cgColor]
|
||||||
|
|
||||||
if let (_, _, previousInvite, previousColor, _) = previousParams, previousInvite == invite {
|
if let (_, _, previousInvite, previousColor, _) = previousParams, previousInvite == invite {
|
||||||
if previousColor != color {
|
if previousColor != color && color == .red {
|
||||||
if let snapshotView = self.wrapperNode.view.snapshotContentTree() {
|
if let snapshotView = self.wrapperNode.view.snapshotContentTree() {
|
||||||
snapshotView.frame = self.wrapperNode.bounds
|
snapshotView.frame = self.wrapperNode.bounds
|
||||||
self.wrapperNode.view.addSubview(snapshotView)
|
self.wrapperNode.view.addSubview(snapshotView)
|
||||||
@ -266,12 +284,18 @@ private class ItemNode: ASDisplayNode {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
self.backgroundGradientLayer.colors = colors as? [Any]
|
self.backgroundGradientLayer.colors = colors as? [Any]
|
||||||
|
} else if (color == .green && nextColor == .yellow) || (color == .yellow && nextColor == .red) {
|
||||||
|
let previousColors = self.backgroundGradientLayer.colors
|
||||||
|
if transition.isAnimated {
|
||||||
|
self.backgroundGradientLayer.animate(from: previousColors as AnyObject, to: self.backgroundGradientLayer.colors as AnyObject, keyPath: "colors", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: 2.5)
|
||||||
|
}
|
||||||
|
self.backgroundGradientLayer.colors = colors as? [Any]
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.backgroundGradientLayer.colors = colors as? [Any]
|
self.backgroundGradientLayer.colors = colors as? [Any]
|
||||||
}
|
}
|
||||||
|
|
||||||
let secondaryTextColor = color.colors.text
|
let secondaryTextColor = nextColor.colors.text.mixedWith(color.colors.text, alpha: transitionFraction)
|
||||||
|
|
||||||
let itemWidth = wide ? size.width : floor((size.width - itemSpacing) / 2.0)
|
let itemWidth = wide ? size.width : floor((size.width - itemSpacing) / 2.0)
|
||||||
var inviteLink = invite.link.replacingOccurrences(of: "https://", with: "")
|
var inviteLink = invite.link.replacingOccurrences(of: "https://", with: "")
|
||||||
|
@ -293,7 +293,7 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
|||||||
case let .privateLinkHeader(_, title):
|
case let .privateLinkHeader(_, title):
|
||||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
|
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
|
||||||
case let .privateLink(_, invite, displayImporters):
|
case let .privateLink(_, invite, displayImporters):
|
||||||
return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: invite, count: 0, peers: [], displayButton: true, displayImporters: displayImporters, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: {
|
return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: invite, count: 0, peers: [], displayButton: true, displayImporters: false, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: {
|
||||||
if let invite = invite {
|
if let invite = invite {
|
||||||
arguments.copyLink(invite)
|
arguments.copyLink(invite)
|
||||||
}
|
}
|
||||||
@ -598,13 +598,13 @@ 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))
|
||||||
}
|
}
|
||||||
switch mode {
|
// switch mode {
|
||||||
case .initialSetup:
|
// case .initialSetup:
|
||||||
break
|
// break
|
||||||
case .generic, .privateLink:
|
// case .generic, .privateLink:
|
||||||
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
|
// entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
|
||||||
entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
|
// entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
case .privateChannel:
|
case .privateChannel:
|
||||||
let invite = (view.cachedData as? CachedChannelData)?.exportedInvitation
|
let invite = (view.cachedData as? CachedChannelData)?.exportedInvitation
|
||||||
@ -615,13 +615,13 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
|||||||
} else {
|
} else {
|
||||||
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Channel_Username_CreatePrivateLinkHelp))
|
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Channel_Username_CreatePrivateLinkHelp))
|
||||||
}
|
}
|
||||||
switch mode {
|
// switch mode {
|
||||||
case .initialSetup:
|
// case .initialSetup:
|
||||||
break
|
// break
|
||||||
case .generic, .privateLink:
|
// case .generic, .privateLink:
|
||||||
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
|
// entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
|
||||||
entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
|
// entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
} else if let _ = view.peers[view.peerId] as? TelegramGroup {
|
} else if let _ = view.peers[view.peerId] as? TelegramGroup {
|
||||||
switch mode {
|
switch mode {
|
||||||
@ -630,13 +630,13 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
|||||||
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_PermanentLink.uppercased()))
|
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_PermanentLink.uppercased()))
|
||||||
entries.append(.privateLink(presentationData.theme, invite, mode != .initialSetup))
|
entries.append(.privateLink(presentationData.theme, invite, mode != .initialSetup))
|
||||||
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.GroupInfo_InviteLink_Help))
|
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.GroupInfo_InviteLink_Help))
|
||||||
switch mode {
|
// switch mode {
|
||||||
case .initialSetup:
|
// case .initialSetup:
|
||||||
break
|
// break
|
||||||
case .generic, .privateLink:
|
// case .generic, .privateLink:
|
||||||
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
|
// entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
|
||||||
entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
|
// entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
|
||||||
}
|
// }
|
||||||
case .generic, .initialSetup:
|
case .generic, .initialSetup:
|
||||||
let selectedType: CurrentChannelType
|
let selectedType: CurrentChannelType
|
||||||
if let current = state.selectedType {
|
if let current = state.selectedType {
|
||||||
@ -729,13 +729,13 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
|||||||
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_PermanentLink.uppercased()))
|
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_PermanentLink.uppercased()))
|
||||||
entries.append(.privateLink(presentationData.theme, invite, mode != .initialSetup))
|
entries.append(.privateLink(presentationData.theme, invite, mode != .initialSetup))
|
||||||
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePrivateLinkHelp))
|
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePrivateLinkHelp))
|
||||||
switch mode {
|
// switch mode {
|
||||||
case .initialSetup:
|
// case .initialSetup:
|
||||||
break
|
// break
|
||||||
case .generic, .privateLink:
|
// case .generic, .privateLink:
|
||||||
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
|
// entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
|
||||||
entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
|
// entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -943,27 +943,27 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
|
|||||||
})
|
})
|
||||||
})))
|
})))
|
||||||
|
|
||||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in
|
// items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor)
|
// return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor)
|
||||||
}, action: { _, f in
|
// }, action: { _, f in
|
||||||
f(.dismissWithoutContent)
|
// f(.dismissWithoutContent)
|
||||||
|
//
|
||||||
let _ = (context.account.postbox.transaction { transaction -> ExportedInvitation? in
|
// let _ = (context.account.postbox.transaction { transaction -> ExportedInvitation? in
|
||||||
if let cachedData = transaction.getPeerCachedData(peerId: peerId) {
|
// if let cachedData = transaction.getPeerCachedData(peerId: peerId) {
|
||||||
if let cachedData = cachedData as? CachedChannelData {
|
// if let cachedData = cachedData as? CachedChannelData {
|
||||||
return cachedData.exportedInvitation
|
// return cachedData.exportedInvitation
|
||||||
} else if let cachedData = cachedData as? CachedGroupData {
|
// } else if let cachedData = cachedData as? CachedGroupData {
|
||||||
return cachedData.exportedInvitation
|
// return cachedData.exportedInvitation
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return nil
|
// return nil
|
||||||
} |> deliverOnMainQueue).start(next: { invite in
|
// } |> deliverOnMainQueue).start(next: { invite in
|
||||||
if let invite = invite {
|
// if let invite = invite {
|
||||||
let controller = InviteLinkQRCodeController(context: context, invite: invite)
|
// let controller = InviteLinkQRCodeController(context: context, invite: invite)
|
||||||
presentControllerImpl?(controller, nil)
|
// presentControllerImpl?(controller, nil)
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
})))
|
// })))
|
||||||
|
|
||||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextRevoke, textColor: .destructive, icon: { theme in
|
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextRevoke, textColor: .destructive, icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor)
|
||||||
|
@ -354,7 +354,8 @@ public final class VoiceChatController: ViewController {
|
|||||||
text = .text(presentationData.strings.VoiceChat_StatusMutedForYou, .destructive)
|
text = .text(presentationData.strings.VoiceChat_StatusMutedForYou, .destructive)
|
||||||
icon = .microphone(true, UIColor(rgb: 0xff3b30))
|
icon = .microphone(true, UIColor(rgb: 0xff3b30))
|
||||||
} else {
|
} else {
|
||||||
if let volume = peerEntry.volume, volume != 10000 {
|
let volumeValue = peerEntry.volume.flatMap { $0 / 100 }
|
||||||
|
if let volume = volumeValue, volume != 100 {
|
||||||
text = .text("\(volume / 100)% \(presentationData.strings.VoiceChat_StatusSpeaking)", .constructive)
|
text = .text("\(volume / 100)% \(presentationData.strings.VoiceChat_StatusSpeaking)", .constructive)
|
||||||
} else {
|
} else {
|
||||||
text = .text(presentationData.strings.VoiceChat_StatusSpeaking, .constructive)
|
text = .text(presentationData.strings.VoiceChat_StatusSpeaking, .constructive)
|
||||||
@ -1275,6 +1276,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
|
|
||||||
@objc private func closePressed() {
|
@objc private func closePressed() {
|
||||||
self.controller?.dismiss(closing: false)
|
self.controller?.dismiss(closing: false)
|
||||||
|
self.controller?.dismissAllTooltips()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func leavePressed() {
|
@objc private func leavePressed() {
|
||||||
@ -1284,11 +1286,13 @@ public final class VoiceChatController: ViewController {
|
|||||||
|> deliverOnMainQueue).start(completed: { [weak self] in
|
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||||
self?.controller?.dismiss(closing: true)
|
self?.controller?.dismiss(closing: true)
|
||||||
}))
|
}))
|
||||||
|
self.controller?.dismissAllTooltips()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func dimTapGesture(_ recognizer: UITapGestureRecognizer) {
|
@objc func dimTapGesture(_ recognizer: UITapGestureRecognizer) {
|
||||||
if case .ended = recognizer.state {
|
if case .ended = recognizer.state {
|
||||||
self.controller?.dismiss(closing: false)
|
self.controller?.dismiss(closing: false)
|
||||||
|
self.controller?.dismissAllTooltips()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2144,6 +2148,8 @@ public final class VoiceChatController: ViewController {
|
|||||||
topInset = self.listNode.frame.height
|
topInset = self.listNode.frame.height
|
||||||
}
|
}
|
||||||
self.panGestureArguments = (topInset, 0.0)
|
self.panGestureArguments = (topInset, 0.0)
|
||||||
|
|
||||||
|
self.controller?.dismissAllTooltips()
|
||||||
case .changed:
|
case .changed:
|
||||||
var translation = recognizer.translation(in: self.contentContainer.view).y
|
var translation = recognizer.translation(in: self.contentContainer.view).y
|
||||||
var topInset: CGFloat = 0.0
|
var topInset: CGFloat = 0.0
|
||||||
@ -2459,6 +2465,20 @@ public final class VoiceChatController: ViewController {
|
|||||||
self.dismiss()
|
self.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func dismissAllTooltips() {
|
||||||
|
self.window?.forEachController({ controller in
|
||||||
|
if let controller = controller as? UndoOverlayController {
|
||||||
|
controller.dismissWithCommitAction()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
self.forEachController({ controller in
|
||||||
|
if let controller = controller as? UndoOverlayController {
|
||||||
|
controller.dismissWithCommitAction()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
private func detachActionButton() {
|
private func detachActionButton() {
|
||||||
guard self.currentOverlayController == nil && !self.isDisconnected else {
|
guard self.currentOverlayController == nil && !self.isDisconnected else {
|
||||||
return
|
return
|
||||||
|
@ -85,6 +85,9 @@ private final class VoiceChatVolumeContextItemNode: ASDisplayNode, ContextMenuCu
|
|||||||
|
|
||||||
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))
|
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))
|
||||||
self.view.addGestureRecognizer(panGestureRecognizer)
|
self.view.addGestureRecognizer(panGestureRecognizer)
|
||||||
|
|
||||||
|
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))
|
||||||
|
self.view.addGestureRecognizer(tapGestureRecognizer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateTheme(presentationData: PresentationData) {
|
func updateTheme(presentationData: PresentationData) {
|
||||||
@ -180,4 +183,10 @@ private final class VoiceChatVolumeContextItemNode: ASDisplayNode, ContextMenuCu
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func tapGesture(_ gestureRecognizer: UITapGestureRecognizer) {
|
||||||
|
let location = gestureRecognizer.location(in: gestureRecognizer.view)
|
||||||
|
self.value = max(0.0, min(2.0, location.x / self.bounds.width * 2.0))
|
||||||
|
self.valueChanged(self.value, true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1094,12 +1094,6 @@ public final class GroupCallParticipantsContext {
|
|||||||
|
|
||||||
public func updateMuteState(peerId: PeerId, muteState: Participant.MuteState?, volume: Int32?) {
|
public func updateMuteState(peerId: PeerId, muteState: Participant.MuteState?, volume: Int32?) {
|
||||||
|
|
||||||
var muteState = muteState
|
|
||||||
if muteState == nil, let _ = volume {
|
|
||||||
muteState = self.stateValue.overlayState.pendingMuteStateChanges[peerId]?.state
|
|
||||||
?? self.stateValue.state.participants.first(where: { $0.peer.id == peerId })?.muteState
|
|
||||||
}
|
|
||||||
|
|
||||||
if let current = self.stateValue.overlayState.pendingMuteStateChanges[peerId] {
|
if let current = self.stateValue.overlayState.pendingMuteStateChanges[peerId] {
|
||||||
if current.state == muteState {
|
if current.state == muteState {
|
||||||
return
|
return
|
||||||
@ -1135,12 +1129,11 @@ public final class GroupCallParticipantsContext {
|
|||||||
return .single(nil)
|
return .single(nil)
|
||||||
}
|
}
|
||||||
var flags: Int32 = 0
|
var flags: Int32 = 0
|
||||||
if let _ = volume {
|
if let volume = volume, volume > 0 {
|
||||||
flags |= 1 << 1
|
flags |= 1 << 1
|
||||||
} else {
|
}
|
||||||
if let muteState = muteState, (!muteState.canUnmute || peerId == account.peerId || muteState.mutedByYou) {
|
if let muteState = muteState, (!muteState.canUnmute || peerId == account.peerId || muteState.mutedByYou) {
|
||||||
flags |= 1 << 0
|
flags |= 1 << 0
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return account.network.request(Api.functions.phone.editGroupCallMember(flags: flags, call: .inputGroupCall(id: id, accessHash: accessHash), userId: inputUser, volume: volume))
|
return account.network.request(Api.functions.phone.editGroupCallMember(flags: flags, call: .inputGroupCall(id: id, accessHash: accessHash), userId: inputUser, volume: volume))
|
||||||
|
@ -258,6 +258,22 @@ public struct PeerExportedInvitationsState: Equatable {
|
|||||||
public var hasLoadedOnce: Bool
|
public var hasLoadedOnce: Bool
|
||||||
public var canLoadMore: Bool
|
public var canLoadMore: Bool
|
||||||
public var count: Int32
|
public var count: Int32
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
self.invitations = []
|
||||||
|
self.isLoadingMore = false
|
||||||
|
self.hasLoadedOnce = false
|
||||||
|
self.canLoadMore = false
|
||||||
|
self.count = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(invitations: [ExportedInvitation], isLoadingMore: Bool, hasLoadedOnce: Bool, canLoadMore: Bool, count: Int32) {
|
||||||
|
self.invitations = invitations
|
||||||
|
self.isLoadingMore = isLoadingMore
|
||||||
|
self.hasLoadedOnce = hasLoadedOnce
|
||||||
|
self.canLoadMore = canLoadMore
|
||||||
|
self.count = count
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class CachedPeerExportedInvitations: PostboxCoding {
|
final class CachedPeerExportedInvitations: PostboxCoding {
|
||||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -66,6 +66,173 @@ private final class ChatEmptyNodeRegularChatContent: ASDisplayNode, ChatEmptyNod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class ChatEmptyNodeGreetingChatContent: ASDisplayNode, ChatEmptyNodeContent, UIGestureRecognizerDelegate {
|
||||||
|
private let account: Account
|
||||||
|
private let interaction: ChatPanelInterfaceInteraction?
|
||||||
|
|
||||||
|
private let titleNode: ImmediateTextNode
|
||||||
|
private let textNode: ImmediateTextNode
|
||||||
|
|
||||||
|
private var stickerItem: ChatMediaInputStickerGridItem?
|
||||||
|
private let stickerNode: ChatMediaInputStickerGridItemNode
|
||||||
|
|
||||||
|
private var currentTheme: PresentationTheme?
|
||||||
|
private var currentStrings: PresentationStrings?
|
||||||
|
|
||||||
|
private var didSetupSticker = false
|
||||||
|
private let disposable = MetaDisposable()
|
||||||
|
|
||||||
|
var greetingStickerNode: ASDisplayNode? {
|
||||||
|
if let animationNode = self.stickerNode.animationNode, animationNode.supernode === stickerNode {
|
||||||
|
return animationNode
|
||||||
|
} else if self.stickerNode.imageNode.supernode === stickerNode {
|
||||||
|
return self.stickerNode.imageNode
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init(account: Account, interaction: ChatPanelInterfaceInteraction?) {
|
||||||
|
self.account = account
|
||||||
|
self.interaction = interaction
|
||||||
|
|
||||||
|
self.titleNode = ImmediateTextNode()
|
||||||
|
self.titleNode.maximumNumberOfLines = 0
|
||||||
|
self.titleNode.lineSpacing = 0.15
|
||||||
|
self.titleNode.textAlignment = .center
|
||||||
|
self.titleNode.isUserInteractionEnabled = false
|
||||||
|
self.titleNode.displaysAsynchronously = false
|
||||||
|
|
||||||
|
self.textNode = ImmediateTextNode()
|
||||||
|
self.textNode.maximumNumberOfLines = 0
|
||||||
|
self.textNode.lineSpacing = 0.15
|
||||||
|
self.textNode.textAlignment = .center
|
||||||
|
self.textNode.isUserInteractionEnabled = false
|
||||||
|
self.textNode.displaysAsynchronously = false
|
||||||
|
|
||||||
|
self.stickerNode = ChatMediaInputStickerGridItemNode()
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.addSubnode(self.titleNode)
|
||||||
|
self.addSubnode(self.textNode)
|
||||||
|
self.addSubnode(self.stickerNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func didLoad() {
|
||||||
|
super.didLoad()
|
||||||
|
|
||||||
|
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.stickerTapGesture(_:)))
|
||||||
|
tapRecognizer.delegate = self
|
||||||
|
self.stickerNode.view.addGestureRecognizer(tapRecognizer)
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
self.disposable.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func stickerTapGesture(_ gestureRecognizer: UITapGestureRecognizer) {
|
||||||
|
guard let stickerItem = self.stickerItem else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let _ = self.interaction?.sendSticker(.standalone(media: stickerItem.stickerItem.file), self.stickerNode, self.stickerNode.bounds)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateLayout(interfaceState: ChatPresentationInterfaceState, size: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
|
||||||
|
if self.currentTheme !== interfaceState.theme || self.currentStrings !== interfaceState.strings {
|
||||||
|
self.currentTheme = interfaceState.theme
|
||||||
|
self.currentStrings = interfaceState.strings
|
||||||
|
|
||||||
|
let serviceColor = serviceMessageColorComponents(theme: interfaceState.theme, wallpaper: interfaceState.chatWallpaper)
|
||||||
|
|
||||||
|
self.titleNode.attributedText = NSAttributedString(string: interfaceState.strings.Conversation_EmptyPlaceholder, font: titleFont, textColor: serviceColor.primaryText)
|
||||||
|
|
||||||
|
self.textNode.attributedText = NSAttributedString(string: interfaceState.strings.Conversation_GreetingText, font: messageFont, textColor: serviceColor.primaryText)
|
||||||
|
}
|
||||||
|
|
||||||
|
let stickerSize = CGSize(width: 160.0, height: 160.0)
|
||||||
|
if let item = self.stickerItem {
|
||||||
|
self.stickerNode.updateLayout(item: item, size: stickerSize, isVisible: true, synchronousLoads: true)
|
||||||
|
} else if !self.didSetupSticker {
|
||||||
|
let sticker: Signal<TelegramMediaFile?, NoError>
|
||||||
|
if let preloadedSticker = interfaceState.peerNearbyData?.sticker {
|
||||||
|
sticker = .single(preloadedSticker)
|
||||||
|
} else {
|
||||||
|
sticker = randomGreetingSticker(account: self.account)
|
||||||
|
|> map { item -> TelegramMediaFile? in
|
||||||
|
return item?.file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.didSetupSticker = true
|
||||||
|
self.disposable.set((sticker
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] sticker in
|
||||||
|
if let strongSelf = self, let sticker = sticker {
|
||||||
|
let inputNodeInteraction = ChatMediaInputNodeInteraction(
|
||||||
|
navigateToCollectionId: { _ in
|
||||||
|
},
|
||||||
|
navigateBackToStickers: {
|
||||||
|
},
|
||||||
|
setGifMode: { _ in
|
||||||
|
},
|
||||||
|
openSettings: {
|
||||||
|
},
|
||||||
|
toggleSearch: { _, _, _ in
|
||||||
|
},
|
||||||
|
openPeerSpecificSettings: {
|
||||||
|
},
|
||||||
|
dismissPeerSpecificSettings: {
|
||||||
|
},
|
||||||
|
clearRecentlyUsedStickers: {
|
||||||
|
}
|
||||||
|
)
|
||||||
|
inputNodeInteraction.displayStickerPlaceholder = false
|
||||||
|
|
||||||
|
let index = ItemCollectionItemIndex(index: 0, id: 0)
|
||||||
|
let collectionId = ItemCollectionId(namespace: 0, id: 0)
|
||||||
|
let stickerPackItem = StickerPackItem(index: index, file: sticker, indexKeys: [])
|
||||||
|
let item = ChatMediaInputStickerGridItem(account: strongSelf.account, collectionId: collectionId, stickerPackInfo: nil, index: ItemCollectionViewEntryIndex(collectionIndex: 0, collectionId: collectionId, itemIndex: index), stickerItem: stickerPackItem, canManagePeerSpecificPack: nil, interfaceInteraction: nil, inputNodeInteraction: inputNodeInteraction, hasAccessory: false, theme: interfaceState.theme, large: true, selected: {})
|
||||||
|
strongSelf.stickerItem = item
|
||||||
|
strongSelf.stickerNode.updateLayout(item: item, size: stickerSize, isVisible: true, synchronousLoads: true)
|
||||||
|
strongSelf.stickerNode.isVisibleInGrid = true
|
||||||
|
strongSelf.stickerNode.updateIsPanelVisible(true)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
let insets = UIEdgeInsets(top: 15.0, left: 15.0, bottom: 15.0, right: 15.0)
|
||||||
|
let titleSpacing: CGFloat = 5.0
|
||||||
|
let stickerSpacing: CGFloat = 5.0
|
||||||
|
|
||||||
|
var contentWidth: CGFloat = 210.0
|
||||||
|
var contentHeight: CGFloat = 0.0
|
||||||
|
|
||||||
|
let titleSize = self.titleNode.updateLayout(CGSize(width: contentWidth, height: CGFloat.greatestFiniteMagnitude))
|
||||||
|
let textSize = self.textNode.updateLayout(CGSize(width: contentWidth, height: CGFloat.greatestFiniteMagnitude))
|
||||||
|
|
||||||
|
contentWidth = max(contentWidth, max(titleSize.width, textSize.width))
|
||||||
|
|
||||||
|
contentHeight += titleSize.height + titleSpacing + textSize.height + stickerSpacing + stickerSize.height
|
||||||
|
|
||||||
|
let contentRect = CGRect(origin: CGPoint(x: insets.left, y: insets.top), size: CGSize(width: contentWidth, height: contentHeight))
|
||||||
|
|
||||||
|
let titleFrame = CGRect(origin: CGPoint(x: contentRect.minX + floor((contentRect.width - titleSize.width) / 2.0), y: contentRect.minY), size: titleSize)
|
||||||
|
transition.updateFrame(node: self.titleNode, frame: titleFrame)
|
||||||
|
|
||||||
|
let textFrame = CGRect(origin: CGPoint(x: contentRect.minX + floor((contentRect.width - textSize.width) / 2.0), y: titleFrame.maxY + titleSpacing), size: textSize)
|
||||||
|
transition.updateFrame(node: self.textNode, frame: textFrame)
|
||||||
|
|
||||||
|
let stickerFrame = CGRect(origin: CGPoint(x: contentRect.minX + floor((contentRect.width - stickerSize.width) / 2.0), y: textFrame.maxY + stickerSpacing), size: stickerSize)
|
||||||
|
transition.updateFrame(node: self.stickerNode, frame: stickerFrame)
|
||||||
|
|
||||||
|
return contentRect.insetBy(dx: -insets.left, dy: -insets.top).size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final class ChatEmptyNodeNearbyChatContent: ASDisplayNode, ChatEmptyNodeContent, UIGestureRecognizerDelegate {
|
private final class ChatEmptyNodeNearbyChatContent: ASDisplayNode, ChatEmptyNodeContent, UIGestureRecognizerDelegate {
|
||||||
private let account: Account
|
private let account: Account
|
||||||
private let interaction: ChatPanelInterfaceInteraction?
|
private let interaction: ChatPanelInterfaceInteraction?
|
||||||
@ -232,7 +399,8 @@ private final class ChatEmptyNodeNearbyChatContent: ASDisplayNode, ChatEmptyNode
|
|||||||
|
|
||||||
let titleFrame = CGRect(origin: CGPoint(x: contentRect.minX + floor((contentRect.width - titleSize.width) / 2.0), y: contentRect.minY), size: titleSize)
|
let titleFrame = CGRect(origin: CGPoint(x: contentRect.minX + floor((contentRect.width - titleSize.width) / 2.0), y: contentRect.minY), size: titleSize)
|
||||||
transition.updateFrame(node: self.titleNode, frame: titleFrame)
|
transition.updateFrame(node: self.titleNode, frame: titleFrame)
|
||||||
let textFrame = CGRect(origin: CGPoint(x: contentRect.minX, y: titleFrame.maxY + titleSpacing), size: textSize)
|
|
||||||
|
let textFrame = CGRect(origin: CGPoint(x: contentRect.minX + floor((contentRect.width - textSize.width) / 2.0), y: titleFrame.maxY + titleSpacing), size: textSize)
|
||||||
transition.updateFrame(node: self.textNode, frame: textFrame)
|
transition.updateFrame(node: self.textNode, frame: textFrame)
|
||||||
|
|
||||||
let stickerFrame = CGRect(origin: CGPoint(x: contentRect.minX + floor((contentRect.width - stickerSize.width) / 2.0), y: textFrame.maxY + stickerSpacing), size: stickerSize)
|
let stickerFrame = CGRect(origin: CGPoint(x: contentRect.minX + floor((contentRect.width - stickerSize.width) / 2.0), y: textFrame.maxY + stickerSpacing), size: stickerSize)
|
||||||
@ -611,6 +779,7 @@ private enum ChatEmptyNodeContentType {
|
|||||||
case group
|
case group
|
||||||
case cloud
|
case cloud
|
||||||
case peerNearby
|
case peerNearby
|
||||||
|
case greeting
|
||||||
}
|
}
|
||||||
|
|
||||||
final class ChatEmptyNode: ASDisplayNode {
|
final class ChatEmptyNode: ASDisplayNode {
|
||||||
@ -668,6 +837,8 @@ final class ChatEmptyNode: ASDisplayNode {
|
|||||||
contentType = .group
|
contentType = .group
|
||||||
} else if let _ = interfaceState.peerNearbyData {
|
} else if let _ = interfaceState.peerNearbyData {
|
||||||
contentType = .peerNearby
|
contentType = .peerNearby
|
||||||
|
} else if let _ = peer as? TelegramUser {
|
||||||
|
contentType = .greeting
|
||||||
} else {
|
} else {
|
||||||
contentType = .regular
|
contentType = .regular
|
||||||
}
|
}
|
||||||
@ -692,12 +863,14 @@ final class ChatEmptyNode: ASDisplayNode {
|
|||||||
node = ChatEmptyNodeCloudChatContent()
|
node = ChatEmptyNodeCloudChatContent()
|
||||||
case .peerNearby:
|
case .peerNearby:
|
||||||
node = ChatEmptyNodeNearbyChatContent(account: self.account, interaction: self.interaction)
|
node = ChatEmptyNodeNearbyChatContent(account: self.account, interaction: self.interaction)
|
||||||
|
case .greeting:
|
||||||
|
node = ChatEmptyNodeGreetingChatContent(account: self.account, interaction: self.interaction)
|
||||||
}
|
}
|
||||||
self.content = (contentType, node)
|
self.content = (contentType, node)
|
||||||
self.addSubnode(node)
|
self.addSubnode(node)
|
||||||
contentTransition = .immediate
|
contentTransition = .immediate
|
||||||
}
|
}
|
||||||
self.isUserInteractionEnabled = contentType == .peerNearby
|
self.isUserInteractionEnabled = [.regular, .peerNearby].contains(contentType)
|
||||||
|
|
||||||
let displayRect = CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: size.width, height: size.height - insets.top - insets.bottom))
|
let displayRect = CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: size.width, height: size.height - insets.top - insets.bottom))
|
||||||
|
|
||||||
@ -716,7 +889,9 @@ final class ChatEmptyNode: ASDisplayNode {
|
|||||||
|
|
||||||
var greetingStickerNode: ASDisplayNode? {
|
var greetingStickerNode: ASDisplayNode? {
|
||||||
if let (_, node) = self.content {
|
if let (_, node) = self.content {
|
||||||
if let node = node as? ChatEmptyNodeNearbyChatContent {
|
if let node = node as? ChatEmptyNodeGreetingChatContent {
|
||||||
|
return node.greetingStickerNode
|
||||||
|
} else if let node = node as? ChatEmptyNodeNearbyChatContent {
|
||||||
return node.greetingStickerNode
|
return node.greetingStickerNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,11 +203,14 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
|
|||||||
if entries.count <= 3 {
|
if entries.count <= 3 {
|
||||||
loop: for entry in view.entries {
|
loop: for entry in view.entries {
|
||||||
var isEmptyMedia = false
|
var isEmptyMedia = false
|
||||||
|
var isPeerJoined = false
|
||||||
for media in entry.message.media {
|
for media in entry.message.media {
|
||||||
if let action = media as? TelegramMediaAction {
|
if let action = media as? TelegramMediaAction {
|
||||||
switch action.action {
|
switch action.action {
|
||||||
case .groupCreated, .photoUpdated, .channelMigratedFromGroup, .groupMigratedToChannel:
|
case .groupCreated, .photoUpdated, .channelMigratedFromGroup, .groupMigratedToChannel:
|
||||||
isEmptyMedia = true
|
isEmptyMedia = true
|
||||||
|
case .peerJoined:
|
||||||
|
isPeerJoined = true
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -219,7 +222,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
|
|||||||
} else if let peer = entry.message.peers[entry.message.id.peerId] as? TelegramChannel, case .group = peer.info, peer.flags.contains(.isCreator) {
|
} else if let peer = entry.message.peers[entry.message.id.peerId] as? TelegramChannel, case .group = peer.info, peer.flags.contains(.isCreator) {
|
||||||
isCreator = true
|
isCreator = true
|
||||||
}
|
}
|
||||||
if isEmptyMedia && isCreator {
|
if isPeerJoined || (isEmptyMedia && isCreator) {
|
||||||
} else {
|
} else {
|
||||||
isEmpty = false
|
isEmpty = false
|
||||||
break loop
|
break loop
|
||||||
|
@ -777,7 +777,7 @@ final class ChatPresentationInterfaceState: Equatable {
|
|||||||
|
|
||||||
func canSendMessagesToChat(_ state: ChatPresentationInterfaceState) -> Bool {
|
func canSendMessagesToChat(_ state: ChatPresentationInterfaceState) -> Bool {
|
||||||
if let peer = state.renderedPeer?.peer {
|
if let peer = state.renderedPeer?.peer {
|
||||||
if canSendMessagesToPeer(peer) {
|
if true || canSendMessagesToPeer(peer) {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
|
@ -57,6 +57,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
|||||||
|
|
||||||
private var titleLeftIcon: ChatTitleIcon = .none
|
private var titleLeftIcon: ChatTitleIcon = .none
|
||||||
private var titleRightIcon: ChatTitleIcon = .none
|
private var titleRightIcon: ChatTitleIcon = .none
|
||||||
|
private var titleFakeIcon = false
|
||||||
private var titleScamIcon = false
|
private var titleScamIcon = false
|
||||||
|
|
||||||
//private var networkStatusNode: ChatTitleNetworkStatusNode?
|
//private var networkStatusNode: ChatTitleNetworkStatusNode?
|
||||||
@ -104,6 +105,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
|||||||
var titleLeftIcon: ChatTitleIcon = .none
|
var titleLeftIcon: ChatTitleIcon = .none
|
||||||
var titleRightIcon: ChatTitleIcon = .none
|
var titleRightIcon: ChatTitleIcon = .none
|
||||||
var titleScamIcon = false
|
var titleScamIcon = false
|
||||||
|
var titleFakeIcon = false
|
||||||
var isEnabled = true
|
var isEnabled = true
|
||||||
switch titleContent {
|
switch titleContent {
|
||||||
case let .peer(peerView, _, isScheduledMessages):
|
case let .peer(peerView, _, isScheduledMessages):
|
||||||
@ -129,7 +131,11 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
|||||||
segments = [.text(0, NSAttributedString(string: peer.displayTitle(strings: self.strings, displayOrder: self.nameDisplayOrder), font: Font.medium(17.0), textColor: titleTheme.rootController.navigationBar.primaryTextColor))]
|
segments = [.text(0, NSAttributedString(string: peer.displayTitle(strings: self.strings, displayOrder: self.nameDisplayOrder), font: Font.medium(17.0), textColor: titleTheme.rootController.navigationBar.primaryTextColor))]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
titleScamIcon = peer.isScam
|
if peer.isFake {
|
||||||
|
titleFakeIcon = true
|
||||||
|
} else if peer.isScam {
|
||||||
|
titleScamIcon = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if peerView.peerId.namespace == Namespaces.Peer.SecretChat {
|
if peerView.peerId.namespace == Namespaces.Peer.SecretChat {
|
||||||
titleLeftIcon = .lock
|
titleLeftIcon = .lock
|
||||||
@ -231,6 +237,12 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
|||||||
updated = true
|
updated = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if titleFakeIcon != self.titleFakeIcon {
|
||||||
|
self.titleFakeIcon = titleFakeIcon
|
||||||
|
self.titleCredibilityIconNode.image = titleFakeIcon ? PresentationResourcesChatList.fakeIcon(titleTheme, type: .regular) : nil
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
|
||||||
if titleScamIcon != self.titleScamIcon {
|
if titleScamIcon != self.titleScamIcon {
|
||||||
self.titleScamIcon = titleScamIcon
|
self.titleScamIcon = titleScamIcon
|
||||||
self.titleCredibilityIconNode.image = titleScamIcon ? PresentationResourcesChatList.scamIcon(titleTheme, type: .regular) : nil
|
self.titleCredibilityIconNode.image = titleScamIcon ? PresentationResourcesChatList.scamIcon(titleTheme, type: .regular) : nil
|
||||||
|
@ -123,7 +123,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
|||||||
self?.openPeer?(peer)
|
self?.openPeer?(peer)
|
||||||
}
|
}
|
||||||
case let .chats(chatsNode):
|
case let .chats(chatsNode):
|
||||||
chatsNode.peerSelected = { [weak self] peer, _, _ in
|
chatsNode.peerSelected = { [weak self] peer, _, _, _ in
|
||||||
self?.openPeer?(.peer(peer: peer, isGlobal: false, participantCount: nil))
|
self?.openPeer?(.peer(peer: peer, isGlobal: false, participantCount: nil))
|
||||||
}
|
}
|
||||||
chatsNode.additionalCategorySelected = { [weak self] id in
|
chatsNode.additionalCategorySelected = { [weak self] id in
|
||||||
|
@ -654,17 +654,17 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
discussionPeer = peer
|
discussionPeer = peer
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentInvitationsContext == nil {
|
// if currentInvitationsContext == nil {
|
||||||
var canManageInvitations = false
|
// var canManageInvitations = false
|
||||||
if let channel = peerViewMainPeer(peerView) as? TelegramChannel, let cachedData = peerView.cachedData as? CachedChannelData, channel.flags.contains(.isCreator) || ((channel.adminRights != nil && channel.hasPermission(.pinMessages)) && cachedData.flags.contains(.canChangeUsername)) {
|
// if let channel = peerViewMainPeer(peerView) as? TelegramChannel, let cachedData = peerView.cachedData as? CachedChannelData, channel.flags.contains(.isCreator) || ((channel.adminRights != nil && channel.hasPermission(.pinMessages)) && cachedData.flags.contains(.canChangeUsername)) {
|
||||||
canManageInvitations = true
|
// canManageInvitations = true
|
||||||
}
|
// }
|
||||||
if canManageInvitations {
|
// if canManageInvitations {
|
||||||
let invitationsContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: true)
|
// let invitationsContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: true)
|
||||||
invitationsContextPromise.set(.single(invitationsContext))
|
// invitationsContextPromise.set(.single(invitationsContext))
|
||||||
invitationsStatePromise.set(invitationsContext.state |> map(Optional.init))
|
// invitationsStatePromise.set(invitationsContext.state |> map(Optional.init))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return PeerInfoScreenData(
|
return PeerInfoScreenData(
|
||||||
peer: peerView.peers[peerId],
|
peer: peerView.peers[peerId],
|
||||||
@ -811,19 +811,19 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentInvitationsContext == nil {
|
// if currentInvitationsContext == nil {
|
||||||
var canManageInvitations = false
|
// var canManageInvitations = false
|
||||||
if let group = peerViewMainPeer(peerView) as? TelegramGroup, case .creator = group.role {
|
// if let group = peerViewMainPeer(peerView) as? TelegramGroup, case .creator = group.role {
|
||||||
canManageInvitations = true
|
// canManageInvitations = true
|
||||||
} else if let channel = peerViewMainPeer(peerView) as? TelegramChannel, let cachedData = peerView.cachedData as? CachedChannelData, channel.flags.contains(.isCreator) || ((channel.adminRights != nil && channel.hasPermission(.pinMessages)) && cachedData.flags.contains(.canChangeUsername)) {
|
// } else if let channel = peerViewMainPeer(peerView) as? TelegramChannel, let cachedData = peerView.cachedData as? CachedChannelData, channel.flags.contains(.isCreator) || ((channel.adminRights != nil && channel.hasPermission(.pinMessages)) && cachedData.flags.contains(.canChangeUsername)) {
|
||||||
canManageInvitations = true
|
// canManageInvitations = true
|
||||||
}
|
// }
|
||||||
if canManageInvitations {
|
// if canManageInvitations {
|
||||||
let invitationsContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: true)
|
// let invitationsContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: true)
|
||||||
invitationsContextPromise.set(.single(invitationsContext))
|
// invitationsContextPromise.set(.single(invitationsContext))
|
||||||
invitationsStatePromise.set(invitationsContext.state |> map(Optional.init))
|
// invitationsStatePromise.set(invitationsContext.state |> map(Optional.init))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return PeerInfoScreenData(
|
return PeerInfoScreenData(
|
||||||
peer: peerView.peers[groupId],
|
peer: peerView.peers[groupId],
|
||||||
|
@ -2754,6 +2754,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
self.avatarListNode.listContainerNode.updateEntryIsHidden(entry: entry)
|
self.avatarListNode.listContainerNode.updateEntryIsHidden(entry: entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var initializedCredibilityIcon = false
|
||||||
func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, notificationSettings: TelegramPeerNotificationSettings?, statusData: PeerInfoStatusData?, isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat {
|
func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, notificationSettings: TelegramPeerNotificationSettings?, statusData: PeerInfoStatusData?, isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat {
|
||||||
self.state = state
|
self.state = state
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
@ -2775,19 +2776,35 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
let themeUpdated = self.presentationData?.theme !== presentationData.theme
|
let themeUpdated = self.presentationData?.theme !== presentationData.theme
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
|
|
||||||
if themeUpdated {
|
if themeUpdated || !initializedCredibilityIcon {
|
||||||
if let sourceImage = UIImage(bundleImageName: "Peer Info/VerifiedIcon") {
|
let image: UIImage?
|
||||||
let image = generateImage(sourceImage.size, contextGenerator: { size, context in
|
if let peer = peer {
|
||||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
self.initializedCredibilityIcon = true
|
||||||
context.setFillColor(presentationData.theme.list.itemCheckColors.foregroundColor.cgColor)
|
if peer.isFake {
|
||||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: 7.0, dy: 7.0))
|
image = PresentationResourcesChatList.fakeIcon(presentationData.theme, type: .regular)
|
||||||
context.setFillColor(presentationData.theme.list.itemCheckColors.fillColor.cgColor)
|
} else if peer.isScam {
|
||||||
context.clip(to: CGRect(origin: CGPoint(), size: size), mask: sourceImage.cgImage!)
|
image = PresentationResourcesChatList.scamIcon(presentationData.theme, type: .regular)
|
||||||
context.fill(CGRect(origin: CGPoint(), size: size))
|
} else if peer.isVerified {
|
||||||
})
|
if let sourceImage = UIImage(bundleImageName: "Peer Info/VerifiedIcon") {
|
||||||
self.titleCredibilityIconNode.image = image
|
image = generateImage(sourceImage.size, contextGenerator: { size, context in
|
||||||
self.titleExpandedCredibilityIconNode.image = image
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
|
context.setFillColor(presentationData.theme.list.itemCheckColors.foregroundColor.cgColor)
|
||||||
|
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: 7.0, dy: 7.0))
|
||||||
|
context.setFillColor(presentationData.theme.list.itemCheckColors.fillColor.cgColor)
|
||||||
|
context.clip(to: CGRect(origin: CGPoint(), size: size), mask: sourceImage.cgImage!)
|
||||||
|
context.fill(CGRect(origin: CGPoint(), size: size))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
image = nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
image = nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
image = nil
|
||||||
}
|
}
|
||||||
|
self.titleCredibilityIconNode.image = image
|
||||||
|
self.titleExpandedCredibilityIconNode.image = image
|
||||||
}
|
}
|
||||||
|
|
||||||
self.regularContentNode.alpha = state.isEditing ? 0.0 : 1.0
|
self.regularContentNode.alpha = state.isEditing ? 0.0 : 1.0
|
||||||
@ -2925,10 +2942,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
|
|
||||||
if let image = self.titleCredibilityIconNode.image {
|
if let image = self.titleCredibilityIconNode.image {
|
||||||
transition.updateFrame(node: self.titleCredibilityIconNode, frame: CGRect(origin: CGPoint(x: titleSize.width + 4.0, y: floor((titleSize.height - image.size.height) / 2.0) + 1.0), size: image.size))
|
transition.updateFrame(node: self.titleCredibilityIconNode, frame: CGRect(origin: CGPoint(x: titleSize.width + 4.0, y: floor((titleSize.height - image.size.height) / 2.0) + 1.0), size: image.size))
|
||||||
self.titleCredibilityIconNode.isHidden = !isVerified
|
|
||||||
|
|
||||||
transition.updateFrame(node: self.titleExpandedCredibilityIconNode, frame: CGRect(origin: CGPoint(x: titleExpandedSize.width + 4.0, y: floor((titleExpandedSize.height - image.size.height) / 2.0) + 1.0), size: image.size))
|
transition.updateFrame(node: self.titleExpandedCredibilityIconNode, frame: CGRect(origin: CGPoint(x: titleExpandedSize.width + 4.0, y: floor((titleExpandedSize.height - image.size.height) / 2.0) + 1.0), size: image.size))
|
||||||
self.titleExpandedCredibilityIconNode.isHidden = !isVerified
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let titleFrame: CGRect
|
let titleFrame: CGRect
|
||||||
|
@ -1219,9 +1219,9 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
|||||||
invitesText = ""
|
invitesText = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: {
|
// items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: {
|
||||||
interaction.editingOpenInviteLinksSetup()
|
// interaction.editingOpenInviteLinksSetup()
|
||||||
}))
|
// }))
|
||||||
|
|
||||||
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemDiscussionGroup, label: .text(discussionGroupTitle), text: presentationData.strings.Channel_DiscussionGroup, action: {
|
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemDiscussionGroup, label: .text(discussionGroupTitle), text: presentationData.strings.Channel_DiscussionGroup, action: {
|
||||||
interaction.editingOpenDiscussionGroupSetup()
|
interaction.editingOpenDiscussionGroupSetup()
|
||||||
@ -1303,9 +1303,9 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
|||||||
invitesText = ""
|
invitesText = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: {
|
// items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: {
|
||||||
interaction.editingOpenInviteLinksSetup()
|
// interaction.editingOpenInviteLinksSetup()
|
||||||
}))
|
// }))
|
||||||
}
|
}
|
||||||
|
|
||||||
if cachedData.flags.contains(.canChangeUsername) {
|
if cachedData.flags.contains(.canChangeUsername) {
|
||||||
@ -1387,9 +1387,9 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
|||||||
invitesText = ""
|
invitesText = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: {
|
// items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: {
|
||||||
interaction.editingOpenInviteLinksSetup()
|
// interaction.editingOpenInviteLinksSetup()
|
||||||
}))
|
// }))
|
||||||
|
|
||||||
items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPreHistory, label: .text(presentationData.strings.GroupInfo_GroupHistoryHidden), text: presentationData.strings.GroupInfo_GroupHistory, action: {
|
items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPreHistory, label: .text(presentationData.strings.GroupInfo_GroupHistoryHidden), text: presentationData.strings.GroupInfo_GroupHistory, action: {
|
||||||
interaction.editingOpenPreHistorySetup()
|
interaction.editingOpenPreHistorySetup()
|
||||||
@ -1412,6 +1412,8 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
|||||||
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemAdmins, text: presentationData.strings.GroupInfo_Administrators, action: {
|
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemAdmins, text: presentationData.strings.GroupInfo_Administrators, action: {
|
||||||
interaction.openParticipantsSection(.admins)
|
interaction.openParticipantsSection(.admins)
|
||||||
}))
|
}))
|
||||||
|
} else if case .admin = group.role {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3667,9 +3669,9 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
|||||||
|
|
||||||
let options: [PeerReportOption]
|
let options: [PeerReportOption]
|
||||||
if user {
|
if user {
|
||||||
options = [.spam, .violence, .pornography, .childAbuse]
|
options = [.spam, .fake, .violence, .pornography, .childAbuse]
|
||||||
} else {
|
} else {
|
||||||
options = [.spam, .violence, .pornography, .childAbuse, .copyright, .other]
|
options = [.spam, .fake, .violence, .pornography, .childAbuse, .copyright, .other]
|
||||||
}
|
}
|
||||||
controller.present(peerReportOptionsController(context: self.context, subject: .peer(self.peerId), options: options, present: { [weak controller] c, a in
|
controller.present(peerReportOptionsController(context: self.context, subject: .peer(self.peerId), options: options, present: { [weak controller] c, a in
|
||||||
controller?.present(c, in: .window(.root), with: a)
|
controller?.present(c, in: .window(.root), with: a)
|
||||||
|
@ -112,7 +112,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
self?.requestActivateSearch?()
|
self?.requestActivateSearch?()
|
||||||
}
|
}
|
||||||
|
|
||||||
self.chatListNode.peerSelected = { [weak self] peer, _, _ in
|
self.chatListNode.peerSelected = { [weak self] peer, _, _, _ in
|
||||||
self?.chatListNode.clearHighlightAnimated(true)
|
self?.chatListNode.clearHighlightAnimated(true)
|
||||||
self?.requestOpenPeer?(peer)
|
self?.requestOpenPeer?(peer)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user