Merge commit '0b1e72044aeb8a1286d90bb0ac5d61cf6e4c13d9'

This commit is contained in:
Ali 2021-01-23 22:45:45 +04:00
commit b13a0e9a06
23 changed files with 5037 additions and 491 deletions

View File

@ -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.GreetingText" = "Send a message or tap on the greeting below.";
"CallList.DeleteAllForMe" = "Delete for me";
"CallList.DeleteAllForEveryone" = "Delete for me and Others";
"Conversation.ImportProgress" = "Importing Messages... %@%";

View File

@ -583,7 +583,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
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 navigationController = strongSelf.navigationController as? NavigationController {
var scrollToEndIfExists = false
@ -591,7 +591,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
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)
if let promoInfo = promoInfo {
switch promoInfo {

View File

@ -475,8 +475,8 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
itemNode.listNode.deletePeerChat = { [weak self] peerId, joined in
self?.deletePeerChat?(peerId, joined)
}
itemNode.listNode.peerSelected = { [weak self] peerId, a, b in
self?.peerSelected?(peerId, a, b)
itemNode.listNode.peerSelected = { [weak self] peerId, animated, activateInput, promoInfo in
self?.peerSelected?(peerId, animated, activateInput, promoInfo)
}
itemNode.listNode.groupSelected = { [weak self] groupId in
self?.groupSelected?(groupId)
@ -522,7 +522,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
var toggleArchivedFolderHiddenByDefault: (() -> Void)?
var hidePsa: ((PeerId) -> Void)?
var deletePeerChat: ((PeerId, Bool) -> Void)?
var peerSelected: ((Peer, Bool, ChatListNodeEntryPromoInfo?) -> Void)?
var peerSelected: ((Peer, Bool, Bool, ChatListNodeEntryPromoInfo?) -> Void)?
var groupSelected: ((PeerGroupId) -> Void)?
var updatePeerGrouping: ((PeerId, Bool) -> Void)?
var contentOffsetChanged: ((ListViewVisibleContentOffset) -> Void)?

View File

@ -440,7 +440,7 @@ public final class ChatListNode: ListView {
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 additionalCategorySelected: ((Int) -> Void)?
public var groupSelected: ((PeerGroupId) -> Void)?
@ -565,7 +565,7 @@ public final class ChatListNode: ListView {
}
}, peerSelected: { [weak self] peer, promoInfo in
if let strongSelf = self, let peerSelected = strongSelf.peerSelected {
peerSelected(peer, true, promoInfo)
peerSelected(peer, true, true, promoInfo)
}
}, disabledPeerSelected: { [weak self] peer in
if let strongSelf = self, let disabledPeerSelected = strongSelf.disabledPeerSelected {
@ -594,7 +594,18 @@ public final class ChatListNode: ListView {
self?.additionalCategorySelected?(id)
}, messageSelected: { [weak self] peer, message, promoInfo in
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
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)
strongSelf.setChatListLocation(location)
strongSelf.peerSelected?(peer, false, nil)
strongSelf.peerSelected?(peer, false, false, nil)
})
case .previous(unread: false), .next(unread: false):
var target: (ChatListIndex, Peer)? = nil
@ -1774,7 +1785,7 @@ public final class ChatListNode: ListView {
if let target = target {
let location: ChatListNodeLocation = .scroll(index: target.0, sourceIndex: .absoluteLowerBound, scrollPosition: .center(.top), animated: true, filter: self.chatListFilter)
self.setChatListLocation(location)
self.peerSelected?(target.1, false, nil)
self.peerSelected?(target.1, false, false, nil)
}
case let .peerId(peerId):
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 {
return
}
strongSelf.peerSelected?(peer, false, nil)
strongSelf.peerSelected?(peer, false, false, nil)
})
case let .index(index):
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] {
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: .absoluteLowerBound, scrollPosition: .center(.top), animated: true, filter: filter)
self.setChatListLocation(location)
self.peerSelected?(renderedPeer.peer!, false, nil)
self.peerSelected?(renderedPeer.peer!, false, false, nil)
}
})
})

