mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +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.PermanentLink" = "Permanent Link";
|
||||
"InviteLink.PublicLink" = "Public Link";
|
||||
"InviteLink.Share" = "Share Link";
|
||||
"InviteLink.PeopleJoinedNone" = "no one joined yet";
|
||||
"InviteLink.PeopleJoined_1" = "%@ people joined";
|
||||
@ -5895,6 +5896,8 @@ Sorry for the inconvenience.";
|
||||
|
||||
"InviteLink.ExpiresIn" = "expires in %@";
|
||||
|
||||
"InviteLink.InviteLinkCopiedText" = "Invite link copied to clipboard";
|
||||
|
||||
"Conversation.ChecksTooltip.Delivered" = "Delivered";
|
||||
"Conversation.ChecksTooltip.Read" = "Read";
|
||||
|
||||
@ -5902,5 +5905,12 @@ Sorry for the inconvenience.";
|
||||
|
||||
"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";
|
||||
"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 icon: ContactListActionItemIcon
|
||||
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.icon = icon
|
||||
self.action = action
|
||||
self.clearHighlightAutomatically = clearHighlightAutomatically
|
||||
}
|
||||
|
||||
public static func ==(lhs: ContactListAdditionalOption, rhs: ContactListAdditionalOption) -> Bool {
|
||||
|
@ -1258,6 +1258,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
if peer.isScam {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.scamIcon(item.presentationData.theme, type: .regular)
|
||||
credibilityIconOffset = 2.0
|
||||
} else if peer.isFake {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.fakeIcon(item.presentationData.theme, type: .regular)
|
||||
credibilityIconOffset = 2.0
|
||||
} else if peer.isVerified {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
||||
credibilityIconOffset = 3.0
|
||||
@ -1270,6 +1273,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
if peer.isScam {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.scamIcon(item.presentationData.theme, type: .regular)
|
||||
credibilityIconOffset = 2.0
|
||||
} else if peer.isFake {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.fakeIcon(item.presentationData.theme, type: .regular)
|
||||
credibilityIconOffset = 2.0
|
||||
} else if peer.isVerified {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
||||
credibilityIconOffset = 3.0
|
||||
|
@ -175,7 +175,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
interaction.authorize()
|
||||
})
|
||||
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):
|
||||
var status: ContactsPeerItemStatus
|
||||
let itemPeer: ContactsPeerItemPeer
|
||||
|
@ -56,7 +56,7 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
|
||||
|
||||
case usageHeader(PresentationTheme, String)
|
||||
case usagePicker(PresentationTheme, InviteLinkUsageLimit)
|
||||
case usageCustomPicker(PresentationTheme, Int32?, Bool)
|
||||
case usageCustomPicker(PresentationTheme, Int32?, Bool, Bool)
|
||||
case usageInfo(PresentationTheme, String)
|
||||
|
||||
case revoke(PresentationTheme, String)
|
||||
@ -141,8 +141,8 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .usageCustomPicker(lhsTheme, lhsValue, lhsFocused):
|
||||
if case let .usageCustomPicker(rhsTheme, rhsValue, rhsFocused) = rhs, lhsTheme === rhsTheme, lhsValue == rhsValue, lhsFocused == rhsFocused {
|
||||
case let .usageCustomPicker(lhsTheme, lhsValue, lhsFocused, lhsCustomValue):
|
||||
if case let .usageCustomPicker(rhsTheme, rhsValue, rhsFocused, rhsCustomValue) = rhs, lhsTheme === rhsTheme, lhsValue == rhsValue, lhsFocused == rhsFocused, lhsCustomValue == rhsCustomValue {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -221,9 +221,14 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
|
||||
return updatedState
|
||||
})
|
||||
})
|
||||
case let .usageCustomPicker(theme, value, focused):
|
||||
let text = value.flatMap { String($0) } ?? (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, tag: nil, sectionId: self.section, textUpdated: { updatedText in
|
||||
case let .usageCustomPicker(theme, value, focused, customValue):
|
||||
let text: String
|
||||
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 {
|
||||
return
|
||||
}
|
||||
@ -284,7 +289,12 @@ private func inviteLinkEditControllerEntries(invite: ExportedInvitation?, state:
|
||||
|
||||
entries.append(.usageHeader(presentationData.theme, presentationData.strings.InviteLink_Create_UsersLimit.uppercased()))
|
||||
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))
|
||||
|
||||
@ -401,7 +411,7 @@ public func inviteLinkEditController(context: AccountContext, peerId: PeerId, in
|
||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||
expireDate = currentTime + value
|
||||
} else {
|
||||
expireDate = nil
|
||||
expireDate = 0
|
||||
}
|
||||
|
||||
let usageLimit = state.usage.value
|
||||
|
@ -20,6 +20,7 @@ import ShareController
|
||||
import OverlayStatusController
|
||||
import PresentationDataUtils
|
||||
import DirectionalPanGesture
|
||||
import UndoUI
|
||||
|
||||
class InviteLinkInviteInteraction {
|
||||
let context: AccountContext
|
||||
@ -139,7 +140,7 @@ private enum InviteLinkInviteEntry: Comparable, Identifiable {
|
||||
case let .header(theme, title, text):
|
||||
return InviteLinkInviteHeaderItem(theme: theme, title: title, text: text)
|
||||
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)
|
||||
}, shareAction: {
|
||||
interaction.shareLink(invite)
|
||||
@ -345,8 +346,9 @@ public final class InviteLinkInviteController: ViewController {
|
||||
|
||||
if let invite = invite {
|
||||
UIPasteboard.general.string = invite.link
|
||||
|
||||
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)
|
||||
}, copyLink: { [weak self] invite in
|
||||
UIPasteboard.general.string = invite.link
|
||||
|
||||
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
|
||||
let shareController = ShareController(context: context, subject: .url(invite.link))
|
||||
self?.controller?.present(shareController, in: .window(.root))
|
||||
@ -625,6 +628,10 @@ public final class InviteLinkInviteController: ViewController {
|
||||
}
|
||||
|
||||
private var panGestureArguments: CGFloat?
|
||||
|
||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
return gestureRecognizer is DirectionalPanGestureRecognizer && otherGestureRecognizer is UIPanGestureRecognizer
|
||||
}
|
||||
|
||||
@objc func panGesture(_ recognizer: UIPanGestureRecognizer) {
|
||||
let contentOffset = self.listNode.visibleContentOffset()
|
||||
@ -633,10 +640,20 @@ public final class InviteLinkInviteController: ViewController {
|
||||
self.panGestureArguments = 0.0
|
||||
case .changed:
|
||||
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 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 {
|
||||
self.listNode.scroller.panGestureRecognizer.setTranslation(CGPoint(), in: self.listNode.scroller)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
translation = currentPanOffset
|
||||
translation = 0.0
|
||||
recognizer.setTranslation(CGPoint(), in: self.contentNode.view)
|
||||
}
|
||||
|
||||
self.panGestureArguments = translation
|
||||
|
@ -19,6 +19,7 @@ import ContextUI
|
||||
import TelegramStringFormatting
|
||||
import ItemListPeerActionItem
|
||||
import ShareController
|
||||
import UndoUI
|
||||
|
||||
private final class InviteLinkListControllerArguments {
|
||||
let context: AccountContext
|
||||
@ -55,7 +56,7 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
|
||||
case header(PresentationTheme, String)
|
||||
|
||||
case mainLinkHeader(PresentationTheme, String)
|
||||
case mainLink(PresentationTheme, ExportedInvitation?, [Peer])
|
||||
case mainLink(PresentationTheme, ExportedInvitation?, [Peer], Int32, Bool)
|
||||
|
||||
case linksHeader(PresentationTheme, String)
|
||||
case linksCreate(PresentationTheme, String)
|
||||
@ -117,8 +118,8 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .mainLink(lhsTheme, lhsInvite, lhsPeers):
|
||||
if case let .mainLink(rhsTheme, rhsInvite, rhsPeers) = rhs, lhsTheme === rhsTheme, lhsInvite == rhsInvite, arePeerArraysEqual(lhsPeers, rhsPeers) {
|
||||
case let .mainLink(lhsTheme, lhsInvite, lhsPeers, lhsImportersCount, lhsIsPublic):
|
||||
if case let .mainLink(rhsTheme, rhsInvite, rhsPeers, rhsImportersCount, rhsIsPublic) = rhs, lhsTheme === rhsTheme, lhsInvite == rhsInvite, arePeerArraysEqual(lhsPeers, rhsPeers), lhsImportersCount == rhsImportersCount, lhsIsPublic == rhsIsPublic {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -179,8 +180,8 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
|
||||
return InviteLinkHeaderItem(theme: theme, text: text, sectionId: self.section)
|
||||
case let .mainLinkHeader(_, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .mainLink(_, invite, peers):
|
||||
return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: invite, peers: peers, displayButton: true, displayImporters: true, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: {
|
||||
case let .mainLink(_, invite, peers, importersCount, isPublic):
|
||||
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 {
|
||||
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] = []
|
||||
|
||||
entries.append(.header(presentationData.theme, presentationData.strings.InviteLink_CreatePrivateLinkHelp))
|
||||
entries.append(.mainLinkHeader(presentationData.theme, presentationData.strings.InviteLink_PermanentLink.uppercased()))
|
||||
|
||||
|
||||
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
|
||||
} else if let invite = (view.cachedData as? CachedChannelData)?.exportedInvitation {
|
||||
mainInvite = invite
|
||||
@ -241,7 +246,19 @@ private func inviteLinkListControllerEntries(presentationData: PresentationData,
|
||||
} else {
|
||||
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(.linksCreate(presentationData.theme, presentationData.strings.InviteLink_Create))
|
||||
@ -320,10 +337,11 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
||||
pushControllerImpl?(controller)
|
||||
}, copyLink: { invite in
|
||||
UIPasteboard.general.string = invite.link
|
||||
|
||||
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
|
||||
guard let node = node as? ContextExtractedContentContainingNode, let controller = getControllerImpl?() else {
|
||||
guard let node = node as? ContextExtractedContentContainingNode, let controller = getControllerImpl?(), let invite = invite else {
|
||||
return
|
||||
}
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
@ -334,11 +352,10 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
if let invite = invite {
|
||||
UIPasteboard.general.string = invite.link
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.Username_LinkCopied, false)), nil)
|
||||
}
|
||||
UIPasteboard.general.string = invite.link
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
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
|
||||
@ -346,56 +363,56 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
if let invite = invite {
|
||||
let controller = InviteLinkQRCodeController(context: context, invite: invite)
|
||||
presentControllerImpl?(controller, nil)
|
||||
}
|
||||
let controller = InviteLinkQRCodeController(context: context, invite: invite)
|
||||
presentControllerImpl?(controller, nil)
|
||||
})))
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextRevoke, textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor)
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
let controller = ActionSheetController(presentationData: presentationData)
|
||||
let dismissAction: () -> Void = { [weak controller] in
|
||||
controller?.dismissAnimated()
|
||||
}
|
||||
controller.setItemGroups([
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetTextItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeAlert_Text),
|
||||
ActionSheetButtonItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeLink, color: .destructive, action: {
|
||||
dismissAction()
|
||||
|
||||
var revoke = false
|
||||
updateState { state in
|
||||
if !state.revokingPrivateLink {
|
||||
revoke = true
|
||||
var updatedState = state
|
||||
updatedState.revokingPrivateLink = true
|
||||
return updatedState
|
||||
} else {
|
||||
return state
|
||||
}
|
||||
}
|
||||
if revoke {
|
||||
revokeLinkDisposable.set((revokePersistentPeerExportedInvitation(account: context.account, peerId: peerId) |> deliverOnMainQueue).start(completed: {
|
||||
updateState { state in
|
||||
if invite.adminId.toInt64() != 0 {
|
||||
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)
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
let controller = ActionSheetController(presentationData: presentationData)
|
||||
let dismissAction: () -> Void = { [weak controller] in
|
||||
controller?.dismissAnimated()
|
||||
}
|
||||
controller.setItemGroups([
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetTextItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeAlert_Text),
|
||||
ActionSheetButtonItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeLink, color: .destructive, action: {
|
||||
dismissAction()
|
||||
|
||||
var revoke = false
|
||||
updateState { state in
|
||||
if !state.revokingPrivateLink {
|
||||
revoke = true
|
||||
var updatedState = state
|
||||
updatedState.revokingPrivateLink = false
|
||||
updatedState.revokingPrivateLink = true
|
||||
return updatedState
|
||||
} else {
|
||||
return state
|
||||
}
|
||||
|
||||
invitesContext.reload()
|
||||
revokedInvitesContext.reload()
|
||||
}))
|
||||
}
|
||||
})
|
||||
]),
|
||||
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
|
||||
])
|
||||
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
})))
|
||||
}
|
||||
if revoke {
|
||||
revokeLinkDisposable.set((revokePersistentPeerExportedInvitation(account: context.account, peerId: peerId) |> deliverOnMainQueue).start(completed: {
|
||||
updateState { state in
|
||||
var updatedState = state
|
||||
updatedState.revokingPrivateLink = false
|
||||
return updatedState
|
||||
}
|
||||
|
||||
invitesContext.reload()
|
||||
revokedInvitesContext.reload()
|
||||
}))
|
||||
}
|
||||
})
|
||||
]),
|
||||
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
|
||||
])
|
||||
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)
|
||||
presentInGlobalOverlayImpl?(contextController)
|
||||
@ -426,11 +443,21 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
UIPasteboard.general.string = invite.link
|
||||
|
||||
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 {
|
||||
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
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, f in
|
||||
@ -546,29 +573,41 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
||||
|> deliverOnMainQueue
|
||||
|
||||
let importersState = Promise<PeerInvitationImportersState?>(nil)
|
||||
let importersContext: Signal<PeerInvitationImportersContext, NoError> = peerView
|
||||
|> mapToSignal { view -> Signal<ExportedInvitation, NoError> in
|
||||
let importersContext: Signal<PeerInvitationImportersContext?, NoError> = peerView
|
||||
|> mapToSignal { view -> Signal<ExportedInvitation?, NoError> in
|
||||
if let cachedData = view.cachedData as? CachedGroupData, let exportedInvitation = cachedData.exportedInvitation {
|
||||
return .single(exportedInvitation)
|
||||
} else if let cachedData = view.cachedData as? CachedChannelData, let exportedInvitation = cachedData.exportedInvitation {
|
||||
return .single(exportedInvitation)
|
||||
} else {
|
||||
return .complete()
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|> deliverOnMainQueue
|
||||
|> map { invite -> PeerInvitationImportersContext in
|
||||
return PeerInvitationImportersContext(account: context.account, peerId: peerId, invite: invite)
|
||||
|> map { invite -> PeerInvitationImportersContext? in
|
||||
return invite.flatMap { PeerInvitationImportersContext(account: context.account, peerId: peerId, invite: $0) }
|
||||
} |> afterNext { context in
|
||||
importersState.set(context.state |> map(Optional.init))
|
||||
if let context = context {
|
||||
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)
|
||||
|> deliverOnMainQueue
|
||||
|> 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 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))
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import ShareController
|
||||
import OverlayStatusController
|
||||
import PresentationDataUtils
|
||||
import DirectionalPanGesture
|
||||
import UndoUI
|
||||
|
||||
class InviteLinkViewInteraction {
|
||||
let context: AccountContext
|
||||
@ -171,7 +172,7 @@ private enum InviteLinkViewEntry: Comparable, Identifiable {
|
||||
case let .link(_, invite):
|
||||
let buttonColor = color(for: 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)
|
||||
}, shareAction: {
|
||||
interaction.shareLink(invite)
|
||||
@ -393,8 +394,9 @@ public final class InviteLinkViewController: ViewController {
|
||||
}
|
||||
}, copyLink: { [weak self] invite in
|
||||
UIPasteboard.general.string = invite.link
|
||||
|
||||
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
|
||||
let shareController = ShareController(context: context, subject: .url(invite.link))
|
||||
self?.controller?.present(shareController, in: .window(.root))
|
||||
@ -412,8 +414,9 @@ public final class InviteLinkViewController: ViewController {
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
UIPasteboard.general.string = invite.link
|
||||
|
||||
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 {
|
||||
@ -452,6 +455,8 @@ public final class InviteLinkViewController: ViewController {
|
||||
self?.controller?.present(controller, in: .window(.root))
|
||||
})))
|
||||
}
|
||||
|
||||
|
||||
|
||||
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)
|
||||
@ -717,12 +722,20 @@ public final class InviteLinkViewController: ViewController {
|
||||
self.panGestureArguments = 0.0
|
||||
case .changed:
|
||||
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 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 {
|
||||
self.listNode.scroller.panGestureRecognizer.setTranslation(CGPoint(), in: self.listNode.scroller)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
translation = currentPanOffset
|
||||
translation = 0.0
|
||||
recognizer.setTranslation(CGPoint(), in: self.contentNode.view)
|
||||
}
|
||||
|
||||
self.panGestureArguments = translation
|
||||
|
@ -96,7 +96,8 @@ private let shareIcon = generateImage(CGSize(width: 26.0, height: 26.0), context
|
||||
private class ItemNode: ASDisplayNode {
|
||||
private let selectionNode: HighlightTrackingButtonNode
|
||||
private let wrapperNode: ASDisplayNode
|
||||
private let backgroundNode: ASImageNode
|
||||
private let backgroundNode: ASDisplayNode
|
||||
private let backgroundGradientLayer: CAGradientLayer
|
||||
|
||||
private let iconNode: ASImageNode
|
||||
private var timerNode: TimerNode?
|
||||
@ -122,11 +123,19 @@ private class ItemNode: ASDisplayNode {
|
||||
self.selectionNode = HighlightTrackingButtonNode()
|
||||
self.wrapperNode = ASDisplayNode()
|
||||
|
||||
self.backgroundNode = ASImageNode()
|
||||
self.backgroundNode.displaysAsynchronously = false
|
||||
self.backgroundNode.displayWithoutProcessing = true
|
||||
self.backgroundNode = ASDisplayNode()
|
||||
self.backgroundNode.clipsToBounds = true
|
||||
self.backgroundNode.cornerRadius = 15.0
|
||||
if #available(iOS 13.0, *) {
|
||||
self.backgroundNode.layer.cornerCurve = .continuous
|
||||
}
|
||||
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.displaysAsynchronously = false
|
||||
self.iconNode.displayWithoutProcessing = true
|
||||
@ -256,10 +265,10 @@ private class ItemNode: ASDisplayNode {
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
self.backgroundNode.image = generateBackgroundImage(colors: colors)
|
||||
self.backgroundGradientLayer.colors = colors as? [Any]
|
||||
}
|
||||
} else {
|
||||
self.backgroundNode.image = generateBackgroundImage(colors: colors)
|
||||
self.backgroundGradientLayer.colors = colors as? [Any]
|
||||
}
|
||||
|
||||
let secondaryTextColor = color.colors.text
|
||||
@ -329,7 +338,7 @@ private class ItemNode: ASDisplayNode {
|
||||
self.timerNode = 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 {
|
||||
subtitleText = presentationData.strings.InviteLink_TapToCopy
|
||||
}
|
||||
@ -359,6 +368,7 @@ private class ItemNode: ASDisplayNode {
|
||||
transition.updateFrame(node: self.wrapperNode, frame: backgroundFrame)
|
||||
transition.updateFrame(node: self.backgroundNode, 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 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)
|
||||
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?
|
||||
|
||||
|
@ -32,7 +32,9 @@ enum InviteLinkUsageLimit: Equatable {
|
||||
}
|
||||
|
||||
init(value: Int32?) {
|
||||
if let value = value {
|
||||
if value == 0 {
|
||||
self = .unlimited
|
||||
} else if let value = value {
|
||||
if value == 1 {
|
||||
self = .low
|
||||
} else if value == 10 {
|
||||
@ -56,7 +58,7 @@ enum InviteLinkUsageLimit: Equatable {
|
||||
case .high:
|
||||
return 100
|
||||
case .unlimited:
|
||||
return nil
|
||||
return 0
|
||||
case let .custom(value):
|
||||
return value
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ public class ItemListPermanentInviteLinkItem: ListViewItem, ItemListItem {
|
||||
let context: AccountContext
|
||||
let presentationData: ItemListPresentationData
|
||||
let invite: ExportedInvitation?
|
||||
let count: Int32
|
||||
let peers: [Peer]
|
||||
let displayButton: Bool
|
||||
let displayImporters: Bool
|
||||
@ -45,6 +46,7 @@ public class ItemListPermanentInviteLinkItem: ListViewItem, ItemListItem {
|
||||
context: AccountContext,
|
||||
presentationData: ItemListPresentationData,
|
||||
invite: ExportedInvitation?,
|
||||
count: Int32,
|
||||
peers: [Peer],
|
||||
displayButton: Bool,
|
||||
displayImporters: Bool,
|
||||
@ -60,6 +62,7 @@ public class ItemListPermanentInviteLinkItem: ListViewItem, ItemListItem {
|
||||
self.context = context
|
||||
self.presentationData = presentationData
|
||||
self.invite = invite
|
||||
self.count = count
|
||||
self.peers = peers
|
||||
self.displayButton = displayButton
|
||||
self.displayImporters = displayImporters
|
||||
@ -290,18 +293,13 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
|
||||
|
||||
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 subtitleColor: UIColor
|
||||
if let count = item.invite?.count {
|
||||
if count > 0 {
|
||||
subtitle = item.presentationData.strings.InviteLink_PeopleJoined(count)
|
||||
subtitleColor = item.presentationData.theme.list.itemAccentColor
|
||||
} else {
|
||||
subtitle = item.presentationData.strings.InviteLink_PeopleJoinedNone
|
||||
subtitleColor = item.presentationData.theme.list.itemSecondaryTextColor
|
||||
}
|
||||
if item.count > 0 {
|
||||
subtitle = item.presentationData.strings.InviteLink_PeopleJoined(item.count)
|
||||
subtitleColor = item.presentationData.theme.list.itemAccentColor
|
||||
} else {
|
||||
subtitle = item.presentationData.strings.InviteLink_PeopleJoinedNone
|
||||
subtitleColor = item.presentationData.theme.list.itemSecondaryTextColor
|
||||
|
@ -376,6 +376,9 @@ public class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNo
|
||||
if peer.isScam {
|
||||
credibilityIconImage = PresentationResourcesChatList.scamIcon(item.presentationData.theme, type: .regular)
|
||||
credibilityIconOffset = 6.0
|
||||
} else if peer.isFake {
|
||||
credibilityIconImage = PresentationResourcesChatList.fakeIcon(item.presentationData.theme, type: .regular)
|
||||
credibilityIconOffset = 2.0
|
||||
} else if peer.isVerified {
|
||||
credibilityIconImage = PresentationResourcesItemList.verifiedPeerIcon(item.presentationData.theme)
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ public class ItemListSingleLineInputItem: ListViewItem, ItemListItem {
|
||||
let maxLength: Int
|
||||
let enabled: Bool
|
||||
let selectAllOnFocus: Bool
|
||||
let secondaryStyle: Bool
|
||||
public let sectionId: ItemListSectionId
|
||||
let action: () -> Void
|
||||
let textUpdated: (String) -> Void
|
||||
@ -56,7 +57,7 @@ public class ItemListSingleLineInputItem: ListViewItem, ItemListItem {
|
||||
let cleared: (() -> Void)?
|
||||
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.title = title
|
||||
self.text = text
|
||||
@ -69,6 +70,7 @@ public class ItemListSingleLineInputItem: ListViewItem, ItemListItem {
|
||||
self.maxLength = maxLength
|
||||
self.enabled = enabled
|
||||
self.selectAllOnFocus = selectAllOnFocus
|
||||
self.secondaryStyle = secondaryStyle
|
||||
self.tag = tag
|
||||
self.sectionId = sectionId
|
||||
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.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.tintColor = item.presentationData.theme.list.itemAccentColor
|
||||
self.textNode.textField.accessibilityHint = item.placeholder
|
||||
@ -218,6 +220,11 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
|
||||
fontUpdated = true
|
||||
}
|
||||
|
||||
var styleUpdated = false
|
||||
if currentItem?.secondaryStyle != item.secondaryStyle {
|
||||
styleUpdated = true
|
||||
}
|
||||
|
||||
let leftInset: CGFloat = 16.0 + params.leftInset
|
||||
var rightInset: CGFloat = 16.0 + params.rightInset
|
||||
|
||||
@ -252,13 +259,17 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
|
||||
strongSelf.bottomStripeNode.backgroundColor = item.presentationData.theme.list.itemBlocksSeparatorColor
|
||||
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.tintColor = item.presentationData.theme.list.itemAccentColor
|
||||
}
|
||||
|
||||
if fontUpdated {
|
||||
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()
|
||||
|
@ -293,7 +293,7 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
||||
case let .privateLinkHeader(_, title):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
|
||||
case let .privateLink(_, invite, displayImporters):
|
||||
return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: invite, 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 {
|
||||
arguments.copyLink(invite)
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ public enum PeerReportSubject {
|
||||
|
||||
public enum PeerReportOption {
|
||||
case spam
|
||||
case fake
|
||||
case violence
|
||||
case copyright
|
||||
case pornography
|
||||
@ -37,6 +38,8 @@ public func presentPeerReportOptions(context: AccountContext, parent: ViewContro
|
||||
switch option {
|
||||
case .spam:
|
||||
title = presentationData.strings.ReportPeer_ReasonSpam
|
||||
case .fake:
|
||||
title = presentationData.strings.ReportPeer_ReasonFake
|
||||
case .violence:
|
||||
title = presentationData.strings.ReportPeer_ReasonViolence
|
||||
case .pornography:
|
||||
@ -57,6 +60,8 @@ public func presentPeerReportOptions(context: AccountContext, parent: ViewContro
|
||||
switch option {
|
||||
case .spam:
|
||||
reportReason = .spam
|
||||
case .fake:
|
||||
reportReason = .fake
|
||||
case .violence:
|
||||
reportReason = .violence
|
||||
case .pornography:
|
||||
@ -112,6 +117,8 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe
|
||||
switch option {
|
||||
case .spam:
|
||||
title = presentationData.strings.ReportPeer_ReasonSpam
|
||||
case .fake:
|
||||
title = presentationData.strings.ReportPeer_ReasonFake
|
||||
case .violence:
|
||||
title = presentationData.strings.ReportPeer_ReasonViolence
|
||||
case .pornography:
|
||||
@ -128,6 +135,8 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe
|
||||
switch option {
|
||||
case .spam:
|
||||
reportReason = .spam
|
||||
case .fake:
|
||||
reportReason = .fake
|
||||
case .violence:
|
||||
reportReason = .violence
|
||||
case .pornography:
|
||||
|
@ -652,7 +652,15 @@ private func userInfoEntries(account: Account, presentationData: PresentationDat
|
||||
} else {
|
||||
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
|
||||
if let _ = user.botInfo {
|
||||
aboutValue = presentationData.strings.UserInfo_ScamBotWarning
|
||||
|
@ -143,6 +143,7 @@ public struct TelegramChannelFlags: OptionSet {
|
||||
public static let hasGeo = TelegramChannelFlags(rawValue: 1 << 3)
|
||||
public static let hasVoiceChat = TelegramChannelFlags(rawValue: 1 << 4)
|
||||
public static let hasActiveVoiceChat = TelegramChannelFlags(rawValue: 1 << 5)
|
||||
public static let isFake = TelegramChannelFlags(rawValue: 1 << 6)
|
||||
}
|
||||
|
||||
public final class TelegramChannel: Peer {
|
||||
|
@ -14,6 +14,7 @@ public struct UserInfoFlags: OptionSet {
|
||||
public static let isVerified = UserInfoFlags(rawValue: (1 << 0))
|
||||
public static let isSupport = UserInfoFlags(rawValue: (1 << 1))
|
||||
public static let isScam = UserInfoFlags(rawValue: (1 << 2))
|
||||
public static let isFake = UserInfoFlags(rawValue: (1 << 3))
|
||||
}
|
||||
|
||||
public struct BotUserInfoFlags: OptionSet {
|
||||
|
@ -11,8 +11,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) }
|
||||
dict[1210199983] = { return Api.InputGeoPoint.parse_inputGeoPoint($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[2055070967] = { return Api.ChatFull.parse_channelFull($0) }
|
||||
dict[-1159937629] = { return Api.PollResults.parse_pollResults($0) }
|
||||
dict[-925415106] = { return Api.ChatParticipant.parse_chatParticipant($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[-1376497949] = { return Api.ReportReason.parse_inputReportReasonChildAbuse($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[-524237339] = { return Api.PageTableRow.parse_pageTableRow($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[873977640] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentials($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[859091184] = { return Api.InputSecureFile.parse_inputSecureFileUploaded($0) }
|
||||
dict[1399317950] = { return Api.InputSecureFile.parse_inputSecureFile($0) }
|
||||
|
@ -2278,11 +2278,31 @@ public extension Api {
|
||||
|
||||
}
|
||||
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 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) {
|
||||
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):
|
||||
if boxed {
|
||||
buffer.appendInt32(2055070967)
|
||||
@ -2320,38 +2340,71 @@ public extension Api {
|
||||
serializeInt32(pts, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 21) != 0 {call!.serialize(buffer, true)}
|
||||
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)]) {
|
||||
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):
|
||||
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? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
@ -2458,59 +2511,6 @@ public extension Api {
|
||||
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 {
|
||||
@ -13931,6 +13931,7 @@ public extension Api {
|
||||
case inputReportReasonCopyright
|
||||
case inputReportReasonChildAbuse
|
||||
case inputReportReasonGeoIrrelevant
|
||||
case inputReportReasonFake
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
@ -13975,6 +13976,12 @@ public extension Api {
|
||||
buffer.appendInt32(-606798099)
|
||||
}
|
||||
|
||||
break
|
||||
case .inputReportReasonFake:
|
||||
if boxed {
|
||||
buffer.appendInt32(-170010905)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -13995,6 +14002,8 @@ public extension Api {
|
||||
return ("inputReportReasonChildAbuse", [])
|
||||
case .inputReportReasonGeoIrrelevant:
|
||||
return ("inputReportReasonGeoIrrelevant", [])
|
||||
case .inputReportReasonFake:
|
||||
return ("inputReportReasonFake", [])
|
||||
}
|
||||
}
|
||||
|
||||
@ -14027,6 +14036,9 @@ public extension Api {
|
||||
public static func parse_inputReportReasonGeoIrrelevant(_ reader: BufferReader) -> ReportReason? {
|
||||
return Api.ReportReason.inputReportReasonGeoIrrelevant
|
||||
}
|
||||
public static func parse_inputReportReasonFake(_ reader: BufferReader) -> ReportReason? {
|
||||
return Api.ReportReason.inputReportReasonFake
|
||||
}
|
||||
|
||||
}
|
||||
public enum InputEncryptedChat: TypeConstructorDescription {
|
||||
@ -19205,7 +19217,7 @@ public extension Api {
|
||||
case inputPaymentCredentialsSaved(id: String, tmpPassword: Buffer)
|
||||
case inputPaymentCredentials(flags: Int32, data: 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) {
|
||||
switch self {
|
||||
@ -19229,11 +19241,12 @@ public extension Api {
|
||||
}
|
||||
paymentData.serialize(buffer, true)
|
||||
break
|
||||
case .inputPaymentCredentialsGooglePay(let paymentToken):
|
||||
case .inputPaymentCredentialsAndroidPay(let paymentToken, let googleTransactionId):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1966921727)
|
||||
buffer.appendInt32(-905587442)
|
||||
}
|
||||
paymentToken.serialize(buffer, true)
|
||||
serializeString(googleTransactionId, buffer: buffer, boxed: false)
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -19246,8 +19259,8 @@ public extension Api {
|
||||
return ("inputPaymentCredentials", [("flags", flags), ("data", data)])
|
||||
case .inputPaymentCredentialsApplePay(let paymentData):
|
||||
return ("inputPaymentCredentialsApplePay", [("paymentData", paymentData)])
|
||||
case .inputPaymentCredentialsGooglePay(let paymentToken):
|
||||
return ("inputPaymentCredentialsGooglePay", [("paymentToken", paymentToken)])
|
||||
case .inputPaymentCredentialsAndroidPay(let paymentToken, let googleTransactionId):
|
||||
return ("inputPaymentCredentialsAndroidPay", [("paymentToken", paymentToken), ("googleTransactionId", googleTransactionId)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -19294,14 +19307,17 @@ public extension Api {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_inputPaymentCredentialsGooglePay(_ reader: BufferReader) -> InputPaymentCredentials? {
|
||||
public static func parse_inputPaymentCredentialsAndroidPay(_ reader: BufferReader) -> InputPaymentCredentials? {
|
||||
var _1: Api.DataJSON?
|
||||
if let signature = reader.readInt32() {
|
||||
_1 = Api.parse(reader, signature: signature) as? Api.DataJSON
|
||||
}
|
||||
var _2: String?
|
||||
_2 = parseString(reader)
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.InputPaymentCredentials.inputPaymentCredentialsGooglePay(paymentToken: _1!)
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.InputPaymentCredentials.inputPaymentCredentialsAndroidPay(paymentToken: _1!, googleTransactionId: _2!)
|
||||
}
|
||||
else {
|
||||
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>) {
|
||||
let buffer = Buffer()
|
||||
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>) {
|
||||
let buffer = Buffer()
|
||||
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>) {
|
||||
let buffer = Buffer()
|
||||
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>) {
|
||||
let buffer = Buffer()
|
||||
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>) {
|
||||
let buffer = Buffer()
|
||||
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>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(873008187)
|
||||
|
@ -103,7 +103,10 @@ func parseTelegramGroupOrChannel(chat: Api.Chat) -> Peer? {
|
||||
if (flags & Int32(1 << 24)) != 0 {
|
||||
channelFlags.insert(.hasActiveVoiceChat)
|
||||
}
|
||||
|
||||
if (flags & Int32(1 << 25)) != 0 {
|
||||
channelFlags.insert(.isFake)
|
||||
}
|
||||
|
||||
let restrictionInfo: PeerAccessRestrictionInfo?
|
||||
if let restrictionReason = restrictionReason {
|
||||
restrictionInfo = PeerAccessRestrictionInfo(apiReasons: restrictionReason)
|
||||
|
@ -26,7 +26,7 @@ public func leftGroup(account: Account, peerId: PeerId) -> Signal<Void, NoError>
|
||||
|> take(1)
|
||||
|> mapToSignal { peer -> Signal<Void, NoError> in
|
||||
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
|
||||
|> mapToSignal { updates -> Signal<Void, NoError> in
|
||||
account.stateManager.addUpdates(updates)
|
||||
|
@ -275,7 +275,7 @@ private func removeChat(transaction: Transaction, postbox: Postbox, network: Net
|
||||
return .complete()
|
||||
}
|
||||
} 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
|
||||
return result
|
||||
}
|
||||
|
@ -75,6 +75,21 @@ public extension Message {
|
||||
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? {
|
||||
for attribute in self.attributes {
|
||||
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 {
|
||||
switch self {
|
||||
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
|
||||
if let peer = transaction.getPeer(peerId), let memberPeer = transaction.getPeer(memberId), let inputUser = apiInputUser(memberPeer) {
|
||||
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
|
||||
return Void()
|
||||
}
|
||||
|
@ -78,6 +78,7 @@ public func reportPeer(account: Account, peerId: PeerId) -> Signal<Void, NoError
|
||||
|
||||
public enum ReportReason: Equatable {
|
||||
case spam
|
||||
case fake
|
||||
case violence
|
||||
case porno
|
||||
case childAbuse
|
||||
@ -91,6 +92,8 @@ private extension ReportReason {
|
||||
switch self {
|
||||
case .spam:
|
||||
return .inputReportReasonSpam
|
||||
case .fake:
|
||||
return .inputReportReasonFake
|
||||
case .violence:
|
||||
return .inputReportReasonViolence
|
||||
case .porno:
|
||||
|
@ -53,7 +53,10 @@ extension TelegramUser {
|
||||
if (flags & (1 << 24)) != 0 {
|
||||
userFlags.insert(.isScam)
|
||||
}
|
||||
|
||||
if (flags & (1 << 26)) != 0 {
|
||||
userFlags.insert(.isFake)
|
||||
}
|
||||
|
||||
var botInfo: BotUserInfo?
|
||||
if (flags & (1 << 14)) != 0 {
|
||||
var botFlags = BotUserInfoFlags()
|
||||
@ -96,6 +99,9 @@ extension TelegramUser {
|
||||
if (flags & (1 << 24)) != 0 {
|
||||
userFlags.insert(.isScam)
|
||||
}
|
||||
if (flags & Int32(1 << 26)) != 0 {
|
||||
userFlags.insert(.isFake)
|
||||
}
|
||||
|
||||
var botInfo: BotUserInfo?
|
||||
if (flags & (1 << 14)) != 0 {
|
||||
@ -156,7 +162,10 @@ extension TelegramUser {
|
||||
if rhs.flags.contains(.isScam) {
|
||||
userFlags.insert(.isScam)
|
||||
}
|
||||
|
||||
if rhs.flags.contains(.isFake) {
|
||||
userFlags.insert(.isFake)
|
||||
}
|
||||
|
||||
let botInfo: BotUserInfo? = rhs.botInfo
|
||||
|
||||
let restrictionInfo: PeerAccessRestrictionInfo? = rhs.restrictionInfo
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -77,6 +77,9 @@ public enum PresentationResourceKey: Int32 {
|
||||
case chatListScamRegularIcon
|
||||
case chatListScamOutgoingIcon
|
||||
case chatListScamServiceIcon
|
||||
case chatListFakeRegularIcon
|
||||
case chatListFakeOutgoingIcon
|
||||
case chatListFakeServiceIcon
|
||||
case chatListSecretIcon
|
||||
case chatListRecentStatusOnlineIcon
|
||||
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? {
|
||||
return theme.image(PresentationResourceKey.chatListSecretIcon.rawValue, { theme 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
|
||||
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 {
|
||||
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 {
|
||||
case let .bubble(incoming):
|
||||
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 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: {
|
||||
interaction.requestLayout()
|
||||
}))
|
||||
@ -1025,12 +1029,27 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
||||
}))
|
||||
}
|
||||
if let cachedData = data.cachedData as? CachedChannelData {
|
||||
if channel.isScam {
|
||||
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: {
|
||||
interaction.requestLayout()
|
||||
}))
|
||||
let aboutText: String?
|
||||
if channel.isFake {
|
||||
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 {
|
||||
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()
|
||||
}))
|
||||
}
|
||||
@ -1061,12 +1080,19 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
||||
}
|
||||
} else if let group = data.peer as? TelegramGroup {
|
||||
if let cachedData = data.cachedData as? CachedGroupData {
|
||||
if group.isScam {
|
||||
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: {
|
||||
interaction.requestLayout()
|
||||
}))
|
||||
let aboutText: String?
|
||||
if group.isFake {
|
||||
aboutText = presentationData.strings.GroupInfo_FakeGroupWarning
|
||||
} else if group.isScam {
|
||||
aboutText = presentationData.strings.GroupInfo_ScamGroupWarning
|
||||
} 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()
|
||||
}))
|
||||
}
|
||||
@ -1266,6 +1292,9 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
interaction.editingOpenPublicLinkSetup()
|
||||
}))
|
||||
|
||||
}
|
||||
|
||||
if channel.hasPermission(.inviteMembers) {
|
||||
let invitesText: String
|
||||
if let count = data.invitations?.count, count > 0 {
|
||||
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: {
|
||||
interaction.editingOpenInviteLinksSetup()
|
||||
}))
|
||||
|
||||
}
|
||||
|
||||
if cachedData.flags.contains(.canChangeUsername) {
|
||||
if let linkedDiscussionPeer = data.linkedDiscussionPeer {
|
||||
let peerTitle: String
|
||||
if let addressName = linkedDiscussionPeer.addressName, !addressName.isEmpty {
|
||||
@ -4426,7 +4457,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
if canCreateInviteLink {
|
||||
options.append(ContactListAdditionalOption(title: presentationData.strings.GroupInfo_InviteByLink, icon: .generic(UIImage(bundleImageName: "Contact List/LinkActionIcon")!), action: {
|
||||
createInviteLinkImpl?()
|
||||
}))
|
||||
}, clearHighlightAutomatically: true))
|
||||
}
|
||||
|
||||
let contactsController: ViewController
|
||||
|
Loading…
x
Reference in New Issue
Block a user