mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-08 08:31:13 +00:00
Merge commit 'aed14676171da506a0429e92b7eb9c4ebe2f62b0'
This commit is contained in:
commit
f8bf225170
@ -5825,6 +5825,7 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"InviteLink.Title" = "Invite Links";
|
"InviteLink.Title" = "Invite Links";
|
||||||
"InviteLink.PermanentLink" = "Permanent Link";
|
"InviteLink.PermanentLink" = "Permanent Link";
|
||||||
|
"InviteLink.PublicLink" = "Public Link";
|
||||||
"InviteLink.Share" = "Share Link";
|
"InviteLink.Share" = "Share Link";
|
||||||
"InviteLink.PeopleJoinedNone" = "no one joined yet";
|
"InviteLink.PeopleJoinedNone" = "no one joined yet";
|
||||||
"InviteLink.PeopleJoined_1" = "%@ people joined";
|
"InviteLink.PeopleJoined_1" = "%@ people joined";
|
||||||
@ -5895,6 +5896,8 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"InviteLink.ExpiresIn" = "expires in %@";
|
"InviteLink.ExpiresIn" = "expires in %@";
|
||||||
|
|
||||||
|
"InviteLink.InviteLinkCopiedText" = "Invite link copied to clipboard";
|
||||||
|
|
||||||
"Conversation.ChecksTooltip.Delivered" = "Delivered";
|
"Conversation.ChecksTooltip.Delivered" = "Delivered";
|
||||||
"Conversation.ChecksTooltip.Read" = "Read";
|
"Conversation.ChecksTooltip.Read" = "Read";
|
||||||
|
|
||||||
@ -5902,5 +5905,12 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"Common.Save" = "Save";
|
"Common.Save" = "Save";
|
||||||
|
|
||||||
|
"UserInfo.FakeUserWarning" = "⚠️ Warning: Many users reported that this account impersonates a famous person or organization.";
|
||||||
|
"UserInfo.FakeBotWarning" = "⚠️ Warning: Many users reported that this account impersonates a famous person or organization.";
|
||||||
|
"GroupInfo.FakeGroupWarning" = "⚠️ Warning: Many users reported that this account impersonates a famous person or organization.";
|
||||||
|
"ChannelInfo.FakeChannelWarning" = "⚠️ Warning: Many users reported that this account impersonates a famous person or organization.";
|
||||||
|
|
||||||
|
"ReportPeer.ReasonFake" = "Fake Account";
|
||||||
|
|
||||||
"ChatList.HeaderImportIntoAnExistingGroup" = "OR IMPORT INTO AN EXISTING GROUP";
|
"ChatList.HeaderImportIntoAnExistingGroup" = "OR IMPORT INTO AN EXISTING GROUP";
|
||||||
"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.";
|
||||||
|
@ -383,11 +383,13 @@ public struct ContactListAdditionalOption: Equatable {
|
|||||||
public let title: String
|
public let title: String
|
||||||
public let icon: ContactListActionItemIcon
|
public let icon: ContactListActionItemIcon
|
||||||
public let action: () -> Void
|
public let action: () -> Void
|
||||||
|
public let clearHighlightAutomatically: Bool
|
||||||
|
|
||||||
public init(title: String, icon: ContactListActionItemIcon, action: @escaping () -> Void) {
|
public init(title: String, icon: ContactListActionItemIcon, action: @escaping () -> Void, clearHighlightAutomatically: Bool = false) {
|
||||||
self.title = title
|
self.title = title
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
self.action = action
|
self.action = action
|
||||||
|
self.clearHighlightAutomatically = clearHighlightAutomatically
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: ContactListAdditionalOption, rhs: ContactListAdditionalOption) -> Bool {
|
public static func ==(lhs: ContactListAdditionalOption, rhs: ContactListAdditionalOption) -> Bool {
|
||||||
|
@ -1258,6 +1258,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
if peer.isScam {
|
if peer.isScam {
|
||||||
currentCredibilityIconImage = PresentationResourcesChatList.scamIcon(item.presentationData.theme, type: .regular)
|
currentCredibilityIconImage = PresentationResourcesChatList.scamIcon(item.presentationData.theme, type: .regular)
|
||||||
credibilityIconOffset = 2.0
|
credibilityIconOffset = 2.0
|
||||||
|
} else if peer.isFake {
|
||||||
|
currentCredibilityIconImage = PresentationResourcesChatList.fakeIcon(item.presentationData.theme, type: .regular)
|
||||||
|
credibilityIconOffset = 2.0
|
||||||
} else if peer.isVerified {
|
} else if peer.isVerified {
|
||||||
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
||||||
credibilityIconOffset = 3.0
|
credibilityIconOffset = 3.0
|
||||||
@ -1270,6 +1273,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
if peer.isScam {
|
if peer.isScam {
|
||||||
currentCredibilityIconImage = PresentationResourcesChatList.scamIcon(item.presentationData.theme, type: .regular)
|
currentCredibilityIconImage = PresentationResourcesChatList.scamIcon(item.presentationData.theme, type: .regular)
|
||||||
credibilityIconOffset = 2.0
|
credibilityIconOffset = 2.0
|
||||||
|
} else if peer.isFake {
|
||||||
|
currentCredibilityIconImage = PresentationResourcesChatList.fakeIcon(item.presentationData.theme, type: .regular)
|
||||||
|
credibilityIconOffset = 2.0
|
||||||
} else if peer.isVerified {
|
} else if peer.isVerified {
|
||||||
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
||||||
credibilityIconOffset = 3.0
|
credibilityIconOffset = 3.0
|
||||||
|
@ -175,7 +175,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
|||||||
interaction.authorize()
|
interaction.authorize()
|
||||||
})
|
})
|
||||||
case let .option(_, option, header, _, _):
|
case let .option(_, option, header, _, _):
|
||||||
return ContactListActionItem(presentationData: ItemListPresentationData(presentationData), title: option.title, icon: option.icon, clearHighlightAutomatically: false, header: header, action: option.action)
|
return ContactListActionItem(presentationData: ItemListPresentationData(presentationData), title: option.title, icon: option.icon, clearHighlightAutomatically: option.clearHighlightAutomatically, header: header, action: option.action)
|
||||||
case let .peer(_, peer, presence, header, selection, _, strings, dateTimeFormat, nameSortOrder, nameDisplayOrder, displayCallIcons, enabled):
|
case let .peer(_, peer, presence, header, selection, _, strings, dateTimeFormat, nameSortOrder, nameDisplayOrder, displayCallIcons, enabled):
|
||||||
var status: ContactsPeerItemStatus
|
var status: ContactsPeerItemStatus
|
||||||
let itemPeer: ContactsPeerItemPeer
|
let itemPeer: ContactsPeerItemPeer
|
||||||
|
@ -56,7 +56,7 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
|
|||||||
|
|
||||||
case usageHeader(PresentationTheme, String)
|
case usageHeader(PresentationTheme, String)
|
||||||
case usagePicker(PresentationTheme, InviteLinkUsageLimit)
|
case usagePicker(PresentationTheme, InviteLinkUsageLimit)
|
||||||
case usageCustomPicker(PresentationTheme, Int32?, Bool)
|
case usageCustomPicker(PresentationTheme, Int32?, Bool, Bool)
|
||||||
case usageInfo(PresentationTheme, String)
|
case usageInfo(PresentationTheme, String)
|
||||||
|
|
||||||
case revoke(PresentationTheme, String)
|
case revoke(PresentationTheme, String)
|
||||||
@ -141,8 +141,8 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .usageCustomPicker(lhsTheme, lhsValue, lhsFocused):
|
case let .usageCustomPicker(lhsTheme, lhsValue, lhsFocused, lhsCustomValue):
|
||||||
if case let .usageCustomPicker(rhsTheme, rhsValue, rhsFocused) = rhs, lhsTheme === rhsTheme, lhsValue == rhsValue, lhsFocused == rhsFocused {
|
if case let .usageCustomPicker(rhsTheme, rhsValue, rhsFocused, rhsCustomValue) = rhs, lhsTheme === rhsTheme, lhsValue == rhsValue, lhsFocused == rhsFocused, lhsCustomValue == rhsCustomValue {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -221,9 +221,14 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
|
|||||||
return updatedState
|
return updatedState
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
case let .usageCustomPicker(theme, value, focused):
|
case let .usageCustomPicker(theme, value, focused, customValue):
|
||||||
let text = value.flatMap { String($0) } ?? (focused ? "" : presentationData.strings.InviteLink_Create_UsersLimitNumberOfUsersUnlimited)
|
let text: String
|
||||||
return ItemListSingleLineInputItem(presentationData: presentationData, title: NSAttributedString(string: presentationData.strings.InviteLink_Create_UsersLimitNumberOfUsers, textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: "", type: .number, alignment: .right, selectAllOnFocus: true, tag: nil, sectionId: self.section, textUpdated: { updatedText in
|
if let value = value, value != 0 {
|
||||||
|
text = String(value)
|
||||||
|
} else {
|
||||||
|
text = focused ? "" : presentationData.strings.InviteLink_Create_UsersLimitNumberOfUsersUnlimited
|
||||||
|
}
|
||||||
|
return ItemListSingleLineInputItem(presentationData: presentationData, title: NSAttributedString(string: presentationData.strings.InviteLink_Create_UsersLimitNumberOfUsers, textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: "", type: .number, alignment: .right, selectAllOnFocus: true, secondaryStyle: !customValue, tag: nil, sectionId: self.section, textUpdated: { updatedText in
|
||||||
guard !updatedText.isEmpty else {
|
guard !updatedText.isEmpty else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -284,7 +289,12 @@ private func inviteLinkEditControllerEntries(invite: ExportedInvitation?, state:
|
|||||||
|
|
||||||
entries.append(.usageHeader(presentationData.theme, presentationData.strings.InviteLink_Create_UsersLimit.uppercased()))
|
entries.append(.usageHeader(presentationData.theme, presentationData.strings.InviteLink_Create_UsersLimit.uppercased()))
|
||||||
entries.append(.usagePicker(presentationData.theme, state.usage))
|
entries.append(.usagePicker(presentationData.theme, state.usage))
|
||||||
entries.append(.usageCustomPicker(presentationData.theme, state.usage.value, state.pickingUsageLimit))
|
|
||||||
|
var customValue = false
|
||||||
|
if case .custom = state.usage {
|
||||||
|
customValue = true
|
||||||
|
}
|
||||||
|
entries.append(.usageCustomPicker(presentationData.theme, state.usage.value, state.pickingUsageLimit, customValue))
|
||||||
|
|
||||||
entries.append(.usageInfo(presentationData.theme, presentationData.strings.InviteLink_Create_UsersLimitInfo))
|
entries.append(.usageInfo(presentationData.theme, presentationData.strings.InviteLink_Create_UsersLimitInfo))
|
||||||
|
|
||||||
@ -401,7 +411,7 @@ public func inviteLinkEditController(context: AccountContext, peerId: PeerId, in
|
|||||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||||
expireDate = currentTime + value
|
expireDate = currentTime + value
|
||||||
} else {
|
} else {
|
||||||
expireDate = nil
|
expireDate = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
let usageLimit = state.usage.value
|
let usageLimit = state.usage.value
|
||||||
|
@ -20,6 +20,7 @@ import ShareController
|
|||||||
import OverlayStatusController
|
import OverlayStatusController
|
||||||
import PresentationDataUtils
|
import PresentationDataUtils
|
||||||
import DirectionalPanGesture
|
import DirectionalPanGesture
|
||||||
|
import UndoUI
|
||||||
|
|
||||||
class InviteLinkInviteInteraction {
|
class InviteLinkInviteInteraction {
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
@ -139,7 +140,7 @@ private enum InviteLinkInviteEntry: Comparable, Identifiable {
|
|||||||
case let .header(theme, title, text):
|
case let .header(theme, title, text):
|
||||||
return InviteLinkInviteHeaderItem(theme: theme, title: title, text: text)
|
return InviteLinkInviteHeaderItem(theme: theme, title: title, text: text)
|
||||||
case let .mainLink(_, invite):
|
case let .mainLink(_, invite):
|
||||||
return ItemListPermanentInviteLinkItem(context: interaction.context, presentationData: ItemListPresentationData(presentationData), invite: invite, peers: [], displayButton: true, displayImporters: false, buttonColor: nil, sectionId: 0, style: .plain, copyAction: {
|
return ItemListPermanentInviteLinkItem(context: interaction.context, presentationData: ItemListPresentationData(presentationData), invite: invite, count: 0, peers: [], displayButton: true, displayImporters: false, buttonColor: nil, sectionId: 0, style: .plain, copyAction: {
|
||||||
interaction.copyLink(invite)
|
interaction.copyLink(invite)
|
||||||
}, shareAction: {
|
}, shareAction: {
|
||||||
interaction.shareLink(invite)
|
interaction.shareLink(invite)
|
||||||
@ -345,8 +346,9 @@ public final class InviteLinkInviteController: ViewController {
|
|||||||
|
|
||||||
if let invite = invite {
|
if let invite = invite {
|
||||||
UIPasteboard.general.string = invite.link
|
UIPasteboard.general.string = invite.link
|
||||||
|
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
self?.controller?.present(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.Username_LinkCopied, false)), in: .window(.root))
|
self?.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||||
}
|
}
|
||||||
})))
|
})))
|
||||||
|
|
||||||
@ -390,8 +392,9 @@ public final class InviteLinkInviteController: ViewController {
|
|||||||
self?.controller?.presentInGlobalOverlay(contextController)
|
self?.controller?.presentInGlobalOverlay(contextController)
|
||||||
}, copyLink: { [weak self] invite in
|
}, copyLink: { [weak self] invite in
|
||||||
UIPasteboard.general.string = invite.link
|
UIPasteboard.general.string = invite.link
|
||||||
|
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
self?.controller?.present(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.Username_LinkCopied, false)), in: .window(.root))
|
self?.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||||
}, shareLink: { [weak self] invite in
|
}, shareLink: { [weak self] invite in
|
||||||
let shareController = ShareController(context: context, subject: .url(invite.link))
|
let shareController = ShareController(context: context, subject: .url(invite.link))
|
||||||
self?.controller?.present(shareController, in: .window(.root))
|
self?.controller?.present(shareController, in: .window(.root))
|
||||||
@ -626,6 +629,10 @@ public final class InviteLinkInviteController: ViewController {
|
|||||||
|
|
||||||
private var panGestureArguments: CGFloat?
|
private var panGestureArguments: CGFloat?
|
||||||
|
|
||||||
|
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||||
|
return gestureRecognizer is DirectionalPanGestureRecognizer && otherGestureRecognizer is UIPanGestureRecognizer
|
||||||
|
}
|
||||||
|
|
||||||
@objc func panGesture(_ recognizer: UIPanGestureRecognizer) {
|
@objc func panGesture(_ recognizer: UIPanGestureRecognizer) {
|
||||||
let contentOffset = self.listNode.visibleContentOffset()
|
let contentOffset = self.listNode.visibleContentOffset()
|
||||||
switch recognizer.state {
|
switch recognizer.state {
|
||||||
@ -633,10 +640,20 @@ public final class InviteLinkInviteController: ViewController {
|
|||||||
self.panGestureArguments = 0.0
|
self.panGestureArguments = 0.0
|
||||||
case .changed:
|
case .changed:
|
||||||
var translation = recognizer.translation(in: self.contentNode.view).y
|
var translation = recognizer.translation(in: self.contentNode.view).y
|
||||||
if let currentPanOffset = self.panGestureArguments {
|
if let currentOffset = self.panGestureArguments {
|
||||||
if case let .known(value) = contentOffset, value <= 0.5 {
|
if case let .known(value) = contentOffset, value <= 0.5 {
|
||||||
|
if currentOffset > 0.0 {
|
||||||
|
let translation = self.listNode.scroller.panGestureRecognizer.translation(in: self.listNode.scroller)
|
||||||
|
if translation.y > 10.0 {
|
||||||
|
self.listNode.scroller.panGestureRecognizer.isEnabled = false
|
||||||
|
self.listNode.scroller.panGestureRecognizer.isEnabled = true
|
||||||
} else {
|
} else {
|
||||||
translation = currentPanOffset
|
self.listNode.scroller.panGestureRecognizer.setTranslation(CGPoint(), in: self.listNode.scroller)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
translation = 0.0
|
||||||
|
recognizer.setTranslation(CGPoint(), in: self.contentNode.view)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.panGestureArguments = translation
|
self.panGestureArguments = translation
|
||||||
|
@ -19,6 +19,7 @@ import ContextUI
|
|||||||
import TelegramStringFormatting
|
import TelegramStringFormatting
|
||||||
import ItemListPeerActionItem
|
import ItemListPeerActionItem
|
||||||
import ShareController
|
import ShareController
|
||||||
|
import UndoUI
|
||||||
|
|
||||||
private final class InviteLinkListControllerArguments {
|
private final class InviteLinkListControllerArguments {
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
@ -55,7 +56,7 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
|
|||||||
case header(PresentationTheme, String)
|
case header(PresentationTheme, String)
|
||||||
|
|
||||||
case mainLinkHeader(PresentationTheme, String)
|
case mainLinkHeader(PresentationTheme, String)
|
||||||
case mainLink(PresentationTheme, ExportedInvitation?, [Peer])
|
case mainLink(PresentationTheme, ExportedInvitation?, [Peer], Int32, Bool)
|
||||||
|
|
||||||
case linksHeader(PresentationTheme, String)
|
case linksHeader(PresentationTheme, String)
|
||||||
case linksCreate(PresentationTheme, String)
|
case linksCreate(PresentationTheme, String)
|
||||||
@ -117,8 +118,8 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .mainLink(lhsTheme, lhsInvite, lhsPeers):
|
case let .mainLink(lhsTheme, lhsInvite, lhsPeers, lhsImportersCount, lhsIsPublic):
|
||||||
if case let .mainLink(rhsTheme, rhsInvite, rhsPeers) = rhs, lhsTheme === rhsTheme, lhsInvite == rhsInvite, arePeerArraysEqual(lhsPeers, rhsPeers) {
|
if case let .mainLink(rhsTheme, rhsInvite, rhsPeers, rhsImportersCount, rhsIsPublic) = rhs, lhsTheme === rhsTheme, lhsInvite == rhsInvite, arePeerArraysEqual(lhsPeers, rhsPeers), lhsImportersCount == rhsImportersCount, lhsIsPublic == rhsIsPublic {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -179,8 +180,8 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
|
|||||||
return InviteLinkHeaderItem(theme: theme, text: text, sectionId: self.section)
|
return InviteLinkHeaderItem(theme: theme, text: text, sectionId: self.section)
|
||||||
case let .mainLinkHeader(_, text):
|
case let .mainLinkHeader(_, text):
|
||||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||||
case let .mainLink(_, invite, peers):
|
case let .mainLink(_, invite, peers, importersCount, isPublic):
|
||||||
return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: invite, peers: peers, displayButton: true, displayImporters: true, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: {
|
return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: invite, count: importersCount, peers: peers, displayButton: true, displayImporters: !isPublic, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: {
|
||||||
if let invite = invite {
|
if let invite = invite {
|
||||||
arguments.copyLink(invite)
|
arguments.copyLink(invite)
|
||||||
}
|
}
|
||||||
@ -225,14 +226,18 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func inviteLinkListControllerEntries(presentationData: PresentationData, view: PeerView, invites: [ExportedInvitation]?, revokedInvites: [ExportedInvitation]?, mainPeers: [Peer]) -> [InviteLinksListEntry] {
|
private func inviteLinkListControllerEntries(presentationData: PresentationData, view: PeerView, invites: [ExportedInvitation]?, revokedInvites: [ExportedInvitation]?, importers: PeerInvitationImportersState?) -> [InviteLinksListEntry] {
|
||||||
var entries: [InviteLinksListEntry] = []
|
var entries: [InviteLinksListEntry] = []
|
||||||
|
|
||||||
entries.append(.header(presentationData.theme, presentationData.strings.InviteLink_CreatePrivateLinkHelp))
|
entries.append(.header(presentationData.theme, presentationData.strings.InviteLink_CreatePrivateLinkHelp))
|
||||||
entries.append(.mainLinkHeader(presentationData.theme, presentationData.strings.InviteLink_PermanentLink.uppercased()))
|
|
||||||
|
|
||||||
let mainInvite: ExportedInvitation?
|
let mainInvite: ExportedInvitation?
|
||||||
if let invites = invites, let invite = invites.first(where: { $0.isPermanent && !$0.isRevoked }) {
|
var isPublic = false
|
||||||
|
if let peer = peerViewMainPeer(view), let address = peer.addressName, !address.isEmpty {
|
||||||
|
mainInvite = ExportedInvitation(link: "t.me/\(address)", isPermanent: true, isRevoked: false, adminId: PeerId(0), date: 0, startDate: nil, expireDate: nil, usageLimit: nil, count: nil)
|
||||||
|
isPublic = true
|
||||||
|
} else if let invites = invites, let invite = invites.first(where: { $0.isPermanent && !$0.isRevoked }) {
|
||||||
mainInvite = invite
|
mainInvite = invite
|
||||||
} else if let invite = (view.cachedData as? CachedChannelData)?.exportedInvitation {
|
} else if let invite = (view.cachedData as? CachedChannelData)?.exportedInvitation {
|
||||||
mainInvite = invite
|
mainInvite = invite
|
||||||
@ -241,7 +246,19 @@ private func inviteLinkListControllerEntries(presentationData: PresentationData,
|
|||||||
} else {
|
} else {
|
||||||
mainInvite = nil
|
mainInvite = nil
|
||||||
}
|
}
|
||||||
entries.append(.mainLink(presentationData.theme, mainInvite, mainPeers))
|
|
||||||
|
entries.append(.mainLinkHeader(presentationData.theme, isPublic ? presentationData.strings.InviteLink_PublicLink.uppercased() : presentationData.strings.InviteLink_PermanentLink.uppercased()))
|
||||||
|
|
||||||
|
let importersCount: Int32
|
||||||
|
if let count = importers?.count {
|
||||||
|
importersCount = count
|
||||||
|
} else if let count = mainInvite?.count {
|
||||||
|
importersCount = count
|
||||||
|
} else {
|
||||||
|
importersCount = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.append(.mainLink(presentationData.theme, mainInvite, importers?.importers.prefix(3).compactMap { $0.peer.peer } ?? [], importersCount, isPublic))
|
||||||
|
|
||||||
entries.append(.linksHeader(presentationData.theme, presentationData.strings.InviteLink_AdditionalLinks.uppercased()))
|
entries.append(.linksHeader(presentationData.theme, presentationData.strings.InviteLink_AdditionalLinks.uppercased()))
|
||||||
entries.append(.linksCreate(presentationData.theme, presentationData.strings.InviteLink_Create))
|
entries.append(.linksCreate(presentationData.theme, presentationData.strings.InviteLink_Create))
|
||||||
@ -320,10 +337,11 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
|||||||
pushControllerImpl?(controller)
|
pushControllerImpl?(controller)
|
||||||
}, copyLink: { invite in
|
}, copyLink: { invite in
|
||||||
UIPasteboard.general.string = invite.link
|
UIPasteboard.general.string = invite.link
|
||||||
|
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
presentControllerImpl?(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.Username_LinkCopied, false)), nil)
|
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||||
}, mainLinkContextAction: { invite, node, gesture in
|
}, mainLinkContextAction: { invite, node, gesture in
|
||||||
guard let node = node as? ContextExtractedContentContainingNode, let controller = getControllerImpl?() else {
|
guard let node = node as? ContextExtractedContentContainingNode, let controller = getControllerImpl?(), let invite = invite else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
@ -334,11 +352,10 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
|||||||
}, action: { _, f in
|
}, action: { _, f in
|
||||||
f(.dismissWithoutContent)
|
f(.dismissWithoutContent)
|
||||||
|
|
||||||
if let invite = invite {
|
|
||||||
UIPasteboard.general.string = invite.link
|
UIPasteboard.general.string = invite.link
|
||||||
|
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
presentControllerImpl?(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.Username_LinkCopied, false)), nil)
|
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||||
}
|
|
||||||
})))
|
})))
|
||||||
|
|
||||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in
|
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in
|
||||||
@ -346,12 +363,11 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
|||||||
}, action: { _, f in
|
}, action: { _, f in
|
||||||
f(.dismissWithoutContent)
|
f(.dismissWithoutContent)
|
||||||
|
|
||||||
if let invite = invite {
|
|
||||||
let controller = InviteLinkQRCodeController(context: context, invite: invite)
|
let controller = InviteLinkQRCodeController(context: context, invite: invite)
|
||||||
presentControllerImpl?(controller, nil)
|
presentControllerImpl?(controller, nil)
|
||||||
}
|
|
||||||
})))
|
})))
|
||||||
|
|
||||||
|
if invite.adminId.toInt64() != 0 {
|
||||||
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)
|
||||||
}, action: { _, f in
|
}, action: { _, f in
|
||||||
@ -396,6 +412,7 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
|||||||
])
|
])
|
||||||
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||||
})))
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture)
|
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture)
|
||||||
presentInGlobalOverlayImpl?(contextController)
|
presentInGlobalOverlayImpl?(contextController)
|
||||||
@ -426,11 +443,21 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
|||||||
f(.dismissWithoutContent)
|
f(.dismissWithoutContent)
|
||||||
|
|
||||||
UIPasteboard.general.string = invite.link
|
UIPasteboard.general.string = invite.link
|
||||||
|
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
presentControllerImpl?(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.Username_LinkCopied, false)), nil)
|
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||||
})))
|
})))
|
||||||
|
|
||||||
if !invite.isRevoked {
|
if !invite.isRevoked {
|
||||||
|
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextShare, icon: { theme in
|
||||||
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor)
|
||||||
|
}, action: { _, f in
|
||||||
|
f(.dismissWithoutContent)
|
||||||
|
|
||||||
|
let shareController = ShareController(context: context, subject: .url(invite.link))
|
||||||
|
presentControllerImpl?(shareController, nil)
|
||||||
|
})))
|
||||||
|
|
||||||
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
|
||||||
@ -546,29 +573,41 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
|||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
|
|
||||||
let importersState = Promise<PeerInvitationImportersState?>(nil)
|
let importersState = Promise<PeerInvitationImportersState?>(nil)
|
||||||
let importersContext: Signal<PeerInvitationImportersContext, NoError> = peerView
|
let importersContext: Signal<PeerInvitationImportersContext?, NoError> = peerView
|
||||||
|> mapToSignal { view -> Signal<ExportedInvitation, NoError> in
|
|> mapToSignal { view -> Signal<ExportedInvitation?, NoError> in
|
||||||
if let cachedData = view.cachedData as? CachedGroupData, let exportedInvitation = cachedData.exportedInvitation {
|
if let cachedData = view.cachedData as? CachedGroupData, let exportedInvitation = cachedData.exportedInvitation {
|
||||||
return .single(exportedInvitation)
|
return .single(exportedInvitation)
|
||||||
} else if let cachedData = view.cachedData as? CachedChannelData, let exportedInvitation = cachedData.exportedInvitation {
|
} else if let cachedData = view.cachedData as? CachedChannelData, let exportedInvitation = cachedData.exportedInvitation {
|
||||||
return .single(exportedInvitation)
|
return .single(exportedInvitation)
|
||||||
} else {
|
} else {
|
||||||
return .complete()
|
return .single(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> distinctUntilChanged
|
|> distinctUntilChanged
|
||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
|> map { invite -> PeerInvitationImportersContext in
|
|> map { invite -> PeerInvitationImportersContext? in
|
||||||
return PeerInvitationImportersContext(account: context.account, peerId: peerId, invite: invite)
|
return invite.flatMap { PeerInvitationImportersContext(account: context.account, peerId: peerId, invite: $0) }
|
||||||
} |> afterNext { context in
|
} |> afterNext { context in
|
||||||
|
if let context = context {
|
||||||
importersState.set(context.state |> map(Optional.init))
|
importersState.set(context.state |> map(Optional.init))
|
||||||
|
} else {
|
||||||
|
importersState.set(.single(nil))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let previousRevokedInvites = Atomic<PeerExportedInvitationsState?>(value: nil)
|
||||||
let signal = combineLatest(context.sharedContext.presentationData, peerView, importersContext, importersState.get(), invitesContext.state, revokedInvitesContext.state)
|
let signal = combineLatest(context.sharedContext.presentationData, peerView, importersContext, importersState.get(), invitesContext.state, revokedInvitesContext.state)
|
||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
|> map { presentationData, view, importersContext, importers, invites, revokedInvites -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
|> map { presentationData, view, importersContext, importers, invites, revokedInvites -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||||
|
let previousRevokedInvites = previousRevokedInvites.swap(invites)
|
||||||
|
|
||||||
|
var crossfade = false
|
||||||
|
if (previousRevokedInvites?.hasLoadedOnce ?? false) != (revokedInvites.hasLoadedOnce) {
|
||||||
|
crossfade = true
|
||||||
|
}
|
||||||
|
|
||||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.InviteLink_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
|
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.InviteLink_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
|
||||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: inviteLinkListControllerEntries(presentationData: presentationData, view: view, invites: invites.invitations, revokedInvites: revokedInvites.invitations, mainPeers: importers?.importers.compactMap { $0.peer.peer } ?? []), style: .blocks, emptyStateItem: nil, crossfadeState: false, animateChanges: false)
|
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: inviteLinkListControllerEntries(presentationData: presentationData, view: view, invites: invites.invitations, revokedInvites: revokedInvites.invitations, importers: importers), style: .blocks, emptyStateItem: nil, crossfadeState: crossfade, animateChanges: false)
|
||||||
|
|
||||||
return (controllerState, (listState, arguments))
|
return (controllerState, (listState, arguments))
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import ShareController
|
|||||||
import OverlayStatusController
|
import OverlayStatusController
|
||||||
import PresentationDataUtils
|
import PresentationDataUtils
|
||||||
import DirectionalPanGesture
|
import DirectionalPanGesture
|
||||||
|
import UndoUI
|
||||||
|
|
||||||
class InviteLinkViewInteraction {
|
class InviteLinkViewInteraction {
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
@ -171,7 +172,7 @@ private enum InviteLinkViewEntry: Comparable, Identifiable {
|
|||||||
case let .link(_, invite):
|
case let .link(_, invite):
|
||||||
let buttonColor = color(for: invite)
|
let buttonColor = color(for: invite)
|
||||||
let availability = invitationAvailability(invite)
|
let availability = invitationAvailability(invite)
|
||||||
return ItemListPermanentInviteLinkItem(context: interaction.context, presentationData: ItemListPresentationData(presentationData), invite: invite, 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: buttonColor, sectionId: 0, style: .plain, copyAction: {
|
||||||
interaction.copyLink(invite)
|
interaction.copyLink(invite)
|
||||||
}, shareAction: {
|
}, shareAction: {
|
||||||
interaction.shareLink(invite)
|
interaction.shareLink(invite)
|
||||||
@ -393,8 +394,9 @@ public final class InviteLinkViewController: ViewController {
|
|||||||
}
|
}
|
||||||
}, copyLink: { [weak self] invite in
|
}, copyLink: { [weak self] invite in
|
||||||
UIPasteboard.general.string = invite.link
|
UIPasteboard.general.string = invite.link
|
||||||
|
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
self?.controller?.present(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.Username_LinkCopied, false)), in: .window(.root))
|
self?.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||||
}, shareLink: { [weak self] invite in
|
}, shareLink: { [weak self] invite in
|
||||||
let shareController = ShareController(context: context, subject: .url(invite.link))
|
let shareController = ShareController(context: context, subject: .url(invite.link))
|
||||||
self?.controller?.present(shareController, in: .window(.root))
|
self?.controller?.present(shareController, in: .window(.root))
|
||||||
@ -412,8 +414,9 @@ public final class InviteLinkViewController: ViewController {
|
|||||||
f(.dismissWithoutContent)
|
f(.dismissWithoutContent)
|
||||||
|
|
||||||
UIPasteboard.general.string = invite.link
|
UIPasteboard.general.string = invite.link
|
||||||
|
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
self?.controller?.present(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.Username_LinkCopied, false)), in: .window(.root))
|
self?.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||||
})))
|
})))
|
||||||
|
|
||||||
if invite.isRevoked {
|
if invite.isRevoked {
|
||||||
@ -453,6 +456,8 @@ public final class InviteLinkViewController: ViewController {
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture)
|
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture)
|
||||||
self?.controller?.presentInGlobalOverlay(contextController)
|
self?.controller?.presentInGlobalOverlay(contextController)
|
||||||
})
|
})
|
||||||
@ -717,12 +722,20 @@ public final class InviteLinkViewController: ViewController {
|
|||||||
self.panGestureArguments = 0.0
|
self.panGestureArguments = 0.0
|
||||||
case .changed:
|
case .changed:
|
||||||
var translation = recognizer.translation(in: self.contentNode.view).y
|
var translation = recognizer.translation(in: self.contentNode.view).y
|
||||||
if let currentPanOffset = self.panGestureArguments {
|
if let currentOffset = self.panGestureArguments {
|
||||||
|
|
||||||
|
|
||||||
if case let .known(value) = contentOffset, value <= 0.5 {
|
if case let .known(value) = contentOffset, value <= 0.5 {
|
||||||
|
if currentOffset > 0.0 {
|
||||||
|
let translation = self.listNode.scroller.panGestureRecognizer.translation(in: self.listNode.scroller)
|
||||||
|
if translation.y > 10.0 {
|
||||||
|
self.listNode.scroller.panGestureRecognizer.isEnabled = false
|
||||||
|
self.listNode.scroller.panGestureRecognizer.isEnabled = true
|
||||||
} else {
|
} else {
|
||||||
translation = currentPanOffset
|
self.listNode.scroller.panGestureRecognizer.setTranslation(CGPoint(), in: self.listNode.scroller)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
translation = 0.0
|
||||||
|
recognizer.setTranslation(CGPoint(), in: self.contentNode.view)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.panGestureArguments = translation
|
self.panGestureArguments = translation
|
||||||
|
@ -96,7 +96,8 @@ private let shareIcon = generateImage(CGSize(width: 26.0, height: 26.0), context
|
|||||||
private class ItemNode: ASDisplayNode {
|
private class ItemNode: ASDisplayNode {
|
||||||
private let selectionNode: HighlightTrackingButtonNode
|
private let selectionNode: HighlightTrackingButtonNode
|
||||||
private let wrapperNode: ASDisplayNode
|
private let wrapperNode: ASDisplayNode
|
||||||
private let backgroundNode: ASImageNode
|
private let backgroundNode: ASDisplayNode
|
||||||
|
private let backgroundGradientLayer: CAGradientLayer
|
||||||
|
|
||||||
private let iconNode: ASImageNode
|
private let iconNode: ASImageNode
|
||||||
private var timerNode: TimerNode?
|
private var timerNode: TimerNode?
|
||||||
@ -122,11 +123,19 @@ private class ItemNode: ASDisplayNode {
|
|||||||
self.selectionNode = HighlightTrackingButtonNode()
|
self.selectionNode = HighlightTrackingButtonNode()
|
||||||
self.wrapperNode = ASDisplayNode()
|
self.wrapperNode = ASDisplayNode()
|
||||||
|
|
||||||
self.backgroundNode = ASImageNode()
|
self.backgroundNode = ASDisplayNode()
|
||||||
self.backgroundNode.displaysAsynchronously = false
|
self.backgroundNode.clipsToBounds = true
|
||||||
self.backgroundNode.displayWithoutProcessing = true
|
self.backgroundNode.cornerRadius = 15.0
|
||||||
|
if #available(iOS 13.0, *) {
|
||||||
|
self.backgroundNode.layer.cornerCurve = .continuous
|
||||||
|
}
|
||||||
self.backgroundNode.isUserInteractionEnabled = false
|
self.backgroundNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
|
self.backgroundGradientLayer = CAGradientLayer()
|
||||||
|
self.backgroundGradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0)
|
||||||
|
self.backgroundGradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0)
|
||||||
|
self.backgroundNode.layer.addSublayer(self.backgroundGradientLayer)
|
||||||
|
|
||||||
self.iconNode = ASImageNode()
|
self.iconNode = ASImageNode()
|
||||||
self.iconNode.displaysAsynchronously = false
|
self.iconNode.displaysAsynchronously = false
|
||||||
self.iconNode.displayWithoutProcessing = true
|
self.iconNode.displayWithoutProcessing = true
|
||||||
@ -256,10 +265,10 @@ private class ItemNode: ASDisplayNode {
|
|||||||
snapshotView?.removeFromSuperview()
|
snapshotView?.removeFromSuperview()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
self.backgroundNode.image = generateBackgroundImage(colors: colors)
|
self.backgroundGradientLayer.colors = colors as? [Any]
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.backgroundNode.image = generateBackgroundImage(colors: colors)
|
self.backgroundGradientLayer.colors = colors as? [Any]
|
||||||
}
|
}
|
||||||
|
|
||||||
let secondaryTextColor = color.colors.text
|
let secondaryTextColor = color.colors.text
|
||||||
@ -329,7 +338,7 @@ private class ItemNode: ASDisplayNode {
|
|||||||
self.timerNode = timerNode
|
self.timerNode = timerNode
|
||||||
self.addSubnode(timerNode)
|
self.addSubnode(timerNode)
|
||||||
}
|
}
|
||||||
timerNode.update(color: UIColor.white, creationTimestamp: invite.date, deadlineTimestamp: expireDate)
|
timerNode.update(color: UIColor.white, creationTimestamp: invite.startDate ?? invite.date, deadlineTimestamp: expireDate)
|
||||||
if share {
|
if share {
|
||||||
subtitleText = presentationData.strings.InviteLink_TapToCopy
|
subtitleText = presentationData.strings.InviteLink_TapToCopy
|
||||||
}
|
}
|
||||||
@ -359,6 +368,7 @@ private class ItemNode: ASDisplayNode {
|
|||||||
transition.updateFrame(node: self.wrapperNode, frame: backgroundFrame)
|
transition.updateFrame(node: self.wrapperNode, frame: backgroundFrame)
|
||||||
transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame)
|
transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame)
|
||||||
transition.updateFrame(node: self.selectionNode, frame: backgroundFrame)
|
transition.updateFrame(node: self.selectionNode, frame: backgroundFrame)
|
||||||
|
transition.updateFrame(layer: self.backgroundGradientLayer, frame: backgroundFrame)
|
||||||
|
|
||||||
let buttonSize = CGSize(width: 26.0, height: 26.0)
|
let buttonSize = CGSize(width: 26.0, height: 26.0)
|
||||||
let buttonFrame = CGRect(origin: CGPoint(x: itemSize.width - buttonSize.width - 12.0, y: 12.0), size: buttonSize)
|
let buttonFrame = CGRect(origin: CGPoint(x: itemSize.width - buttonSize.width - 12.0, y: 12.0), size: buttonSize)
|
||||||
@ -532,7 +542,7 @@ private final class TimerNode: ASDisplayNode {
|
|||||||
|
|
||||||
let currentTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
|
let currentTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
|
||||||
var fraction = CGFloat(params.deadlineTimestamp - currentTimestamp) / CGFloat(params.deadlineTimestamp - params.creationTimestamp)
|
var fraction = CGFloat(params.deadlineTimestamp - currentTimestamp) / CGFloat(params.deadlineTimestamp - params.creationTimestamp)
|
||||||
fraction = 1.0 - max(0.0, min(1.0, fraction))
|
fraction = max(0.0001, 1.0 - max(0.0, min(1.0, fraction)))
|
||||||
|
|
||||||
let image: UIImage?
|
let image: UIImage?
|
||||||
|
|
||||||
|
@ -32,7 +32,9 @@ enum InviteLinkUsageLimit: Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init(value: Int32?) {
|
init(value: Int32?) {
|
||||||
if let value = value {
|
if value == 0 {
|
||||||
|
self = .unlimited
|
||||||
|
} else if let value = value {
|
||||||
if value == 1 {
|
if value == 1 {
|
||||||
self = .low
|
self = .low
|
||||||
} else if value == 10 {
|
} else if value == 10 {
|
||||||
@ -56,7 +58,7 @@ enum InviteLinkUsageLimit: Equatable {
|
|||||||
case .high:
|
case .high:
|
||||||
return 100
|
return 100
|
||||||
case .unlimited:
|
case .unlimited:
|
||||||
return nil
|
return 0
|
||||||
case let .custom(value):
|
case let .custom(value):
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ public class ItemListPermanentInviteLinkItem: ListViewItem, ItemListItem {
|
|||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let presentationData: ItemListPresentationData
|
let presentationData: ItemListPresentationData
|
||||||
let invite: ExportedInvitation?
|
let invite: ExportedInvitation?
|
||||||
|
let count: Int32
|
||||||
let peers: [Peer]
|
let peers: [Peer]
|
||||||
let displayButton: Bool
|
let displayButton: Bool
|
||||||
let displayImporters: Bool
|
let displayImporters: Bool
|
||||||
@ -45,6 +46,7 @@ public class ItemListPermanentInviteLinkItem: ListViewItem, ItemListItem {
|
|||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
presentationData: ItemListPresentationData,
|
presentationData: ItemListPresentationData,
|
||||||
invite: ExportedInvitation?,
|
invite: ExportedInvitation?,
|
||||||
|
count: Int32,
|
||||||
peers: [Peer],
|
peers: [Peer],
|
||||||
displayButton: Bool,
|
displayButton: Bool,
|
||||||
displayImporters: Bool,
|
displayImporters: Bool,
|
||||||
@ -60,6 +62,7 @@ public class ItemListPermanentInviteLinkItem: ListViewItem, ItemListItem {
|
|||||||
self.context = context
|
self.context = context
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.invite = invite
|
self.invite = invite
|
||||||
|
self.count = count
|
||||||
self.peers = peers
|
self.peers = peers
|
||||||
self.displayButton = displayButton
|
self.displayButton = displayButton
|
||||||
self.displayImporters = displayImporters
|
self.displayImporters = displayImporters
|
||||||
@ -290,22 +293,17 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
|
|||||||
|
|
||||||
let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseFontSize)
|
let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseFontSize)
|
||||||
|
|
||||||
let (addressLayout, addressApply) = makeAddressLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.invite.flatMap({ $0.link.replacingOccurrences(of: "https://", with: "") }) ?? "", font: titleFont, textColor: titleColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - 20.0 - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
let (addressLayout, addressApply) = makeAddressLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.invite.flatMap({ $0.link.replacingOccurrences(of: "https://", with: "") }) ?? "", font: titleFont, textColor: titleColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .middle, constrainedSize: CGSize(width: params.width - leftInset - rightInset - 90.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
let subtitle: String
|
let subtitle: String
|
||||||
let subtitleColor: UIColor
|
let subtitleColor: UIColor
|
||||||
if let count = item.invite?.count {
|
if item.count > 0 {
|
||||||
if count > 0 {
|
subtitle = item.presentationData.strings.InviteLink_PeopleJoined(item.count)
|
||||||
subtitle = item.presentationData.strings.InviteLink_PeopleJoined(count)
|
|
||||||
subtitleColor = item.presentationData.theme.list.itemAccentColor
|
subtitleColor = item.presentationData.theme.list.itemAccentColor
|
||||||
} else {
|
} else {
|
||||||
subtitle = item.presentationData.strings.InviteLink_PeopleJoinedNone
|
subtitle = item.presentationData.strings.InviteLink_PeopleJoinedNone
|
||||||
subtitleColor = item.presentationData.theme.list.itemSecondaryTextColor
|
subtitleColor = item.presentationData.theme.list.itemSecondaryTextColor
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
subtitle = item.presentationData.strings.InviteLink_PeopleJoinedNone
|
|
||||||
subtitleColor = item.presentationData.theme.list.itemSecondaryTextColor
|
|
||||||
}
|
|
||||||
|
|
||||||
let (invitedPeersLayout, invitedPeersApply) = makeInvitedPeersLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: subtitle, font: titleFont, textColor: subtitleColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - 20.0 - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
let (invitedPeersLayout, invitedPeersApply) = makeInvitedPeersLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: subtitle, font: titleFont, textColor: subtitleColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - 20.0 - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
|
@ -376,6 +376,9 @@ public class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNo
|
|||||||
if peer.isScam {
|
if peer.isScam {
|
||||||
credibilityIconImage = PresentationResourcesChatList.scamIcon(item.presentationData.theme, type: .regular)
|
credibilityIconImage = PresentationResourcesChatList.scamIcon(item.presentationData.theme, type: .regular)
|
||||||
credibilityIconOffset = 6.0
|
credibilityIconOffset = 6.0
|
||||||
|
} else if peer.isFake {
|
||||||
|
credibilityIconImage = PresentationResourcesChatList.fakeIcon(item.presentationData.theme, type: .regular)
|
||||||
|
credibilityIconOffset = 2.0
|
||||||
} else if peer.isVerified {
|
} else if peer.isVerified {
|
||||||
credibilityIconImage = PresentationResourcesItemList.verifiedPeerIcon(item.presentationData.theme)
|
credibilityIconImage = PresentationResourcesItemList.verifiedPeerIcon(item.presentationData.theme)
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,7 @@ public class ItemListSingleLineInputItem: ListViewItem, ItemListItem {
|
|||||||
let maxLength: Int
|
let maxLength: Int
|
||||||
let enabled: Bool
|
let enabled: Bool
|
||||||
let selectAllOnFocus: Bool
|
let selectAllOnFocus: Bool
|
||||||
|
let secondaryStyle: Bool
|
||||||
public let sectionId: ItemListSectionId
|
public let sectionId: ItemListSectionId
|
||||||
let action: () -> Void
|
let action: () -> Void
|
||||||
let textUpdated: (String) -> Void
|
let textUpdated: (String) -> Void
|
||||||
@ -56,7 +57,7 @@ public class ItemListSingleLineInputItem: ListViewItem, ItemListItem {
|
|||||||
let cleared: (() -> Void)?
|
let cleared: (() -> Void)?
|
||||||
public let tag: ItemListItemTag?
|
public let tag: ItemListItemTag?
|
||||||
|
|
||||||
public init(presentationData: ItemListPresentationData, title: NSAttributedString, text: String, placeholder: String, type: ItemListSingleLineInputItemType = .regular(capitalization: true, autocorrection: true), returnKeyType: UIReturnKeyType = .`default`, alignment: ItemListSingleLineInputAlignment = .default, spacing: CGFloat = 0.0, clearType: ItemListSingleLineInputClearType = .none, maxLength: Int = 0, enabled: Bool = true, selectAllOnFocus: Bool = false, tag: ItemListItemTag? = nil, sectionId: ItemListSectionId, textUpdated: @escaping (String) -> Void, shouldUpdateText: @escaping (String) -> Bool = { _ in return true }, processPaste: ((String) -> String)? = nil, updatedFocus: ((Bool) -> Void)? = nil, action: @escaping () -> Void, cleared: (() -> Void)? = nil) {
|
public init(presentationData: ItemListPresentationData, title: NSAttributedString, text: String, placeholder: String, type: ItemListSingleLineInputItemType = .regular(capitalization: true, autocorrection: true), returnKeyType: UIReturnKeyType = .`default`, alignment: ItemListSingleLineInputAlignment = .default, spacing: CGFloat = 0.0, clearType: ItemListSingleLineInputClearType = .none, maxLength: Int = 0, enabled: Bool = true, selectAllOnFocus: Bool = false, secondaryStyle: Bool = false, tag: ItemListItemTag? = nil, sectionId: ItemListSectionId, textUpdated: @escaping (String) -> Void, shouldUpdateText: @escaping (String) -> Bool = { _ in return true }, processPaste: ((String) -> String)? = nil, updatedFocus: ((Bool) -> Void)? = nil, action: @escaping () -> Void, cleared: (() -> Void)? = nil) {
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.title = title
|
self.title = title
|
||||||
self.text = text
|
self.text = text
|
||||||
@ -69,6 +70,7 @@ public class ItemListSingleLineInputItem: ListViewItem, ItemListItem {
|
|||||||
self.maxLength = maxLength
|
self.maxLength = maxLength
|
||||||
self.enabled = enabled
|
self.enabled = enabled
|
||||||
self.selectAllOnFocus = selectAllOnFocus
|
self.selectAllOnFocus = selectAllOnFocus
|
||||||
|
self.secondaryStyle = secondaryStyle
|
||||||
self.tag = tag
|
self.tag = tag
|
||||||
self.sectionId = sectionId
|
self.sectionId = sectionId
|
||||||
self.textUpdated = textUpdated
|
self.textUpdated = textUpdated
|
||||||
@ -183,7 +185,7 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
|
|||||||
self.textNode.textField.typingAttributes = [NSAttributedString.Key.font: Font.regular(item.presentationData.fontSize.itemListBaseFontSize)]
|
self.textNode.textField.typingAttributes = [NSAttributedString.Key.font: Font.regular(item.presentationData.fontSize.itemListBaseFontSize)]
|
||||||
self.textNode.textField.font = Font.regular(item.presentationData.fontSize.itemListBaseFontSize)
|
self.textNode.textField.font = Font.regular(item.presentationData.fontSize.itemListBaseFontSize)
|
||||||
|
|
||||||
self.textNode.textField.textColor = item.presentationData.theme.list.itemPrimaryTextColor
|
self.textNode.textField.textColor = item.secondaryStyle ? item.presentationData.theme.list.itemSecondaryTextColor : item.presentationData.theme.list.itemPrimaryTextColor
|
||||||
self.textNode.textField.keyboardAppearance = item.presentationData.theme.rootController.keyboardColor.keyboardAppearance
|
self.textNode.textField.keyboardAppearance = item.presentationData.theme.rootController.keyboardColor.keyboardAppearance
|
||||||
self.textNode.textField.tintColor = item.presentationData.theme.list.itemAccentColor
|
self.textNode.textField.tintColor = item.presentationData.theme.list.itemAccentColor
|
||||||
self.textNode.textField.accessibilityHint = item.placeholder
|
self.textNode.textField.accessibilityHint = item.placeholder
|
||||||
@ -218,6 +220,11 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
|
|||||||
fontUpdated = true
|
fontUpdated = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var styleUpdated = false
|
||||||
|
if currentItem?.secondaryStyle != item.secondaryStyle {
|
||||||
|
styleUpdated = true
|
||||||
|
}
|
||||||
|
|
||||||
let leftInset: CGFloat = 16.0 + params.leftInset
|
let leftInset: CGFloat = 16.0 + params.leftInset
|
||||||
var rightInset: CGFloat = 16.0 + params.rightInset
|
var rightInset: CGFloat = 16.0 + params.rightInset
|
||||||
|
|
||||||
@ -252,7 +259,7 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
|
|||||||
strongSelf.bottomStripeNode.backgroundColor = item.presentationData.theme.list.itemBlocksSeparatorColor
|
strongSelf.bottomStripeNode.backgroundColor = item.presentationData.theme.list.itemBlocksSeparatorColor
|
||||||
strongSelf.backgroundNode.backgroundColor = item.presentationData.theme.list.itemBlocksBackgroundColor
|
strongSelf.backgroundNode.backgroundColor = item.presentationData.theme.list.itemBlocksBackgroundColor
|
||||||
|
|
||||||
strongSelf.textNode.textField.textColor = item.presentationData.theme.list.itemPrimaryTextColor
|
strongSelf.textNode.textField.textColor = item.secondaryStyle ? item.presentationData.theme.list.itemSecondaryTextColor : item.presentationData.theme.list.itemPrimaryTextColor
|
||||||
strongSelf.textNode.textField.keyboardAppearance = item.presentationData.theme.rootController.keyboardColor.keyboardAppearance
|
strongSelf.textNode.textField.keyboardAppearance = item.presentationData.theme.rootController.keyboardColor.keyboardAppearance
|
||||||
strongSelf.textNode.textField.tintColor = item.presentationData.theme.list.itemAccentColor
|
strongSelf.textNode.textField.tintColor = item.presentationData.theme.list.itemAccentColor
|
||||||
}
|
}
|
||||||
@ -261,6 +268,10 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
|
|||||||
strongSelf.textNode.textField.typingAttributes = [NSAttributedString.Key.font: Font.regular(item.presentationData.fontSize.itemListBaseFontSize)]
|
strongSelf.textNode.textField.typingAttributes = [NSAttributedString.Key.font: Font.regular(item.presentationData.fontSize.itemListBaseFontSize)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if styleUpdated {
|
||||||
|
strongSelf.textNode.textField.textColor = item.secondaryStyle ? item.presentationData.theme.list.itemSecondaryTextColor : item.presentationData.theme.list.itemPrimaryTextColor
|
||||||
|
}
|
||||||
|
|
||||||
let _ = titleApply()
|
let _ = titleApply()
|
||||||
strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: leftInset, y: floor((layout.contentSize.height - titleLayout.size.height) / 2.0)), size: titleLayout.size)
|
strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: leftInset, y: floor((layout.contentSize.height - titleLayout.size.height) / 2.0)), size: titleLayout.size)
|
||||||
|
|
||||||
|
@ -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, 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: displayImporters, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: {
|
||||||
if let invite = invite {
|
if let invite = invite {
|
||||||
arguments.copyLink(invite)
|
arguments.copyLink(invite)
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ public enum PeerReportSubject {
|
|||||||
|
|
||||||
public enum PeerReportOption {
|
public enum PeerReportOption {
|
||||||
case spam
|
case spam
|
||||||
|
case fake
|
||||||
case violence
|
case violence
|
||||||
case copyright
|
case copyright
|
||||||
case pornography
|
case pornography
|
||||||
@ -37,6 +38,8 @@ public func presentPeerReportOptions(context: AccountContext, parent: ViewContro
|
|||||||
switch option {
|
switch option {
|
||||||
case .spam:
|
case .spam:
|
||||||
title = presentationData.strings.ReportPeer_ReasonSpam
|
title = presentationData.strings.ReportPeer_ReasonSpam
|
||||||
|
case .fake:
|
||||||
|
title = presentationData.strings.ReportPeer_ReasonFake
|
||||||
case .violence:
|
case .violence:
|
||||||
title = presentationData.strings.ReportPeer_ReasonViolence
|
title = presentationData.strings.ReportPeer_ReasonViolence
|
||||||
case .pornography:
|
case .pornography:
|
||||||
@ -57,6 +60,8 @@ public func presentPeerReportOptions(context: AccountContext, parent: ViewContro
|
|||||||
switch option {
|
switch option {
|
||||||
case .spam:
|
case .spam:
|
||||||
reportReason = .spam
|
reportReason = .spam
|
||||||
|
case .fake:
|
||||||
|
reportReason = .fake
|
||||||
case .violence:
|
case .violence:
|
||||||
reportReason = .violence
|
reportReason = .violence
|
||||||
case .pornography:
|
case .pornography:
|
||||||
@ -112,6 +117,8 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe
|
|||||||
switch option {
|
switch option {
|
||||||
case .spam:
|
case .spam:
|
||||||
title = presentationData.strings.ReportPeer_ReasonSpam
|
title = presentationData.strings.ReportPeer_ReasonSpam
|
||||||
|
case .fake:
|
||||||
|
title = presentationData.strings.ReportPeer_ReasonFake
|
||||||
case .violence:
|
case .violence:
|
||||||
title = presentationData.strings.ReportPeer_ReasonViolence
|
title = presentationData.strings.ReportPeer_ReasonViolence
|
||||||
case .pornography:
|
case .pornography:
|
||||||
@ -128,6 +135,8 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe
|
|||||||
switch option {
|
switch option {
|
||||||
case .spam:
|
case .spam:
|
||||||
reportReason = .spam
|
reportReason = .spam
|
||||||
|
case .fake:
|
||||||
|
reportReason = .fake
|
||||||
case .violence:
|
case .violence:
|
||||||
reportReason = .violence
|
reportReason = .violence
|
||||||
case .pornography:
|
case .pornography:
|
||||||
|
@ -652,7 +652,15 @@ private func userInfoEntries(account: Account, presentationData: PresentationDat
|
|||||||
} else {
|
} else {
|
||||||
aboutTitle = presentationData.strings.Profile_About
|
aboutTitle = presentationData.strings.Profile_About
|
||||||
}
|
}
|
||||||
if user.isScam {
|
if user.isFake {
|
||||||
|
let aboutValue: String
|
||||||
|
if let _ = user.botInfo {
|
||||||
|
aboutValue = presentationData.strings.UserInfo_FakeBotWarning
|
||||||
|
} else {
|
||||||
|
aboutValue = presentationData.strings.UserInfo_FakeUserWarning
|
||||||
|
}
|
||||||
|
entries.append(UserInfoEntry.about(presentationData.theme, peer, aboutTitle, aboutValue))
|
||||||
|
} else if user.isScam {
|
||||||
let aboutValue: String
|
let aboutValue: String
|
||||||
if let _ = user.botInfo {
|
if let _ = user.botInfo {
|
||||||
aboutValue = presentationData.strings.UserInfo_ScamBotWarning
|
aboutValue = presentationData.strings.UserInfo_ScamBotWarning
|
||||||
|
@ -143,6 +143,7 @@ public struct TelegramChannelFlags: OptionSet {
|
|||||||
public static let hasGeo = TelegramChannelFlags(rawValue: 1 << 3)
|
public static let hasGeo = TelegramChannelFlags(rawValue: 1 << 3)
|
||||||
public static let hasVoiceChat = TelegramChannelFlags(rawValue: 1 << 4)
|
public static let hasVoiceChat = TelegramChannelFlags(rawValue: 1 << 4)
|
||||||
public static let hasActiveVoiceChat = TelegramChannelFlags(rawValue: 1 << 5)
|
public static let hasActiveVoiceChat = TelegramChannelFlags(rawValue: 1 << 5)
|
||||||
|
public static let isFake = TelegramChannelFlags(rawValue: 1 << 6)
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class TelegramChannel: Peer {
|
public final class TelegramChannel: Peer {
|
||||||
|
@ -14,6 +14,7 @@ public struct UserInfoFlags: OptionSet {
|
|||||||
public static let isVerified = UserInfoFlags(rawValue: (1 << 0))
|
public static let isVerified = UserInfoFlags(rawValue: (1 << 0))
|
||||||
public static let isSupport = UserInfoFlags(rawValue: (1 << 1))
|
public static let isSupport = UserInfoFlags(rawValue: (1 << 1))
|
||||||
public static let isScam = UserInfoFlags(rawValue: (1 << 2))
|
public static let isScam = UserInfoFlags(rawValue: (1 << 2))
|
||||||
|
public static let isFake = UserInfoFlags(rawValue: (1 << 3))
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct BotUserInfoFlags: OptionSet {
|
public struct BotUserInfoFlags: OptionSet {
|
||||||
|
@ -11,8 +11,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) }
|
dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) }
|
||||||
dict[1210199983] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) }
|
dict[1210199983] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) }
|
||||||
dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) }
|
dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) }
|
||||||
dict[2055070967] = { return Api.ChatFull.parse_channelFull($0) }
|
|
||||||
dict[-213431562] = { return Api.ChatFull.parse_chatFull($0) }
|
dict[-213431562] = { return Api.ChatFull.parse_chatFull($0) }
|
||||||
|
dict[2055070967] = { return Api.ChatFull.parse_channelFull($0) }
|
||||||
dict[-1159937629] = { return Api.PollResults.parse_pollResults($0) }
|
dict[-1159937629] = { return Api.PollResults.parse_pollResults($0) }
|
||||||
dict[-925415106] = { return Api.ChatParticipant.parse_chatParticipant($0) }
|
dict[-925415106] = { return Api.ChatParticipant.parse_chatParticipant($0) }
|
||||||
dict[-636267638] = { return Api.ChatParticipant.parse_chatParticipantCreator($0) }
|
dict[-636267638] = { return Api.ChatParticipant.parse_chatParticipantCreator($0) }
|
||||||
@ -474,6 +474,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-1685456582] = { return Api.ReportReason.parse_inputReportReasonCopyright($0) }
|
dict[-1685456582] = { return Api.ReportReason.parse_inputReportReasonCopyright($0) }
|
||||||
dict[-1376497949] = { return Api.ReportReason.parse_inputReportReasonChildAbuse($0) }
|
dict[-1376497949] = { return Api.ReportReason.parse_inputReportReasonChildAbuse($0) }
|
||||||
dict[-606798099] = { return Api.ReportReason.parse_inputReportReasonGeoIrrelevant($0) }
|
dict[-606798099] = { return Api.ReportReason.parse_inputReportReasonGeoIrrelevant($0) }
|
||||||
|
dict[-170010905] = { return Api.ReportReason.parse_inputReportReasonFake($0) }
|
||||||
dict[-247351839] = { return Api.InputEncryptedChat.parse_inputEncryptedChat($0) }
|
dict[-247351839] = { return Api.InputEncryptedChat.parse_inputEncryptedChat($0) }
|
||||||
dict[-524237339] = { return Api.PageTableRow.parse_pageTableRow($0) }
|
dict[-524237339] = { return Api.PageTableRow.parse_pageTableRow($0) }
|
||||||
dict[-40996577] = { return Api.DraftMessage.parse_draftMessage($0) }
|
dict[-40996577] = { return Api.DraftMessage.parse_draftMessage($0) }
|
||||||
@ -659,7 +660,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-1056001329] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentialsSaved($0) }
|
dict[-1056001329] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentialsSaved($0) }
|
||||||
dict[873977640] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentials($0) }
|
dict[873977640] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentials($0) }
|
||||||
dict[178373535] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentialsApplePay($0) }
|
dict[178373535] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentialsApplePay($0) }
|
||||||
dict[-1966921727] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentialsGooglePay($0) }
|
dict[-905587442] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentialsAndroidPay($0) }
|
||||||
dict[-1239335713] = { return Api.ShippingOption.parse_shippingOption($0) }
|
dict[-1239335713] = { return Api.ShippingOption.parse_shippingOption($0) }
|
||||||
dict[859091184] = { return Api.InputSecureFile.parse_inputSecureFileUploaded($0) }
|
dict[859091184] = { return Api.InputSecureFile.parse_inputSecureFileUploaded($0) }
|
||||||
dict[1399317950] = { return Api.InputSecureFile.parse_inputSecureFile($0) }
|
dict[1399317950] = { return Api.InputSecureFile.parse_inputSecureFile($0) }
|
||||||
|
@ -2278,11 +2278,31 @@ public extension Api {
|
|||||||
|
|
||||||
}
|
}
|
||||||
public enum ChatFull: TypeConstructorDescription {
|
public enum ChatFull: TypeConstructorDescription {
|
||||||
case channelFull(flags: Int32, id: Int32, about: String, participantsCount: Int32?, adminsCount: Int32?, kickedCount: Int32?, bannedCount: Int32?, onlineCount: Int32?, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, chatPhoto: Api.Photo, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite?, botInfo: [Api.BotInfo], migratedFromChatId: Int32?, migratedFromMaxId: Int32?, pinnedMsgId: Int32?, stickerset: Api.StickerSet?, availableMinId: Int32?, folderId: Int32?, linkedChatId: Int32?, location: Api.ChannelLocation?, slowmodeSeconds: Int32?, slowmodeNextSendDate: Int32?, statsDc: Int32?, pts: Int32, call: Api.InputGroupCall?)
|
|
||||||
case chatFull(flags: Int32, id: Int32, about: String, participants: Api.ChatParticipants, chatPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite?, botInfo: [Api.BotInfo]?, pinnedMsgId: Int32?, folderId: Int32?, call: Api.InputGroupCall?)
|
case chatFull(flags: Int32, id: Int32, about: String, participants: Api.ChatParticipants, chatPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite?, botInfo: [Api.BotInfo]?, pinnedMsgId: Int32?, folderId: Int32?, call: Api.InputGroupCall?)
|
||||||
|
case channelFull(flags: Int32, id: Int32, about: String, participantsCount: Int32?, adminsCount: Int32?, kickedCount: Int32?, bannedCount: Int32?, onlineCount: Int32?, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, chatPhoto: Api.Photo, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite?, botInfo: [Api.BotInfo], migratedFromChatId: Int32?, migratedFromMaxId: Int32?, pinnedMsgId: Int32?, stickerset: Api.StickerSet?, availableMinId: Int32?, folderId: Int32?, linkedChatId: Int32?, location: Api.ChannelLocation?, slowmodeSeconds: Int32?, slowmodeNextSendDate: Int32?, statsDc: Int32?, pts: Int32, call: Api.InputGroupCall?)
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
|
case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId, let call):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-213431562)
|
||||||
|
}
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(id, buffer: buffer, boxed: false)
|
||||||
|
serializeString(about, buffer: buffer, boxed: false)
|
||||||
|
participants.serialize(buffer, true)
|
||||||
|
if Int(flags) & Int(1 << 2) != 0 {chatPhoto!.serialize(buffer, true)}
|
||||||
|
notifySettings.serialize(buffer, true)
|
||||||
|
if Int(flags) & Int(1 << 13) != 0 {exportedInvite!.serialize(buffer, true)}
|
||||||
|
if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(botInfo!.count))
|
||||||
|
for item in botInfo! {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}}
|
||||||
|
if Int(flags) & Int(1 << 6) != 0 {serializeInt32(pinnedMsgId!, buffer: buffer, boxed: false)}
|
||||||
|
if Int(flags) & Int(1 << 11) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)}
|
||||||
|
if Int(flags) & Int(1 << 12) != 0 {call!.serialize(buffer, true)}
|
||||||
|
break
|
||||||
case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let statsDc, let pts, let call):
|
case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let statsDc, let pts, let call):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(2055070967)
|
buffer.appendInt32(2055070967)
|
||||||
@ -2320,38 +2340,71 @@ public extension Api {
|
|||||||
serializeInt32(pts, buffer: buffer, boxed: false)
|
serializeInt32(pts, buffer: buffer, boxed: false)
|
||||||
if Int(flags) & Int(1 << 21) != 0 {call!.serialize(buffer, true)}
|
if Int(flags) & Int(1 << 21) != 0 {call!.serialize(buffer, true)}
|
||||||
break
|
break
|
||||||
case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId, let call):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-213431562)
|
|
||||||
}
|
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
|
||||||
serializeInt32(id, buffer: buffer, boxed: false)
|
|
||||||
serializeString(about, buffer: buffer, boxed: false)
|
|
||||||
participants.serialize(buffer, true)
|
|
||||||
if Int(flags) & Int(1 << 2) != 0 {chatPhoto!.serialize(buffer, true)}
|
|
||||||
notifySettings.serialize(buffer, true)
|
|
||||||
if Int(flags) & Int(1 << 13) != 0 {exportedInvite!.serialize(buffer, true)}
|
|
||||||
if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(botInfo!.count))
|
|
||||||
for item in botInfo! {
|
|
||||||
item.serialize(buffer, true)
|
|
||||||
}}
|
|
||||||
if Int(flags) & Int(1 << 6) != 0 {serializeInt32(pinnedMsgId!, buffer: buffer, boxed: false)}
|
|
||||||
if Int(flags) & Int(1 << 11) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)}
|
|
||||||
if Int(flags) & Int(1 << 12) != 0 {call!.serialize(buffer, true)}
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
switch self {
|
switch self {
|
||||||
case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let statsDc, let pts, let call):
|
|
||||||
return ("channelFull", [("flags", flags), ("id", id), ("about", about), ("participantsCount", participantsCount), ("adminsCount", adminsCount), ("kickedCount", kickedCount), ("bannedCount", bannedCount), ("onlineCount", onlineCount), ("readInboxMaxId", readInboxMaxId), ("readOutboxMaxId", readOutboxMaxId), ("unreadCount", unreadCount), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("migratedFromChatId", migratedFromChatId), ("migratedFromMaxId", migratedFromMaxId), ("pinnedMsgId", pinnedMsgId), ("stickerset", stickerset), ("availableMinId", availableMinId), ("folderId", folderId), ("linkedChatId", linkedChatId), ("location", location), ("slowmodeSeconds", slowmodeSeconds), ("slowmodeNextSendDate", slowmodeNextSendDate), ("statsDc", statsDc), ("pts", pts), ("call", call)])
|
|
||||||
case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId, let call):
|
case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId, let call):
|
||||||
return ("chatFull", [("flags", flags), ("id", id), ("about", about), ("participants", participants), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("pinnedMsgId", pinnedMsgId), ("folderId", folderId), ("call", call)])
|
return ("chatFull", [("flags", flags), ("id", id), ("about", about), ("participants", participants), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("pinnedMsgId", pinnedMsgId), ("folderId", folderId), ("call", call)])
|
||||||
|
case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let statsDc, let pts, let call):
|
||||||
|
return ("channelFull", [("flags", flags), ("id", id), ("about", about), ("participantsCount", participantsCount), ("adminsCount", adminsCount), ("kickedCount", kickedCount), ("bannedCount", bannedCount), ("onlineCount", onlineCount), ("readInboxMaxId", readInboxMaxId), ("readOutboxMaxId", readOutboxMaxId), ("unreadCount", unreadCount), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("migratedFromChatId", migratedFromChatId), ("migratedFromMaxId", migratedFromMaxId), ("pinnedMsgId", pinnedMsgId), ("stickerset", stickerset), ("availableMinId", availableMinId), ("folderId", folderId), ("linkedChatId", linkedChatId), ("location", location), ("slowmodeSeconds", slowmodeSeconds), ("slowmodeNextSendDate", slowmodeNextSendDate), ("statsDc", statsDc), ("pts", pts), ("call", call)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func parse_chatFull(_ reader: BufferReader) -> ChatFull? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: Int32?
|
||||||
|
_2 = reader.readInt32()
|
||||||
|
var _3: String?
|
||||||
|
_3 = parseString(reader)
|
||||||
|
var _4: Api.ChatParticipants?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
_4 = Api.parse(reader, signature: signature) as? Api.ChatParticipants
|
||||||
|
}
|
||||||
|
var _5: Api.Photo?
|
||||||
|
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
|
||||||
|
_5 = Api.parse(reader, signature: signature) as? Api.Photo
|
||||||
|
} }
|
||||||
|
var _6: Api.PeerNotifySettings?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
_6 = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings
|
||||||
|
}
|
||||||
|
var _7: Api.ExportedChatInvite?
|
||||||
|
if Int(_1!) & Int(1 << 13) != 0 {if let signature = reader.readInt32() {
|
||||||
|
_7 = Api.parse(reader, signature: signature) as? Api.ExportedChatInvite
|
||||||
|
} }
|
||||||
|
var _8: [Api.BotInfo]?
|
||||||
|
if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() {
|
||||||
|
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BotInfo.self)
|
||||||
|
} }
|
||||||
|
var _9: Int32?
|
||||||
|
if Int(_1!) & Int(1 << 6) != 0 {_9 = reader.readInt32() }
|
||||||
|
var _10: Int32?
|
||||||
|
if Int(_1!) & Int(1 << 11) != 0 {_10 = reader.readInt32() }
|
||||||
|
var _11: Api.InputGroupCall?
|
||||||
|
if Int(_1!) & Int(1 << 12) != 0 {if let signature = reader.readInt32() {
|
||||||
|
_11 = Api.parse(reader, signature: signature) as? Api.InputGroupCall
|
||||||
|
} }
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
let _c4 = _4 != nil
|
||||||
|
let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil
|
||||||
|
let _c6 = _6 != nil
|
||||||
|
let _c7 = (Int(_1!) & Int(1 << 13) == 0) || _7 != nil
|
||||||
|
let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil
|
||||||
|
let _c9 = (Int(_1!) & Int(1 << 6) == 0) || _9 != nil
|
||||||
|
let _c10 = (Int(_1!) & Int(1 << 11) == 0) || _10 != nil
|
||||||
|
let _c11 = (Int(_1!) & Int(1 << 12) == 0) || _11 != nil
|
||||||
|
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 {
|
||||||
|
return Api.ChatFull.chatFull(flags: _1!, id: _2!, about: _3!, participants: _4!, chatPhoto: _5, notifySettings: _6!, exportedInvite: _7, botInfo: _8, pinnedMsgId: _9, folderId: _10, call: _11)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
public static func parse_channelFull(_ reader: BufferReader) -> ChatFull? {
|
public static func parse_channelFull(_ reader: BufferReader) -> ChatFull? {
|
||||||
var _1: Int32?
|
var _1: Int32?
|
||||||
_1 = reader.readInt32()
|
_1 = reader.readInt32()
|
||||||
@ -2458,59 +2511,6 @@ public extension Api {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static func parse_chatFull(_ reader: BufferReader) -> ChatFull? {
|
|
||||||
var _1: Int32?
|
|
||||||
_1 = reader.readInt32()
|
|
||||||
var _2: Int32?
|
|
||||||
_2 = reader.readInt32()
|
|
||||||
var _3: String?
|
|
||||||
_3 = parseString(reader)
|
|
||||||
var _4: Api.ChatParticipants?
|
|
||||||
if let signature = reader.readInt32() {
|
|
||||||
_4 = Api.parse(reader, signature: signature) as? Api.ChatParticipants
|
|
||||||
}
|
|
||||||
var _5: Api.Photo?
|
|
||||||
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
|
|
||||||
_5 = Api.parse(reader, signature: signature) as? Api.Photo
|
|
||||||
} }
|
|
||||||
var _6: Api.PeerNotifySettings?
|
|
||||||
if let signature = reader.readInt32() {
|
|
||||||
_6 = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings
|
|
||||||
}
|
|
||||||
var _7: Api.ExportedChatInvite?
|
|
||||||
if Int(_1!) & Int(1 << 13) != 0 {if let signature = reader.readInt32() {
|
|
||||||
_7 = Api.parse(reader, signature: signature) as? Api.ExportedChatInvite
|
|
||||||
} }
|
|
||||||
var _8: [Api.BotInfo]?
|
|
||||||
if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() {
|
|
||||||
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BotInfo.self)
|
|
||||||
} }
|
|
||||||
var _9: Int32?
|
|
||||||
if Int(_1!) & Int(1 << 6) != 0 {_9 = reader.readInt32() }
|
|
||||||
var _10: Int32?
|
|
||||||
if Int(_1!) & Int(1 << 11) != 0 {_10 = reader.readInt32() }
|
|
||||||
var _11: Api.InputGroupCall?
|
|
||||||
if Int(_1!) & Int(1 << 12) != 0 {if let signature = reader.readInt32() {
|
|
||||||
_11 = Api.parse(reader, signature: signature) as? Api.InputGroupCall
|
|
||||||
} }
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
let _c3 = _3 != nil
|
|
||||||
let _c4 = _4 != nil
|
|
||||||
let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil
|
|
||||||
let _c6 = _6 != nil
|
|
||||||
let _c7 = (Int(_1!) & Int(1 << 13) == 0) || _7 != nil
|
|
||||||
let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil
|
|
||||||
let _c9 = (Int(_1!) & Int(1 << 6) == 0) || _9 != nil
|
|
||||||
let _c10 = (Int(_1!) & Int(1 << 11) == 0) || _10 != nil
|
|
||||||
let _c11 = (Int(_1!) & Int(1 << 12) == 0) || _11 != nil
|
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 {
|
|
||||||
return Api.ChatFull.chatFull(flags: _1!, id: _2!, about: _3!, participants: _4!, chatPhoto: _5, notifySettings: _6!, exportedInvite: _7, botInfo: _8, pinnedMsgId: _9, folderId: _10, call: _11)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
public enum PollResults: TypeConstructorDescription {
|
public enum PollResults: TypeConstructorDescription {
|
||||||
@ -13931,6 +13931,7 @@ public extension Api {
|
|||||||
case inputReportReasonCopyright
|
case inputReportReasonCopyright
|
||||||
case inputReportReasonChildAbuse
|
case inputReportReasonChildAbuse
|
||||||
case inputReportReasonGeoIrrelevant
|
case inputReportReasonGeoIrrelevant
|
||||||
|
case inputReportReasonFake
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
@ -13975,6 +13976,12 @@ public extension Api {
|
|||||||
buffer.appendInt32(-606798099)
|
buffer.appendInt32(-606798099)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
case .inputReportReasonFake:
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-170010905)
|
||||||
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -13995,6 +14002,8 @@ public extension Api {
|
|||||||
return ("inputReportReasonChildAbuse", [])
|
return ("inputReportReasonChildAbuse", [])
|
||||||
case .inputReportReasonGeoIrrelevant:
|
case .inputReportReasonGeoIrrelevant:
|
||||||
return ("inputReportReasonGeoIrrelevant", [])
|
return ("inputReportReasonGeoIrrelevant", [])
|
||||||
|
case .inputReportReasonFake:
|
||||||
|
return ("inputReportReasonFake", [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14027,6 +14036,9 @@ public extension Api {
|
|||||||
public static func parse_inputReportReasonGeoIrrelevant(_ reader: BufferReader) -> ReportReason? {
|
public static func parse_inputReportReasonGeoIrrelevant(_ reader: BufferReader) -> ReportReason? {
|
||||||
return Api.ReportReason.inputReportReasonGeoIrrelevant
|
return Api.ReportReason.inputReportReasonGeoIrrelevant
|
||||||
}
|
}
|
||||||
|
public static func parse_inputReportReasonFake(_ reader: BufferReader) -> ReportReason? {
|
||||||
|
return Api.ReportReason.inputReportReasonFake
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
public enum InputEncryptedChat: TypeConstructorDescription {
|
public enum InputEncryptedChat: TypeConstructorDescription {
|
||||||
@ -19205,7 +19217,7 @@ public extension Api {
|
|||||||
case inputPaymentCredentialsSaved(id: String, tmpPassword: Buffer)
|
case inputPaymentCredentialsSaved(id: String, tmpPassword: Buffer)
|
||||||
case inputPaymentCredentials(flags: Int32, data: Api.DataJSON)
|
case inputPaymentCredentials(flags: Int32, data: Api.DataJSON)
|
||||||
case inputPaymentCredentialsApplePay(paymentData: Api.DataJSON)
|
case inputPaymentCredentialsApplePay(paymentData: Api.DataJSON)
|
||||||
case inputPaymentCredentialsGooglePay(paymentToken: Api.DataJSON)
|
case inputPaymentCredentialsAndroidPay(paymentToken: Api.DataJSON, googleTransactionId: String)
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
@ -19229,11 +19241,12 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
paymentData.serialize(buffer, true)
|
paymentData.serialize(buffer, true)
|
||||||
break
|
break
|
||||||
case .inputPaymentCredentialsGooglePay(let paymentToken):
|
case .inputPaymentCredentialsAndroidPay(let paymentToken, let googleTransactionId):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(-1966921727)
|
buffer.appendInt32(-905587442)
|
||||||
}
|
}
|
||||||
paymentToken.serialize(buffer, true)
|
paymentToken.serialize(buffer, true)
|
||||||
|
serializeString(googleTransactionId, buffer: buffer, boxed: false)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -19246,8 +19259,8 @@ public extension Api {
|
|||||||
return ("inputPaymentCredentials", [("flags", flags), ("data", data)])
|
return ("inputPaymentCredentials", [("flags", flags), ("data", data)])
|
||||||
case .inputPaymentCredentialsApplePay(let paymentData):
|
case .inputPaymentCredentialsApplePay(let paymentData):
|
||||||
return ("inputPaymentCredentialsApplePay", [("paymentData", paymentData)])
|
return ("inputPaymentCredentialsApplePay", [("paymentData", paymentData)])
|
||||||
case .inputPaymentCredentialsGooglePay(let paymentToken):
|
case .inputPaymentCredentialsAndroidPay(let paymentToken, let googleTransactionId):
|
||||||
return ("inputPaymentCredentialsGooglePay", [("paymentToken", paymentToken)])
|
return ("inputPaymentCredentialsAndroidPay", [("paymentToken", paymentToken), ("googleTransactionId", googleTransactionId)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19294,14 +19307,17 @@ public extension Api {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static func parse_inputPaymentCredentialsGooglePay(_ reader: BufferReader) -> InputPaymentCredentials? {
|
public static func parse_inputPaymentCredentialsAndroidPay(_ reader: BufferReader) -> InputPaymentCredentials? {
|
||||||
var _1: Api.DataJSON?
|
var _1: Api.DataJSON?
|
||||||
if let signature = reader.readInt32() {
|
if let signature = reader.readInt32() {
|
||||||
_1 = Api.parse(reader, signature: signature) as? Api.DataJSON
|
_1 = Api.parse(reader, signature: signature) as? Api.DataJSON
|
||||||
}
|
}
|
||||||
|
var _2: String?
|
||||||
|
_2 = parseString(reader)
|
||||||
let _c1 = _1 != nil
|
let _c1 = _1 != nil
|
||||||
if _c1 {
|
let _c2 = _2 != nil
|
||||||
return Api.InputPaymentCredentials.inputPaymentCredentialsGooglePay(paymentToken: _1!)
|
if _c1 && _c2 {
|
||||||
|
return Api.InputPaymentCredentials.inputPaymentCredentialsAndroidPay(paymentToken: _1!, googleTransactionId: _2!)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -2012,21 +2012,6 @@ public extension Api {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func deleteChatUser(chatId: Int32, userId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
|
||||||
let buffer = Buffer()
|
|
||||||
buffer.appendInt32(-530505962)
|
|
||||||
serializeInt32(chatId, buffer: buffer, boxed: false)
|
|
||||||
userId.serialize(buffer, true)
|
|
||||||
return (FunctionDescription(name: "messages.deleteChatUser", parameters: [("chatId", chatId), ("userId", userId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
|
||||||
let reader = BufferReader(buffer)
|
|
||||||
var result: Api.Updates?
|
|
||||||
if let signature = reader.readInt32() {
|
|
||||||
result = Api.parse(reader, signature: signature) as? Api.Updates
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func createChat(users: [Api.InputUser], title: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
public static func createChat(users: [Api.InputUser], title: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(164303470)
|
buffer.appendInt32(164303470)
|
||||||
@ -3889,25 +3874,6 @@ public extension Api {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func getExportedChatInvites(flags: Int32, peer: Api.InputPeer, adminId: Api.InputUser?, offsetDate: Int32?, offsetLink: String?, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.ExportedChatInvites>) {
|
|
||||||
let buffer = Buffer()
|
|
||||||
buffer.appendInt32(1785900140)
|
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
|
||||||
peer.serialize(buffer, true)
|
|
||||||
if Int(flags) & Int(1 << 0) != 0 {adminId!.serialize(buffer, true)}
|
|
||||||
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(offsetDate!, buffer: buffer, boxed: false)}
|
|
||||||
if Int(flags) & Int(1 << 2) != 0 {serializeString(offsetLink!, buffer: buffer, boxed: false)}
|
|
||||||
serializeInt32(limit, buffer: buffer, boxed: false)
|
|
||||||
return (FunctionDescription(name: "messages.getExportedChatInvites", parameters: [("flags", flags), ("peer", peer), ("adminId", adminId), ("offsetDate", offsetDate), ("offsetLink", offsetLink), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.ExportedChatInvites? in
|
|
||||||
let reader = BufferReader(buffer)
|
|
||||||
var result: Api.messages.ExportedChatInvites?
|
|
||||||
if let signature = reader.readInt32() {
|
|
||||||
result = Api.parse(reader, signature: signature) as? Api.messages.ExportedChatInvites
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func exportChatInvite(flags: Int32, peer: Api.InputPeer, expireDate: Int32?, usageLimit: Int32?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.ExportedChatInvite>) {
|
public static func exportChatInvite(flags: Int32, peer: Api.InputPeer, expireDate: Int32?, usageLimit: Int32?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.ExportedChatInvite>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(347716823)
|
buffer.appendInt32(347716823)
|
||||||
@ -3943,6 +3909,43 @@ public extension Api {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func getChatInviteImporters(peer: Api.InputPeer, link: String, offsetDate: Int32, offsetUser: Api.InputUser, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.ChatInviteImporters>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(654013065)
|
||||||
|
peer.serialize(buffer, true)
|
||||||
|
serializeString(link, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(offsetDate, buffer: buffer, boxed: false)
|
||||||
|
offsetUser.serialize(buffer, true)
|
||||||
|
serializeInt32(limit, buffer: buffer, boxed: false)
|
||||||
|
return (FunctionDescription(name: "messages.getChatInviteImporters", parameters: [("peer", peer), ("link", link), ("offsetDate", offsetDate), ("offsetUser", offsetUser), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.ChatInviteImporters? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.messages.ChatInviteImporters?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.messages.ChatInviteImporters
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func getExportedChatInvites(flags: Int32, peer: Api.InputPeer, adminId: Api.InputUser?, offsetDate: Int32?, offsetLink: String?, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.ExportedChatInvites>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(1785900140)
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
peer.serialize(buffer, true)
|
||||||
|
if Int(flags) & Int(1 << 0) != 0 {adminId!.serialize(buffer, true)}
|
||||||
|
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(offsetDate!, buffer: buffer, boxed: false)}
|
||||||
|
if Int(flags) & Int(1 << 2) != 0 {serializeString(offsetLink!, buffer: buffer, boxed: false)}
|
||||||
|
serializeInt32(limit, buffer: buffer, boxed: false)
|
||||||
|
return (FunctionDescription(name: "messages.getExportedChatInvites", parameters: [("flags", flags), ("peer", peer), ("adminId", adminId), ("offsetDate", offsetDate), ("offsetLink", offsetLink), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.ExportedChatInvites? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.messages.ExportedChatInvites?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.messages.ExportedChatInvites
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
public static func deleteRevokedExportedChatInvites(peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
public static func deleteRevokedExportedChatInvites(peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(1375999075)
|
buffer.appendInt32(1375999075)
|
||||||
@ -3972,24 +3975,6 @@ public extension Api {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func getChatInviteImporters(peer: Api.InputPeer, link: String, offsetDate: Int32, offsetUser: Api.InputUser, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.ChatInviteImporters>) {
|
|
||||||
let buffer = Buffer()
|
|
||||||
buffer.appendInt32(654013065)
|
|
||||||
peer.serialize(buffer, true)
|
|
||||||
serializeString(link, buffer: buffer, boxed: false)
|
|
||||||
serializeInt32(offsetDate, buffer: buffer, boxed: false)
|
|
||||||
offsetUser.serialize(buffer, true)
|
|
||||||
serializeInt32(limit, buffer: buffer, boxed: false)
|
|
||||||
return (FunctionDescription(name: "messages.getChatInviteImporters", parameters: [("peer", peer), ("link", link), ("offsetDate", offsetDate), ("offsetUser", offsetUser), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.ChatInviteImporters? in
|
|
||||||
let reader = BufferReader(buffer)
|
|
||||||
var result: Api.messages.ChatInviteImporters?
|
|
||||||
if let signature = reader.readInt32() {
|
|
||||||
result = Api.parse(reader, signature: signature) as? Api.messages.ChatInviteImporters
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func discardEncryption(flags: Int32, chatId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
public static func discardEncryption(flags: Int32, chatId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(-208425312)
|
buffer.appendInt32(-208425312)
|
||||||
@ -4019,6 +4004,22 @@ public extension Api {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func deleteChatUser(flags: Int32, chatId: Int32, userId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(-986430054)
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(chatId, buffer: buffer, boxed: false)
|
||||||
|
userId.serialize(buffer, true)
|
||||||
|
return (FunctionDescription(name: "messages.deleteChatUser", parameters: [("flags", flags), ("chatId", chatId), ("userId", userId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.Updates?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.Updates
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
public static func deletePhoneCallHistory(flags: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.AffectedHistory>) {
|
public static func deletePhoneCallHistory(flags: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.AffectedHistory>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(1828657989)
|
buffer.appendInt32(1828657989)
|
||||||
@ -4033,6 +4034,20 @@ public extension Api {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func checkHistoryImport(importHead: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.HistoryImportParsed>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(1140726259)
|
||||||
|
serializeString(importHead, buffer: buffer, boxed: false)
|
||||||
|
return (FunctionDescription(name: "messages.checkHistoryImport", parameters: [("importHead", importHead)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.HistoryImportParsed? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.messages.HistoryImportParsed?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.messages.HistoryImportParsed
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
public static func initHistoryImport(peer: Api.InputPeer, file: Api.InputFile, mediaCount: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.HistoryImport>) {
|
public static func initHistoryImport(peer: Api.InputPeer, file: Api.InputFile, mediaCount: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.HistoryImport>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(873008187)
|
buffer.appendInt32(873008187)
|
||||||
|
@ -103,6 +103,9 @@ func parseTelegramGroupOrChannel(chat: Api.Chat) -> Peer? {
|
|||||||
if (flags & Int32(1 << 24)) != 0 {
|
if (flags & Int32(1 << 24)) != 0 {
|
||||||
channelFlags.insert(.hasActiveVoiceChat)
|
channelFlags.insert(.hasActiveVoiceChat)
|
||||||
}
|
}
|
||||||
|
if (flags & Int32(1 << 25)) != 0 {
|
||||||
|
channelFlags.insert(.isFake)
|
||||||
|
}
|
||||||
|
|
||||||
let restrictionInfo: PeerAccessRestrictionInfo?
|
let restrictionInfo: PeerAccessRestrictionInfo?
|
||||||
if let restrictionReason = restrictionReason {
|
if let restrictionReason = restrictionReason {
|
||||||
|
@ -26,7 +26,7 @@ public func leftGroup(account: Account, peerId: PeerId) -> Signal<Void, NoError>
|
|||||||
|> take(1)
|
|> take(1)
|
||||||
|> mapToSignal { peer -> Signal<Void, NoError> in
|
|> mapToSignal { peer -> Signal<Void, NoError> in
|
||||||
if let inputUser = apiInputUser(peer) {
|
if let inputUser = apiInputUser(peer) {
|
||||||
return account.network.request(Api.functions.messages .deleteChatUser(chatId: peerId.id, userId: inputUser))
|
return account.network.request(Api.functions.messages.deleteChatUser(flags: 0, chatId: peerId.id, userId: inputUser))
|
||||||
|> retryRequest
|
|> retryRequest
|
||||||
|> mapToSignal { updates -> Signal<Void, NoError> in
|
|> mapToSignal { updates -> Signal<Void, NoError> in
|
||||||
account.stateManager.addUpdates(updates)
|
account.stateManager.addUpdates(updates)
|
||||||
|
@ -275,7 +275,7 @@ private func removeChat(transaction: Transaction, postbox: Postbox, network: Net
|
|||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
deleteUser = network.request(Api.functions.messages.deleteChatUser(chatId: peer.id.id, userId: Api.InputUser.inputUserSelf))
|
deleteUser = network.request(Api.functions.messages.deleteChatUser(flags: 0, chatId: peer.id.id, userId: Api.InputUser.inputUserSelf))
|
||||||
|> map { result -> Api.Updates? in
|
|> map { result -> Api.Updates? in
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,21 @@ public extension Message {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isFake: Bool {
|
||||||
|
if let author = self.author, author.isFake {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if let forwardAuthor = self.forwardInfo?.author, forwardAuthor.isFake {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for attribute in self.attributes {
|
||||||
|
if let attribute = attribute as? InlineBotMessageAttribute, let peerId = attribute.peerId, let bot = self.peers[peerId] as? TelegramUser, bot.isFake {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
var sourceReference: SourceReferenceMessageAttribute? {
|
var sourceReference: SourceReferenceMessageAttribute? {
|
||||||
for attribute in self.attributes {
|
for attribute in self.attributes {
|
||||||
if let attribute = attribute as? SourceReferenceMessageAttribute {
|
if let attribute = attribute as? SourceReferenceMessageAttribute {
|
||||||
|
@ -122,6 +122,17 @@ public extension Peer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isFake: Bool {
|
||||||
|
switch self {
|
||||||
|
case let user as TelegramUser:
|
||||||
|
return user.flags.contains(.isFake)
|
||||||
|
case let channel as TelegramChannel:
|
||||||
|
return channel.flags.contains(.isFake)
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var isVerified: Bool {
|
var isVerified: Bool {
|
||||||
switch self {
|
switch self {
|
||||||
case let user as TelegramUser:
|
case let user as TelegramUser:
|
||||||
|
@ -17,7 +17,7 @@ public func removePeerMember(account: Account, peerId: PeerId, memberId: PeerId)
|
|||||||
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
|
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||||
if let peer = transaction.getPeer(peerId), let memberPeer = transaction.getPeer(memberId), let inputUser = apiInputUser(memberPeer) {
|
if let peer = transaction.getPeer(peerId), let memberPeer = transaction.getPeer(memberId), let inputUser = apiInputUser(memberPeer) {
|
||||||
if let group = peer as? TelegramGroup {
|
if let group = peer as? TelegramGroup {
|
||||||
return account.network.request(Api.functions.messages.deleteChatUser(chatId: group.id.id, userId: inputUser))
|
return account.network.request(Api.functions.messages.deleteChatUser(flags: 0, chatId: group.id.id, userId: inputUser))
|
||||||
|> mapError { error -> Void in
|
|> mapError { error -> Void in
|
||||||
return Void()
|
return Void()
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,7 @@ public func reportPeer(account: Account, peerId: PeerId) -> Signal<Void, NoError
|
|||||||
|
|
||||||
public enum ReportReason: Equatable {
|
public enum ReportReason: Equatable {
|
||||||
case spam
|
case spam
|
||||||
|
case fake
|
||||||
case violence
|
case violence
|
||||||
case porno
|
case porno
|
||||||
case childAbuse
|
case childAbuse
|
||||||
@ -91,6 +92,8 @@ private extension ReportReason {
|
|||||||
switch self {
|
switch self {
|
||||||
case .spam:
|
case .spam:
|
||||||
return .inputReportReasonSpam
|
return .inputReportReasonSpam
|
||||||
|
case .fake:
|
||||||
|
return .inputReportReasonFake
|
||||||
case .violence:
|
case .violence:
|
||||||
return .inputReportReasonViolence
|
return .inputReportReasonViolence
|
||||||
case .porno:
|
case .porno:
|
||||||
|
@ -53,6 +53,9 @@ extension TelegramUser {
|
|||||||
if (flags & (1 << 24)) != 0 {
|
if (flags & (1 << 24)) != 0 {
|
||||||
userFlags.insert(.isScam)
|
userFlags.insert(.isScam)
|
||||||
}
|
}
|
||||||
|
if (flags & (1 << 26)) != 0 {
|
||||||
|
userFlags.insert(.isFake)
|
||||||
|
}
|
||||||
|
|
||||||
var botInfo: BotUserInfo?
|
var botInfo: BotUserInfo?
|
||||||
if (flags & (1 << 14)) != 0 {
|
if (flags & (1 << 14)) != 0 {
|
||||||
@ -96,6 +99,9 @@ extension TelegramUser {
|
|||||||
if (flags & (1 << 24)) != 0 {
|
if (flags & (1 << 24)) != 0 {
|
||||||
userFlags.insert(.isScam)
|
userFlags.insert(.isScam)
|
||||||
}
|
}
|
||||||
|
if (flags & Int32(1 << 26)) != 0 {
|
||||||
|
userFlags.insert(.isFake)
|
||||||
|
}
|
||||||
|
|
||||||
var botInfo: BotUserInfo?
|
var botInfo: BotUserInfo?
|
||||||
if (flags & (1 << 14)) != 0 {
|
if (flags & (1 << 14)) != 0 {
|
||||||
@ -156,6 +162,9 @@ extension TelegramUser {
|
|||||||
if rhs.flags.contains(.isScam) {
|
if rhs.flags.contains(.isScam) {
|
||||||
userFlags.insert(.isScam)
|
userFlags.insert(.isScam)
|
||||||
}
|
}
|
||||||
|
if rhs.flags.contains(.isFake) {
|
||||||
|
userFlags.insert(.isFake)
|
||||||
|
}
|
||||||
|
|
||||||
let botInfo: BotUserInfo? = rhs.botInfo
|
let botInfo: BotUserInfo? = rhs.botInfo
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -77,6 +77,9 @@ public enum PresentationResourceKey: Int32 {
|
|||||||
case chatListScamRegularIcon
|
case chatListScamRegularIcon
|
||||||
case chatListScamOutgoingIcon
|
case chatListScamOutgoingIcon
|
||||||
case chatListScamServiceIcon
|
case chatListScamServiceIcon
|
||||||
|
case chatListFakeRegularIcon
|
||||||
|
case chatListFakeOutgoingIcon
|
||||||
|
case chatListFakeServiceIcon
|
||||||
case chatListSecretIcon
|
case chatListSecretIcon
|
||||||
case chatListRecentStatusOnlineIcon
|
case chatListRecentStatusOnlineIcon
|
||||||
case chatListRecentStatusOnlineHighlightedIcon
|
case chatListRecentStatusOnlineHighlightedIcon
|
||||||
|
@ -248,6 +248,42 @@ public struct PresentationResourcesChatList {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func fakeIcon(_ theme: PresentationTheme, type: ScamIconType) -> UIImage? {
|
||||||
|
let key: PresentationResourceKey
|
||||||
|
let color: UIColor
|
||||||
|
switch type {
|
||||||
|
case .regular:
|
||||||
|
key = PresentationResourceKey.chatListFakeRegularIcon
|
||||||
|
color = theme.chat.message.incoming.scamColor
|
||||||
|
case .outgoing:
|
||||||
|
key = PresentationResourceKey.chatListFakeOutgoingIcon
|
||||||
|
color = theme.chat.message.outgoing.scamColor
|
||||||
|
case .service:
|
||||||
|
key = PresentationResourceKey.chatListFakeServiceIcon
|
||||||
|
color = theme.chat.serviceMessage.components.withDefaultWallpaper.scam
|
||||||
|
}
|
||||||
|
return theme.image(key.rawValue, { theme in
|
||||||
|
return generateImage(CGSize(width: 37.0, height: 16.0), contextGenerator: { size, context in
|
||||||
|
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||||
|
context.clear(bounds)
|
||||||
|
|
||||||
|
context.setFillColor(color.cgColor)
|
||||||
|
context.setStrokeColor(color.cgColor)
|
||||||
|
context.setLineWidth(1.0)
|
||||||
|
|
||||||
|
context.addPath(UIBezierPath(roundedRect: bounds.insetBy(dx: 0.5, dy: 0.5), cornerRadius: 2.0).cgPath)
|
||||||
|
context.strokePath()
|
||||||
|
|
||||||
|
let titlePath = CGMutablePath()
|
||||||
|
titlePath.addRect(bounds.offsetBy(dx: 0.0, dy: -2.0 + UIScreenPixel))
|
||||||
|
let titleString = NSAttributedString(string: "FAKE", font: Font.bold(10.0), textColor: color, paragraphAlignment: .center)
|
||||||
|
let titleFramesetter = CTFramesetterCreateWithAttributedString(titleString as CFAttributedString)
|
||||||
|
let titleFrame = CTFramesetterCreateFrame(titleFramesetter, CFRangeMake(0, titleString.length), titlePath, nil)
|
||||||
|
CTFrameDraw(titleFrame, context)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
public static func secretIcon(_ theme: PresentationTheme) -> UIImage? {
|
public static func secretIcon(_ theme: PresentationTheme) -> UIImage? {
|
||||||
return theme.image(PresentationResourceKey.chatListSecretIcon.rawValue, { theme in
|
return theme.image(PresentationResourceKey.chatListSecretIcon.rawValue, { theme in
|
||||||
return generateImage(CGSize(width: 9.0, height: 12.0), rotatedContext: { size, context in
|
return generateImage(CGSize(width: 9.0, height: 12.0), rotatedContext: { size, context in
|
||||||
|
Binary file not shown.
@ -1430,9 +1430,13 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
|
|
||||||
var isScam = effectiveAuthor.isScam
|
var isScam = effectiveAuthor.isScam
|
||||||
if case let .peer(peerId) = item.chatLocation, let authorPeerId = item.message.author?.id, authorPeerId == peerId {
|
if case let .peer(peerId) = item.chatLocation, let authorPeerId = item.message.author?.id, authorPeerId == peerId {
|
||||||
isScam = false
|
|
||||||
|
} else if effectiveAuthor.isScam {
|
||||||
|
currentCredibilityIconImage = PresentationResourcesChatList.scamIcon(item.presentationData.theme.theme, type: incoming ? .regular : .outgoing)
|
||||||
|
} else if effectiveAuthor.isFake {
|
||||||
|
currentCredibilityIconImage = PresentationResourcesChatList.scamIcon(item.presentationData.theme.theme, type: incoming ? .regular : .outgoing)
|
||||||
}
|
}
|
||||||
currentCredibilityIconImage = isScam ? PresentationResourcesChatList.scamIcon(item.presentationData.theme.theme, type: incoming ? .regular : .outgoing) : nil
|
|
||||||
}
|
}
|
||||||
if let rawAuthorNameColor = authorNameColor {
|
if let rawAuthorNameColor = authorNameColor {
|
||||||
var dimColors = false
|
var dimColors = false
|
||||||
|
@ -193,7 +193,14 @@ class ChatMessageForwardInfoNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if peer.isScam {
|
if peer.isFake {
|
||||||
|
switch type {
|
||||||
|
case let .bubble(incoming):
|
||||||
|
currentCredibilityIconImage = PresentationResourcesChatList.fakeIcon(presentationData.theme.theme, type: incoming ? .regular : .outgoing)
|
||||||
|
case .standalone:
|
||||||
|
currentCredibilityIconImage = PresentationResourcesChatList.fakeIcon(presentationData.theme.theme, type: .service)
|
||||||
|
}
|
||||||
|
} else if peer.isScam {
|
||||||
switch type {
|
switch type {
|
||||||
case let .bubble(incoming):
|
case let .bubble(incoming):
|
||||||
currentCredibilityIconImage = PresentationResourcesChatList.scamIcon(presentationData.theme.theme, type: incoming ? .regular : .outgoing)
|
currentCredibilityIconImage = PresentationResourcesChatList.scamIcon(presentationData.theme.theme, type: incoming ? .regular : .outgoing)
|
||||||
|
@ -937,7 +937,11 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
if let cachedData = data.cachedData as? CachedUserData {
|
if let cachedData = data.cachedData as? CachedUserData {
|
||||||
if user.isScam {
|
if user.isFake {
|
||||||
|
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: user.botInfo == nil ? presentationData.strings.Profile_About : presentationData.strings.Profile_BotInfo, text: user.botInfo != nil ? presentationData.strings.UserInfo_FakeBotWarning : presentationData.strings.UserInfo_FakeUserWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: user.botInfo != nil ? enabledPrivateBioEntities : []), action: nil, requestLayout: {
|
||||||
|
interaction.requestLayout()
|
||||||
|
}))
|
||||||
|
} else if user.isScam {
|
||||||
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: user.botInfo == nil ? presentationData.strings.Profile_About : presentationData.strings.Profile_BotInfo, text: user.botInfo != nil ? presentationData.strings.UserInfo_ScamBotWarning : presentationData.strings.UserInfo_ScamUserWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: user.botInfo != nil ? enabledPrivateBioEntities : []), action: nil, requestLayout: {
|
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: user.botInfo == nil ? presentationData.strings.Profile_About : presentationData.strings.Profile_BotInfo, text: user.botInfo != nil ? presentationData.strings.UserInfo_ScamBotWarning : presentationData.strings.UserInfo_ScamUserWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: user.botInfo != nil ? enabledPrivateBioEntities : []), action: nil, requestLayout: {
|
||||||
interaction.requestLayout()
|
interaction.requestLayout()
|
||||||
}))
|
}))
|
||||||
@ -1025,12 +1029,27 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
if let cachedData = data.cachedData as? CachedChannelData {
|
if let cachedData = data.cachedData as? CachedChannelData {
|
||||||
if channel.isScam {
|
let aboutText: String?
|
||||||
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemAbout, label: presentationData.strings.Channel_AboutItem, text: presentationData.strings.GroupInfo_ScamGroupWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledPublicBioEntities), action: nil, requestLayout: {
|
if channel.isFake {
|
||||||
interaction.requestLayout()
|
if case .broadcast = channel.info {
|
||||||
}))
|
aboutText = presentationData.strings.ChannelInfo_FakeChannelWarning
|
||||||
|
} else {
|
||||||
|
aboutText = presentationData.strings.GroupInfo_FakeGroupWarning
|
||||||
|
}
|
||||||
|
} else if channel.isScam {
|
||||||
|
if case .broadcast = channel.info {
|
||||||
|
aboutText = presentationData.strings.ChannelInfo_ScamChannelWarning
|
||||||
|
} else {
|
||||||
|
aboutText = presentationData.strings.GroupInfo_ScamGroupWarning
|
||||||
|
}
|
||||||
} else if let about = cachedData.about, !about.isEmpty {
|
} else if let about = cachedData.about, !about.isEmpty {
|
||||||
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemAbout, label: presentationData.strings.Channel_AboutItem, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledPublicBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction, requestLayout: {
|
aboutText = about
|
||||||
|
} else {
|
||||||
|
aboutText = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if let aboutText = aboutText {
|
||||||
|
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemAbout, label: presentationData.strings.Channel_AboutItem, text: aboutText, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledPublicBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction, requestLayout: {
|
||||||
interaction.requestLayout()
|
interaction.requestLayout()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -1061,12 +1080,19 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
}
|
}
|
||||||
} else if let group = data.peer as? TelegramGroup {
|
} else if let group = data.peer as? TelegramGroup {
|
||||||
if let cachedData = data.cachedData as? CachedGroupData {
|
if let cachedData = data.cachedData as? CachedGroupData {
|
||||||
if group.isScam {
|
let aboutText: String?
|
||||||
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.PeerInfo_GroupAboutItem, text: presentationData.strings.GroupInfo_ScamGroupWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledPublicBioEntities), action: nil, requestLayout: {
|
if group.isFake {
|
||||||
interaction.requestLayout()
|
aboutText = presentationData.strings.GroupInfo_FakeGroupWarning
|
||||||
}))
|
} else if group.isScam {
|
||||||
|
aboutText = presentationData.strings.GroupInfo_ScamGroupWarning
|
||||||
} else if let about = cachedData.about, !about.isEmpty {
|
} else if let about = cachedData.about, !about.isEmpty {
|
||||||
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.PeerInfo_GroupAboutItem, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledPublicBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction, requestLayout: {
|
aboutText = about
|
||||||
|
} else {
|
||||||
|
aboutText = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if let aboutText = aboutText {
|
||||||
|
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.PeerInfo_GroupAboutItem, text: aboutText, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledPublicBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction, requestLayout: {
|
||||||
interaction.requestLayout()
|
interaction.requestLayout()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -1266,6 +1292,9 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
|||||||
interaction.editingOpenPublicLinkSetup()
|
interaction.editingOpenPublicLinkSetup()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if channel.hasPermission(.inviteMembers) {
|
||||||
let invitesText: String
|
let invitesText: String
|
||||||
if let count = data.invitations?.count, count > 0 {
|
if let count = data.invitations?.count, count > 0 {
|
||||||
invitesText = "\(count)"
|
invitesText = "\(count)"
|
||||||
@ -1276,7 +1305,9 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
|||||||
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 let linkedDiscussionPeer = data.linkedDiscussionPeer {
|
if let linkedDiscussionPeer = data.linkedDiscussionPeer {
|
||||||
let peerTitle: String
|
let peerTitle: String
|
||||||
if let addressName = linkedDiscussionPeer.addressName, !addressName.isEmpty {
|
if let addressName = linkedDiscussionPeer.addressName, !addressName.isEmpty {
|
||||||
@ -4426,7 +4457,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
|||||||
if canCreateInviteLink {
|
if canCreateInviteLink {
|
||||||
options.append(ContactListAdditionalOption(title: presentationData.strings.GroupInfo_InviteByLink, icon: .generic(UIImage(bundleImageName: "Contact List/LinkActionIcon")!), action: {
|
options.append(ContactListAdditionalOption(title: presentationData.strings.GroupInfo_InviteByLink, icon: .generic(UIImage(bundleImageName: "Contact List/LinkActionIcon")!), action: {
|
||||||
createInviteLinkImpl?()
|
createInviteLinkImpl?()
|
||||||
}))
|
}, clearHighlightAutomatically: true))
|
||||||
}
|
}
|
||||||
|
|
||||||
let contactsController: ViewController
|
let contactsController: ViewController
|
||||||
|
Loading…
x
Reference in New Issue
Block a user