View File

@ -352,16 +352,16 @@ public final class InviteLinkInviteController: ViewController {
}
})))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor)
}, action: { _, f in
f(.dismissWithoutContent)
if let invite = invite {
let controller = InviteLinkQRCodeController(context: context, invite: invite)
self?.controller?.present(controller, in: .window(.root))
}
})))
// items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in
// return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor)
// }, action: { _, f in
// f(.dismissWithoutContent)
//
// if let invite = invite {
// let controller = InviteLinkQRCodeController(context: context, invite: invite)
// self?.controller?.present(controller, in: .window(.root))
// }
// })))
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)
@ -407,7 +407,8 @@ public final class InviteLinkInviteController: ViewController {
let previousEntries = Atomic<[InviteLinkInviteEntry]?>(value: nil)
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
if let strongSelf = self {
var entries: [InviteLinkInviteEntry] = []
@ -426,19 +427,19 @@ public final class InviteLinkInviteController: ViewController {
entries.append(.mainLink(presentationData.theme, mainInvite))
}
let additionalInvites = invites.invitations.filter { $0.link != mainInvite?.link }
var index: Int32 = 0
for i in stride(from: 0, to: additionalInvites.endIndex, by: 2) {
var invitesPair: [ExportedInvitation] = []
invitesPair.append(additionalInvites[i])
if i + 1 < additionalInvites.count {
invitesPair.append(additionalInvites[i + 1])
}
entries.append(.links(index, presentationData.theme, invitesPair))
index += 1
}
// let additionalInvites = invites.invitations.filter { $0.link != mainInvite?.link }
// var index: Int32 = 0
// for i in stride(from: 0, to: additionalInvites.endIndex, by: 2) {
// var invitesPair: [ExportedInvitation] = []
// invitesPair.append(additionalInvites[i])
// if i + 1 < additionalInvites.count {
// invitesPair.append(additionalInvites[i + 1])
// }
// entries.append(.links(index, presentationData.theme, invitesPair))
// 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)
@ -467,7 +468,6 @@ public final class InviteLinkInviteController: ViewController {
self.contentNode.addSubnode(self.headerNode)
self.headerNode.addSubnode(self.headerBackgroundNode)
// self.headerNode.addSubnode(self.titleNode)
self.headerNode.addSubnode(self.doneButton)
self.doneButton.addTarget(self, action: #selector(self.doneButtonPressed), forControlEvents: .touchUpInside)

View File

@ -53,23 +53,6 @@ private enum InviteLinkViewEntryId: Hashable {
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 {
case link(PresentationTheme, ExportedInvitation)
case creatorHeader(PresentationTheme, String)
@ -170,9 +153,8 @@ private enum InviteLinkViewEntry: Comparable, Identifiable {
func item(account: Account, presentationData: PresentationData, interaction: InviteLinkViewInteraction) -> ListViewItem {
switch self {
case let .link(_, invite):
let buttonColor = color(for: 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)
}, shareAction: {
interaction.shareLink(invite)
@ -383,13 +365,13 @@ public final class InviteLinkViewController: ViewController {
self.subtitleNode.maximumNumberOfLines = 1
self.subtitleNode.textAlignment = .center
let buttonColor = color(for: invite) ?? presentationData.theme.actionSheet.controlAccentColor
let accentColor = presentationData.theme.actionSheet.controlAccentColor
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.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.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.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
self.editButton.setTitle(self.presentationData.strings.Common_Edit, with: Font.regular(17.0), with: buttonColor, for: .normal)
self.doneButton.setTitle(self.presentationData.strings.Common_Done, with: Font.bold(17.0), with: buttonColor, for: .normal)
let accentColor = self.presentationData.theme.actionSheet.controlAccentColor
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: accentColor, for: .normal)
}
private func enqueueTransition(_ transition: InviteLinkViewTransaction) {

View File

@ -218,17 +218,29 @@ private class ItemNode: ASDisplayNode {
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
let availability = invitationAvailability(invite)
let transitionFraction: CGFloat
let color: ItemBackgroundColor
let nextColor: ItemBackgroundColor
if invite.isRevoked {
color = .gray
nextColor = .gray
transitionFraction = 0.0
} else if invite.expireDate == nil && invite.usageLimit == nil {
color = .blue
nextColor = .blue
transitionFraction = 0.0
} else if availability >= 0.5 {
color = .green
nextColor = .yellow
transitionFraction = (availability - 0.5) / 0.5
} else if availability > 0.0 {
color = .yellow
nextColor = .red
transitionFraction = availability / 0.5
} else {
color = .red
nextColor = .red
transitionFraction = 0.0
}
let previousParams = self.params
@ -239,8 +251,9 @@ private class ItemNode: ASDisplayNode {
self.updateTimer?.invalidate()
self.updateTimer = nil
if let _ = invite.expireDate, availability > 0.0 {
let updateTimer = SwiftSignalKit.Timer(timeout: 5.0, repeat: true, completion: { [weak self] in
if let expireDate = invite.expireDate, availability > 0.0 {
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 (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))
@ -255,9 +268,14 @@ private class ItemNode: ASDisplayNode {
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 previousColor != color {
if previousColor != color && color == .red {
if let snapshotView = self.wrapperNode.view.snapshotContentTree() {
snapshotView.frame = self.wrapperNode.bounds
self.wrapperNode.view.addSubview(snapshotView)
@ -266,12 +284,18 @@ private class ItemNode: ASDisplayNode {
})
}
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 {
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)
var inviteLink = invite.link.replacingOccurrences(of: "https://", with: "")

View File

@ -293,7 +293,7 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
case let .privateLinkHeader(_, title):
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
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 {
arguments.copyLink(invite)
}
@ -598,13 +598,13 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
} else {
entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Channel_Username_CreatePublicLinkHelp))
}
switch mode {
case .initialSetup:
break
case .generic, .privateLink:
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
}
// switch mode {
// case .initialSetup:
// break
// case .generic, .privateLink:
// entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
// entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
// }
}
case .privateChannel:
let invite = (view.cachedData as? CachedChannelData)?.exportedInvitation
@ -615,13 +615,13 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
} else {
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Channel_Username_CreatePrivateLinkHelp))
}
switch mode {
case .initialSetup:
break
case .generic, .privateLink:
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
}
// switch mode {
// case .initialSetup:
// break
// case .generic, .privateLink:
// entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
// entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
// }
}
} else if let _ = view.peers[view.peerId] as? TelegramGroup {
switch mode {
@ -630,13 +630,13 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_PermanentLink.uppercased()))
entries.append(.privateLink(presentationData.theme, invite, mode != .initialSetup))
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.GroupInfo_InviteLink_Help))
switch mode {
case .initialSetup:
break
case .generic, .privateLink:
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
}
// switch mode {
// case .initialSetup:
// break
// case .generic, .privateLink:
// entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
// entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
// }
case .generic, .initialSetup:
let selectedType: CurrentChannelType
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(.privateLink(presentationData.theme, invite, mode != .initialSetup))
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePrivateLinkHelp))
switch mode {
case .initialSetup:
break
case .generic, .privateLink:
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
}
// switch mode {
// case .initialSetup:
// break
// case .generic, .privateLink:
// entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
// 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
return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor)
}, action: { _, f in
f(.dismissWithoutContent)
let _ = (context.account.postbox.transaction { transaction -> ExportedInvitation? in
if let cachedData = transaction.getPeerCachedData(peerId: peerId) {
if let cachedData = cachedData as? CachedChannelData {
return cachedData.exportedInvitation
} else if let cachedData = cachedData as? CachedGroupData {
return cachedData.exportedInvitation
}
}
return nil
} |> deliverOnMainQueue).start(next: { invite in
if let invite = invite {
let controller = InviteLinkQRCodeController(context: context, invite: invite)
presentControllerImpl?(controller, nil)
}
})
})))
// items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in
// return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor)
// }, action: { _, f in
// f(.dismissWithoutContent)
//
// let _ = (context.account.postbox.transaction { transaction -> ExportedInvitation? in
// if let cachedData = transaction.getPeerCachedData(peerId: peerId) {
// if let cachedData = cachedData as? CachedChannelData {
// return cachedData.exportedInvitation
// } else if let cachedData = cachedData as? CachedGroupData {
// return cachedData.exportedInvitation
// }
// }
// return nil
// } |> deliverOnMainQueue).start(next: { invite in
// if let invite = invite {
// let controller = InviteLinkQRCodeController(context: context, invite: invite)
// presentControllerImpl?(controller, nil)
// }
// })
// })))
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)

View File

@ -354,7 +354,8 @@ public final class VoiceChatController: ViewController {
text = .text(presentationData.strings.VoiceChat_StatusMutedForYou, .destructive)
icon = .microphone(true, UIColor(rgb: 0xff3b30))
} 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)
} else {
text = .text(presentationData.strings.VoiceChat_StatusSpeaking, .constructive)
@ -1275,6 +1276,7 @@ public final class VoiceChatController: ViewController {
@objc private func closePressed() {
self.controller?.dismiss(closing: false)
self.controller?.dismissAllTooltips()
}
@objc private func leavePressed() {
@ -1284,11 +1286,13 @@ public final class VoiceChatController: ViewController {
|> deliverOnMainQueue).start(completed: { [weak self] in
self?.controller?.dismiss(closing: true)
}))
self.controller?.dismissAllTooltips()
}
@objc func dimTapGesture(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state {
self.controller?.dismiss(closing: false)
self.controller?.dismissAllTooltips()
}
}
@ -2144,6 +2148,8 @@ public final class VoiceChatController: ViewController {
topInset = self.listNode.frame.height
}
self.panGestureArguments = (topInset, 0.0)
self.controller?.dismissAllTooltips()
case .changed:
var translation = recognizer.translation(in: self.contentContainer.view).y
var topInset: CGFloat = 0.0
@ -2459,6 +2465,20 @@ public final class VoiceChatController: ViewController {
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() {
guard self.currentOverlayController == nil && !self.isDisconnected else {
return

View File

@ -85,6 +85,9 @@ private final class VoiceChatVolumeContextItemNode: ASDisplayNode, ContextMenuCu
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))
self.view.addGestureRecognizer(panGestureRecognizer)
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))
self.view.addGestureRecognizer(tapGestureRecognizer)
}
func updateTheme(presentationData: PresentationData) {
@ -180,4 +183,10 @@ private final class VoiceChatVolumeContextItemNode: ASDisplayNode, ContextMenuCu
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)
}
}

View File

@ -1094,12 +1094,6 @@ public final class GroupCallParticipantsContext {
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 current.state == muteState {
return
@ -1135,12 +1129,11 @@ public final class GroupCallParticipantsContext {
return .single(nil)
}
var flags: Int32 = 0
if let _ = volume {
if let volume = volume, volume > 0 {
flags |= 1 << 1
} else {
if let muteState = muteState, (!muteState.canUnmute || peerId == account.peerId || muteState.mutedByYou) {
flags |= 1 << 0
}
}
if let muteState = muteState, (!muteState.canUnmute || peerId == account.peerId || muteState.mutedByYou) {
flags |= 1 << 0
}
return account.network.request(Api.functions.phone.editGroupCallMember(flags: flags, call: .inputGroupCall(id: id, accessHash: accessHash), userId: inputUser, volume: volume))

View File

@ -258,6 +258,22 @@ public struct PeerExportedInvitationsState: Equatable {
public var hasLoadedOnce: Bool
public var canLoadMore: Bool
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 {

View File

@ -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 let account: Account
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)
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)
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 cloud
case peerNearby
case greeting
}
final class ChatEmptyNode: ASDisplayNode {
@ -668,6 +837,8 @@ final class ChatEmptyNode: ASDisplayNode {
contentType = .group
} else if let _ = interfaceState.peerNearbyData {
contentType = .peerNearby
} else if let _ = peer as? TelegramUser {
contentType = .greeting
} else {
contentType = .regular
}
@ -692,12 +863,14 @@ final class ChatEmptyNode: ASDisplayNode {
node = ChatEmptyNodeCloudChatContent()
case .peerNearby:
node = ChatEmptyNodeNearbyChatContent(account: self.account, interaction: self.interaction)
case .greeting:
node = ChatEmptyNodeGreetingChatContent(account: self.account, interaction: self.interaction)
}
self.content = (contentType, node)
self.addSubnode(node)
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))
@ -716,7 +889,9 @@ final class ChatEmptyNode: ASDisplayNode {
var greetingStickerNode: ASDisplayNode? {
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
}
}

View File

@ -203,11 +203,14 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
if entries.count <= 3 {
loop: for entry in view.entries {
var isEmptyMedia = false
var isPeerJoined = false
for media in entry.message.media {
if let action = media as? TelegramMediaAction {
switch action.action {
case .groupCreated, .photoUpdated, .channelMigratedFromGroup, .groupMigratedToChannel:
isEmptyMedia = true
case .peerJoined:
isPeerJoined = true
default:
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) {
isCreator = true
}
if isEmptyMedia && isCreator {
if isPeerJoined || (isEmptyMedia && isCreator) {
} else {
isEmpty = false
break loop

View File

@ -777,7 +777,7 @@ final class ChatPresentationInterfaceState: Equatable {
func canSendMessagesToChat(_ state: ChatPresentationInterfaceState) -> Bool {
if let peer = state.renderedPeer?.peer {
if canSendMessagesToPeer(peer) {
if true || canSendMessagesToPeer(peer) {
return true
} else {
return false

View File

@ -57,6 +57,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
private var titleLeftIcon: ChatTitleIcon = .none
private var titleRightIcon: ChatTitleIcon = .none
private var titleFakeIcon = false
private var titleScamIcon = false
//private var networkStatusNode: ChatTitleNetworkStatusNode?
@ -104,6 +105,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
var titleLeftIcon: ChatTitleIcon = .none
var titleRightIcon: ChatTitleIcon = .none
var titleScamIcon = false
var titleFakeIcon = false
var isEnabled = true
switch titleContent {
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))]
}
}
titleScamIcon = peer.isScam
if peer.isFake {
titleFakeIcon = true
} else if peer.isScam {
titleScamIcon = true
}
}
if peerView.peerId.namespace == Namespaces.Peer.SecretChat {
titleLeftIcon = .lock
@ -231,6 +237,12 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
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 {
self.titleScamIcon = titleScamIcon
self.titleCredibilityIconNode.image = titleScamIcon ? PresentationResourcesChatList.scamIcon(titleTheme, type: .regular) : nil

View File

@ -123,7 +123,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
self?.openPeer?(peer)
}
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))
}
chatsNode.additionalCategorySelected = { [weak self] id in

View File

@ -654,17 +654,17 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
discussionPeer = peer
}
if currentInvitationsContext == nil {
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)) {
canManageInvitations = true
}
if canManageInvitations {
let invitationsContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: true)
invitationsContextPromise.set(.single(invitationsContext))
invitationsStatePromise.set(invitationsContext.state |> map(Optional.init))
}
}
// if currentInvitationsContext == nil {
// 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)) {
// canManageInvitations = true
// }
// if canManageInvitations {
// let invitationsContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: true)
// invitationsContextPromise.set(.single(invitationsContext))
// invitationsStatePromise.set(invitationsContext.state |> map(Optional.init))
// }
// }
return PeerInfoScreenData(
peer: peerView.peers[peerId],
@ -811,19 +811,19 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
}
}
if currentInvitationsContext == nil {
var canManageInvitations = false
if let group = peerViewMainPeer(peerView) as? TelegramGroup, case .creator = group.role {
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)) {
canManageInvitations = true
}
if canManageInvitations {
let invitationsContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: true)
invitationsContextPromise.set(.single(invitationsContext))
invitationsStatePromise.set(invitationsContext.state |> map(Optional.init))
}
}
// if currentInvitationsContext == nil {
// var canManageInvitations = false
// if let group = peerViewMainPeer(peerView) as? TelegramGroup, case .creator = group.role {
// 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)) {
// canManageInvitations = true
// }
// if canManageInvitations {
// let invitationsContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: true)
// invitationsContextPromise.set(.single(invitationsContext))
// invitationsStatePromise.set(invitationsContext.state |> map(Optional.init))
// }
// }
return PeerInfoScreenData(
peer: peerView.peers[groupId],

View File

@ -2754,6 +2754,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
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 {
self.state = state
self.peer = peer
@ -2775,19 +2776,35 @@ final class PeerInfoHeaderNode: ASDisplayNode {
let themeUpdated = self.presentationData?.theme !== presentationData.theme
self.presentationData = presentationData
if themeUpdated {
if let sourceImage = UIImage(bundleImageName: "Peer Info/VerifiedIcon") {
let image = generateImage(sourceImage.size, contextGenerator: { size, context in
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))
})
self.titleCredibilityIconNode.image = image
self.titleExpandedCredibilityIconNode.image = image
if themeUpdated || !initializedCredibilityIcon {
let image: UIImage?
if let peer = peer {
self.initializedCredibilityIcon = true
if peer.isFake {
image = PresentationResourcesChatList.fakeIcon(presentationData.theme, type: .regular)
} else if peer.isScam {
image = PresentationResourcesChatList.scamIcon(presentationData.theme, type: .regular)
} else if peer.isVerified {
if let sourceImage = UIImage(bundleImageName: "Peer Info/VerifiedIcon") {
image = generateImage(sourceImage.size, contextGenerator: { size, context in
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
@ -2925,10 +2942,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
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))
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))
self.titleExpandedCredibilityIconNode.isHidden = !isVerified
}
let titleFrame: CGRect

View File

@ -1219,9 +1219,9 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
invitesText = ""
}
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: {
interaction.editingOpenInviteLinksSetup()
}))
// items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: {
// interaction.editingOpenInviteLinksSetup()
// }))
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemDiscussionGroup, label: .text(discussionGroupTitle), text: presentationData.strings.Channel_DiscussionGroup, action: {
interaction.editingOpenDiscussionGroupSetup()
@ -1303,9 +1303,9 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
invitesText = ""
}
items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: {
interaction.editingOpenInviteLinksSetup()
}))
// items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: {
// interaction.editingOpenInviteLinksSetup()
// }))
}
if cachedData.flags.contains(.canChangeUsername) {
@ -1387,9 +1387,9 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
invitesText = ""
}
items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: {
interaction.editingOpenInviteLinksSetup()
}))
// items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: {
// interaction.editingOpenInviteLinksSetup()
// }))
items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPreHistory, label: .text(presentationData.strings.GroupInfo_GroupHistoryHidden), text: presentationData.strings.GroupInfo_GroupHistory, action: {
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: {
interaction.openParticipantsSection(.admins)
}))
} else if case .admin = group.role {
}
}
}
@ -3667,9 +3669,9 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
let options: [PeerReportOption]
if user {
options = [.spam, .violence, .pornography, .childAbuse]
options = [.spam, .fake, .violence, .pornography, .childAbuse]
} 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(c, in: .window(.root), with: a)

View File

@ -112,7 +112,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
self?.requestActivateSearch?()
}
self.chatListNode.peerSelected = { [weak self] peer, _, _ in
self.chatListNode.peerSelected = { [weak self] peer, _, _, _ in
self?.chatListNode.clearHighlightAnimated(true)
self?.requestOpenPeer?(peer)
}